llvm/flang/lib/parser/parse-state.h
peter klausler 424ec7b35b [flang] Handle empty files gracefully.
Create interval.h.  Use std::size_t instead of bare size_t.  Redefine parser::Name to not be just a bare string.

Break out and rename CharBlock from token-sequence.h for use in the parse tree.

Incremental replacement of name strings with pointers to cooked characters.

Fix case sensitivity problem.

Use new CharBlock encoding to replace strings for real literal constants.

Normalized cooked character stream to lower case.

Simplify parsing now that cooked stream is lower case.  Replace Keyword in parse tree.

Add static_asserts to || and recovery parsers to enforce same result types.

Remove needless TODO comment inserted earlier.

Fix case conversion on prefixed character literals (f90_correct/dc04.f90).

Use CharBlock in user-state.h.

Complete transition from nextChar to nextCh (i.e., always use pointers).

Document extensions.  Begin work on compiler directive lines.

More documentation work.

Reformat prescan.cc.

More work on compiler directive scanning.

Original-commit: flang-compiler/f18@38d0404e16
Reviewed-on: https://github.com/flang-compiler/f18/pull/29
Tree-same-pre-rewrite: false
2018-03-23 13:32:55 -07:00

206 lines
6.3 KiB
C++

#ifndef FORTRAN_PARSER_PARSE_STATE_H_
#define FORTRAN_PARSER_PARSE_STATE_H_
// Defines the ParseState type used as the argument for every parser's
// Parse member or static function. Tracks source provenance, context,
// accumulated messages, and an arbitrary UserState instance for parsing
// attempts. Must be efficient to duplicate and assign for backtracking
// and recovery during parsing!
#include "characters.h"
#include "idioms.h"
#include "message.h"
#include "provenance.h"
#include <cstddef>
#include <cstring>
#include <list>
#include <memory>
#include <optional>
#include <utility>
namespace Fortran {
namespace parser {
class UserState;
class ParseState {
public:
// TODO: Add a constructor for parsing a normalized module file.
ParseState(const CookedSource &cooked)
: cooked_{cooked}, p_{&cooked[0]}, limit_{p_ + cooked.size()},
messages_{*cooked.allSources()} {}
ParseState(const ParseState &that)
: cooked_{that.cooked_}, p_{that.p_}, limit_{that.limit_},
column_{that.column_}, messages_{*that.cooked_.allSources()},
userState_{that.userState_}, inFixedForm_{that.inFixedForm_},
encoding_{that.encoding_}, strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_} {}
ParseState(ParseState &&that)
: cooked_{that.cooked_}, p_{that.p_}, limit_{that.limit_},
column_{that.column_}, messages_{std::move(that.messages_)},
context_{std::move(that.context_)}, userState_{that.userState_},
inFixedForm_{that.inFixedForm_}, encoding_{that.encoding_},
strictConformance_{that.strictConformance_},
warnOnNonstandardUsage_{that.warnOnNonstandardUsage_},
warnOnDeprecatedUsage_{that.warnOnDeprecatedUsage_},
anyErrorRecovery_{that.anyErrorRecovery_},
anyConformanceViolation_{that.anyConformanceViolation_} {}
ParseState &operator=(ParseState &&that) {
swap(that);
return *this;
}
void swap(ParseState &that) {
constexpr std::size_t bytes{sizeof *this};
char buffer[bytes];
std::memcpy(buffer, this, bytes);
std::memcpy(this, &that, bytes);
std::memcpy(&that, buffer, bytes);
}
const CookedSource &cooked() const { return cooked_; }
int column() const { return column_; }
Messages *messages() { return &messages_; }
bool anyErrorRecovery() const { return anyErrorRecovery_; }
void set_anyErrorRecovery() { anyErrorRecovery_ = true; }
bool anyConformanceViolation() const { return anyConformanceViolation_; }
void set_anyConformanceViolation() { anyConformanceViolation_ = true; }
UserState *userState() const { return userState_; }
void set_userState(UserState *u) { userState_ = u; }
MessageContext context() const { return context_; }
ParseState &set_context(MessageContext c) {
context_ = c;
return *this;
}
bool inFixedForm() const { return inFixedForm_; }
ParseState &set_inFixedForm(bool yes) {
inFixedForm_ = yes;
return *this;
}
bool strictConformance() const { return strictConformance_; }
ParseState &set_strictConformance(bool yes) {
strictConformance_ = yes;
return *this;
}
bool warnOnNonstandardUsage() const { return warnOnNonstandardUsage_; }
ParseState &set_warnOnNonstandardUsage(bool yes) {
warnOnNonstandardUsage_ = yes;
return *this;
}
bool warnOnDeprecatedUsage() const { return warnOnDeprecatedUsage_; }
ParseState &set_warnOnDeprecatedUsage(bool yes) {
warnOnDeprecatedUsage_ = yes;
return *this;
}
Encoding encoding() const { return encoding_; }
ParseState &set_encoding(Encoding encoding) {
encoding_ = encoding;
return *this;
}
const char *GetLocation() const { return p_; }
Provenance GetProvenance(const char *at) const {
return cooked_.GetProvenance(at).start();
}
Provenance GetProvenance() const { return GetProvenance(p_); }
MessageContext &PushContext(MessageFixedText text) {
context_ = std::make_shared<Message>(GetProvenance(), text, context_);
return context_;
}
void PopContext() {
if (context_) {
context_ = context_->context();
}
}
Message &PutMessage(MessageFixedText t) { return PutMessage(p_, t); }
Message &PutMessage(MessageFormattedText &&t) {
return PutMessage(p_, std::move(t));
}
Message &PutMessage(MessageExpectedText &&t) {
return PutMessage(p_, std::move(t));
}
Message &PutMessage(const char *at, MessageFixedText t) {
return PutMessage(GetProvenance(at), t);
}
Message &PutMessage(const char *at, MessageFormattedText &&t) {
return PutMessage(GetProvenance(at), std::move(t));
}
Message &PutMessage(const char *at, MessageExpectedText &&t) {
return PutMessage(GetProvenance(at), std::move(t));
}
Message &PutMessage(Provenance at, MessageFixedText t) {
return messages_.Put(Message{at, t, context_});
}
Message &PutMessage(Provenance at, MessageFormattedText &&t) {
return messages_.Put(Message{at, std::move(t), context_});
}
Message &PutMessage(Provenance at, MessageExpectedText &&t) {
return messages_.Put(Message{at, std::move(t), context_});
}
bool IsAtEnd() const { return p_ >= limit_; }
char UncheckedAdvance() {
++column_;
char ch{*p_++};
if (ch == '\n') {
column_ = 1;
}
return ch;
}
std::optional<char> GetNextChar() {
if (p_ >= limit_) {
return {};
}
return {UncheckedAdvance()};
}
std::optional<char> PeekAtNextChar() {
if (p_ >= limit_) {
return {};
}
return {*p_};
}
private:
// Text remaining to be parsed
const CookedSource &cooked_;
const char *p_{nullptr}, *limit_{nullptr};
int column_{1};
// Accumulated messages and current nested context.
Messages messages_;
MessageContext context_;
UserState *userState_{nullptr};
bool inFixedForm_{false};
Encoding encoding_{Encoding::UTF8};
bool strictConformance_{false};
bool warnOnNonstandardUsage_{false};
bool warnOnDeprecatedUsage_{false};
bool anyErrorRecovery_{false};
bool anyConformanceViolation_{false};
// NOTE: Any additions or modifications to these data members must also be
// reflected in the copy and move constructors defined at the top of this
// class definition!
};
} // namespace parser
} // namespace Fortran
#endif // FORTRAN_PARSER_PARSE_STATE_H_