From: peter klausler Date: Fri, 2 Feb 2018 23:52:43 +0000 (-0800) Subject: [flang] More preprocessing. X-Git-Tag: llvmorg-12-init~9537^2~2983 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=55fe4d2af5f93569f61630f09f1bf4265be110ce;p=platform%2Fupstream%2Fllvm.git [flang] More preprocessing. Original-commit: flang-compiler/f18@a553505c3c99ec8744d5e3435bb14f4feb2f19c9 --- diff --git a/flang/f2018-demo.cc b/flang/f2018-demo.cc index de5a8b2..23c3794 100644 --- a/flang/f2018-demo.cc +++ b/flang/f2018-demo.cc @@ -5,6 +5,7 @@ #include "cooked-chars.h" #include "grammar.h" #include "idioms.h" +#include "message.h" #include "parse-tree.h" #include "prescan.h" #include "source.h" @@ -95,8 +96,8 @@ int main(int argc, char *const argv[]) { } } - std::stringstream error; Fortran::SourceFile source; + std::stringstream error; if (!source.Open(path, &error)) { std::cerr << error.str() << '\n'; return 1; @@ -106,16 +107,17 @@ int main(int argc, char *const argv[]) { size_t sourceBytes{source.bytes()}; std::unique_ptr prescanned; if (prescan) { + Fortran::Messages messages; + Fortran::Prescanner prescanner{messages}; Fortran::CharBuffer - buffer{Fortran::Prescanner{&error}. + buffer{prescanner. set_fixedForm(fixedForm). set_enableBackslashEscapesInCharLiterals(backslashEscapes). set_fixedFormColumnLimit(columns). set_enableOldDebugLines(enableOldDebugLines). Prescan(source)}; - std::string err{error.str()}; - if (!err.empty()) { - std::cerr << err; + std::cerr << messages; + if (prescanner.anyFatalErrors()) { return 1; } sourceBytes = buffer.bytes(); diff --git a/flang/message.h b/flang/message.h index c98ea9b..cdf6b41 100644 --- a/flang/message.h +++ b/flang/message.h @@ -19,6 +19,10 @@ using MessageContext = std::shared_ptr; class Message { public: + Message() {} + Message(const Message &) = default; + Message(Message &&) = default; + Message(Position pos, const std::string &msg, MessageContext ctx = nullptr) : position_{pos}, message_{msg}, context_{ctx} {} Message(Position pos, std::string &&msg, MessageContext ctx = nullptr) @@ -29,9 +33,6 @@ class Message { : position_{pos}, message_{"expected '"s + ch + '\''}, context_{ctx} {} - Message() {} - Message(const Message &) = default; - Message(Message &&) = default; Message &operator=(const Message &that) = default; Message &operator=(Message &&that) = default; diff --git a/flang/preprocessor.cc b/flang/preprocessor.cc index abfdc74..9fe3fff 100644 --- a/flang/preprocessor.cc +++ b/flang/preprocessor.cc @@ -14,6 +14,16 @@ namespace Fortran { +bool CharPointerWithLength::IsBlank() const { + for (size_t j{0}; j < bytes_; ++j) { + char ch{data_[j]}; + if (ch != ' ' && ch != '\t') { + return false; + } + } + return true; +} + void TokenSequence::Append(const TokenSequence &that) { if (nextStart_ < char_.size()) { start_.push_back(nextStart_); @@ -26,7 +36,7 @@ void TokenSequence::Append(const TokenSequence &that) { nextStart_ = char_.size(); } -void TokenSequence::EmitWithCaseConversion(CharBuffer *out) { +void TokenSequence::EmitWithCaseConversion(CharBuffer *out) const { size_t tokens{start_.size()}; size_t chars{char_.size()}; size_t atToken{0}; @@ -43,6 +53,10 @@ void TokenSequence::EmitWithCaseConversion(CharBuffer *out) { } } +std::string TokenSequence::ToString() const { + return {&char_[0], char_.size()}; +} + Definition::Definition(const TokenSequence &repl, size_t firstToken, size_t tokens) : replacement_{Tokenize({}, repl, firstToken, tokens)} {} @@ -81,13 +95,13 @@ TokenSequence Definition::Tokenize(const std::vector &argNames, } TokenSequence result; for (size_t j{0}; j < tokens; ++j) { - size_t bytes{token.GetBytes(firstToken + j)}; + size_t bytes{token[firstToken + j].size()}; if (bytes == 0) { continue; } - const char *text{token.GetText(firstToken + j)}; + const char *text{token[firstToken + j].data()}; if (bytes > 0 && IsIdentifierFirstCharacter(*text)) { - auto it = args.find(token.GetString(firstToken + j)); + auto it = args.find(token[firstToken + j].ToString()); if (it != args.end()) { result.push_back(it->second); continue; @@ -98,20 +112,9 @@ TokenSequence Definition::Tokenize(const std::vector &argNames, return result; } -static bool IsBlank(const CharPointerWithLength &cpl) { - size_t bytes{cpl.size()}; - for (size_t j{0}; j < bytes; ++j) { - char ch{cpl[j]}; - if (ch != ' ' && ch != '\t') { - return false; - } - } - return true; -} - TokenSequence Definition::Apply(const std::vector &args) { TokenSequence result; - bool stringify{false}, pasting{false}; + bool pasting{false}; size_t tokens{replacement_.size()}; for (size_t j{0}; j < tokens; ++j) { const CharPointerWithLength &token{replacement_[j]}; @@ -122,27 +125,34 @@ TokenSequence Definition::Apply(const std::vector &args) { if (index >= args.size()) { continue; } + int lastNonBlank{static_cast(result.size()) - 1}; + for (; lastNonBlank >= 0; --lastNonBlank) { + if (!result[lastNonBlank].IsBlank()) { + break; + } + } size_t argTokens{args[index].size()}; - if (stringify) { + if (lastNonBlank >= 0 && result[lastNonBlank].ToString() == "#") { + while (result.size() > static_cast(lastNonBlank)) { + result.pop_back(); + } std::string strung{'"'}; for (size_t k{0}; k < argTokens; ++k) { - size_t argBytes{args[index].GetBytes(k)}; - const char *arg{args[index].GetText(k)}; + size_t argBytes{args[index][k].size()}; + const char *arg{args[index][k].data()}; for (size_t n{0}; n < argBytes; ++n) { char ch{arg[n]}; if (ch == '"' || ch == '\\') { - strung += '\\'; + strung += ch; } strung += ch; } } - strung += '"'; - result.pop_back(); // remove the '#' - result.push_back(strung); + result.push_back(strung + '"'); } else { for (size_t k{0}; k < argTokens; ++k) { const CharPointerWithLength &argToken{args[index][k]}; - if (pasting && IsBlank(argToken)) { + if (pasting && argToken.IsBlank()) { } else { result.push_back(argToken); pasting = false; @@ -152,19 +162,17 @@ TokenSequence Definition::Apply(const std::vector &args) { } else if (bytes == 2 && text[0] == '#' && text[1] == '#') { // Token pasting operator in body (not expanded argument); discard any // immediately preceding white space, then reopen the last token. - while (!result.empty() && IsBlank(result[result.size() - 1])) { + while (!result.empty() && result[result.size() - 1].IsBlank()) { result.pop_back(); } if (!result.empty()) { result.ReopenLastToken(); pasting = true; } - } else if (pasting && IsBlank(token)) { + } else if (pasting && token.IsBlank()) { // Delete whitespace immediately following ## in the body. } else { - stringify = bytes == 1 && *text == '#'; - result.push_back(text, bytes); - pasting = false; + result.push_back(token); } } return result; @@ -196,9 +204,9 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input, size_t tokens{input.size()}; size_t j; for (j = 0; j < tokens; ++j) { - size_t bytes{input.GetBytes(j)}; + size_t bytes{input[j].size()}; if (bytes > 0 && - IsIdentifierFirstCharacter(*input.GetText(j)) && + IsIdentifierFirstCharacter(input[j][0]) && IsNameDefined(input[j])) { break; } @@ -212,7 +220,7 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input, } for (; j < tokens; ++j) { const CharPointerWithLength &token{input[j]}; - if (IsBlank(token) || !IsIdentifierFirstCharacter(token[0])) { + if (token.IsBlank() || !IsIdentifierFirstCharacter(token[0])) { result->push_back(token); continue; } @@ -251,7 +259,7 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input, bool leftParen{false}; while (++k < tokens) { const CharPointerWithLength &lookAhead{input[k]}; - if (!IsBlank(lookAhead) && lookAhead[0] != '\n') { + if (!lookAhead.IsBlank() && lookAhead[0] != '\n') { leftParen = lookAhead[0] == '(' && lookAhead.size() == 1; break; } @@ -262,8 +270,8 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input, } std::vector argStart{++k}; for (int nesting{0}; k < tokens; ++k) { - if (input.GetBytes(k) == 1) { - char ch{*input.GetText(k)}; + if (input[k].size() == 1) { + char ch{input[k][0]}; if (ch == '(') { ++nesting; } else if (ch == ')') { @@ -288,7 +296,7 @@ bool Preprocessor::MacroReplacement(const TokenSequence &input, size_t count{(k + 1 == argStart.size() ? j : argStart[k+1] - 1) - at}; TokenSequence actual; for (; count-- > 0; ++at) { - actual.push_back(input.GetText(at), input.GetBytes(at)); + actual.push_back(input[at].data(), input[at].size()); } args.emplace_back(std::move(actual)); } @@ -307,7 +315,7 @@ TokenSequence Preprocessor::ReplaceMacros(const TokenSequence &tokens) { static size_t SkipBlanks(const TokenSequence &tokens, size_t at, size_t lastToken) { for (; at < lastToken; ++at) { - if (!IsBlank(tokens[at])) { + if (!tokens[at].IsBlank()) { break; } } @@ -335,7 +343,7 @@ static std::string ConvertToLowerCase(const std::string &str) { static std::string GetDirectiveName(const TokenSequence &line, size_t *rest) { size_t tokens{line.size()}; size_t j{SkipBlanks(line, 0, tokens)}; - if (j == tokens || line.GetString(j) != "#") { + if (j == tokens || line[j].ToString() != "#") { *rest = tokens; return {}; } @@ -345,70 +353,77 @@ static std::string GetDirectiveName(const TokenSequence &line, size_t *rest) { return {}; } *rest = SkipBlanks(line, j + 1, tokens); - return ConvertToLowerCase(line.GetString(j)); + return ConvertToLowerCase(line[j].ToString()); } -std::string Preprocessor::Directive(const TokenSequence &dir) { +bool Preprocessor::Directive(const TokenSequence &dir) { size_t tokens{dir.size()}; size_t j{SkipBlanks(dir, 0, tokens)}; if (j == tokens) { - return {}; + return true; } - if (dir.GetString(j) != "#") { - return "missing '#'"; + if (dir[j].ToString() != "#") { + Complain("missing '#'"); + return false; } j = SkipBlanks(dir, j + 1, tokens); if (j == tokens) { - return {}; + return true; } - if (isdigit(*dir.GetText(j)) || *dir.GetText(j) == '"') { - return {}; // TODO: treat as #line + if (isdigit(dir[j][0]) || dir[j][0] == '"') { + return true; // TODO: treat as #line } - std::string dirName{ConvertToLowerCase(dir.GetString(j))}; + std::string dirName{ConvertToLowerCase(dir[j].ToString())}; j = SkipBlanks(dir, j + 1, tokens); CharPointerWithLength nameToken; - if (j < tokens && IsIdentifierFirstCharacter(*dir.GetText(j))) { + if (j < tokens && IsIdentifierFirstCharacter(dir[j][0])) { nameToken = dir[j]; } if (dirName == "line") { // TODO - return {}; + return true; } if (dirName == "define") { if (nameToken.empty()) { - return "#define: missing or invalid name"; + Complain("#define: missing or invalid name"); + return false; } nameToken = SaveToken(nameToken); definitions_.erase(nameToken); - if (++j < tokens && dir.GetBytes(j) == 1 && *dir.GetText(j) == '(') { + if (++j < tokens && dir[j].size() == 1 && dir[j][0] == '(') { j = SkipBlanks(dir, j + 1, tokens); std::vector argName; - if (dir.GetString(j) != ")") { + if (dir[j].ToString() != ")") { while (true) { - std::string an{dir.GetString(j)}; + std::string an{dir[j].ToString()}; if (an.empty() || !IsIdentifierFirstCharacter(an[0])) { - return "#define: missing or invalid argument name"; + Complain("#define: missing or invalid argument name"); + return false; } argName.push_back(an); j = SkipBlanks(dir, j + 1, tokens); if (j == tokens) { - return "#define: malformed argument list"; + Complain("#define: malformed argument list"); + return false; } - std::string punc{dir.GetString(j)}; + std::string punc{dir[j].ToString()}; if (punc == ")") { break; } if (punc != ",") { - return "#define: malformed argument list"; + Complain("#define: malformed argument list"); + return false; } j = SkipBlanks(dir, j + 1, tokens); if (j == tokens) { - return "#define: malformed argument list"; + Complain("#define: malformed argument list"); + return false; } } if (std::set(argName.begin(), argName.end()).size() != argName.size()) { - return "#define: argument names are not distinct"; + Complain("#define: argument names are not distinct"); + return false; } } j = SkipBlanks(dir, j + 1, tokens); @@ -418,80 +433,91 @@ std::string Preprocessor::Directive(const TokenSequence &dir) { definitions_.emplace( std::make_pair(nameToken, Definition{dir, j, tokens - j})); } - return {}; + return true; } if (dirName == "undef") { if (nameToken.empty()) { - return "#undef: missing or invalid name"; + Complain("# missing or invalid name"); + return false; } j = SkipBlanks(dir, j + 1, tokens); if (j != tokens) { - return "#undef: excess tokens at end of directive"; + Complain("#undef: excess tokens at end of directive"); + return false; } definitions_.erase(nameToken); - return {}; + return true; } if (dirName == "ifdef" || dirName == "ifndef") { if (nameToken.empty()) { - return "#"s + dirName + ": missing name"; + Complain("#"s + dirName + ": missing name"); + return false; } j = SkipBlanks(dir, j + 1, tokens); if (j != tokens) { - return "#"s + dirName + ": excess tokens at end of directive"; + Complain("#"s + dirName + ": excess tokens at end of directive"); + return false; } if (IsNameDefined(nameToken) == (dirName == "ifdef")) { ifStack_.push(CanDeadElseAppear::Yes); - return {}; + return true; } return SkipDisabledConditionalCode(dirName, IsElseActive::Yes); } if (dirName == "if") { - std::string errors; - if (IsIfPredicateTrue(dir, j, tokens - j, &errors) || !errors.empty()) { + if (IsIfPredicateTrue(dir, j, tokens - j)) { ifStack_.push(CanDeadElseAppear::Yes); - } else { - errors = SkipDisabledConditionalCode(dirName, IsElseActive::Yes); + return true; } - return errors.empty() ? ""s : "#if: "s + errors; + return SkipDisabledConditionalCode(dirName, IsElseActive::Yes); } if (dirName == "else") { if (j != tokens) { - return "#else: excess tokens at end of directive"; + Complain("#else: excess tokens at end of directive"); + return false; } if (ifStack_.empty()) { - return "#else: not nested within #if, #ifdef, or #ifndef"; + Complain("#else: not nested within #if, #ifdef, or #ifndef"); + return false; } if (ifStack_.top() != CanDeadElseAppear::Yes) { - return "#else: already appeared within this #if, #ifdef, or #ifndef"; + Complain("#else: already appeared within this #if, #ifdef, or #ifndef"); + return false; } ifStack_.pop(); return SkipDisabledConditionalCode("else", IsElseActive::No); } if (dirName == "elif") { if (ifStack_.empty()) { - return "#elif: not nested within #if, #ifdef, or #ifndef"; + Complain("#elif: not nested within #if, #ifdef, or #ifndef"); + return false; } if (ifStack_.top() != CanDeadElseAppear::Yes) { - return "#elif: #else previously appeared within this " - "#if, #ifdef, or #ifndef"; + Complain("#elif: #else previously appeared within this " + "#if, #ifdef, or #ifndef"); + return false; } ifStack_.pop(); return SkipDisabledConditionalCode("elif", IsElseActive::No); } if (dirName == "endif") { if (j != tokens) { - return "#endif: excess tokens at end of directive"; + Complain("#endif: excess tokens at end of directive"); + return false; } if (ifStack_.empty()) { - return "#endif: no #if, #ifdef, or #ifndef"; + Complain("#endif: no #if, #ifdef, or #ifndef"); + return false; } ifStack_.pop(); - return {}; + return true; } if (dirName == "error" || dirName == "warning") { - return {dir.data(), dir.size()}; + Complain(dir.ToString()); + return dirName != "error"; } - return "#"s + dirName + ": unknown or unimplemented directive"; + Complain("#"s + dirName + ": unknown or unimplemented directive"); + return false; } CharPointerWithLength Preprocessor::SaveToken(const CharPointerWithLength &t) { @@ -503,7 +529,7 @@ bool Preprocessor::IsNameDefined(const CharPointerWithLength &token) { return definitions_.find(token) != definitions_.end(); } -std::string +bool Preprocessor::SkipDisabledConditionalCode(const std::string &dirName, IsElseActive isElseActive) { int nesting{0}; @@ -514,24 +540,23 @@ Preprocessor::SkipDisabledConditionalCode(const std::string &dirName, ++nesting; } else if (dn == "endif") { if (nesting-- == 0) { - return {}; - } - } else if (isElseActive == IsElseActive::Yes && nesting == 0) { - if (dn == "else") { - ifStack_.push(CanDeadElseAppear::No); - return {}; - } - if (dn == "elif") { - std::string errors; - if (IsIfPredicateTrue(*line, rest, line->size() - rest, &errors) || - !errors.empty()) { - ifStack_.push(CanDeadElseAppear::No); - return errors.empty() ? ""s : "#elif: "s + errors; - } + return true; } + } else if (isElseActive == IsElseActive::Yes && + nesting == 0 && + (dn == "else" || + (dn == "elif" && + IsIfPredicateTrue(*line, rest, line->size() - rest)))) { + ifStack_.push(CanDeadElseAppear::No); + return true; } } - return "#"s + dirName + ": missing #endif"; + Complain("#"s + dirName + ": missing #endif"); + return false; +} + +void Preprocessor::Complain(const std::string &message) { + prescanner_.messages().Add({prescanner_.position(), message}); } // Precedence level codes used here to accommodate mixed Fortran and C: @@ -611,7 +636,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, *errors = "incomplete expression"; return 0; } - std::string t{token.GetString(*atToken)}; + std::string t{token[*atToken].ToString()}; enum Operator op; // Parse and evaluate a primary or a unary operator and its operand. @@ -634,8 +659,8 @@ static std::int64_t ExpressionValue(const TokenSequence &token, } else if (t == "-") { op = UMINUS; } else if (t == "." && *atToken + 2 < tokens && - ConvertToLowerCase(token.GetString(*atToken + 1)) == "not" && - token.GetString(*atToken + 2) == ".") { + ConvertToLowerCase(token[*atToken + 1].ToString()) == "not" && + token[*atToken + 2].ToString() == ".") { op = NOT; *atToken += 2; } else { @@ -655,7 +680,7 @@ static std::int64_t ExpressionValue(const TokenSequence &token, left = ExpressionValue(token, operandPrecedence[op], atToken, errors); switch (op) { case PARENS: - if (*atToken < tokens && token.GetString(*atToken) == ")") { + if (*atToken < tokens && token[*atToken].ToString() == ")") { ++*atToken; } else if (errors->empty()) { *errors = "')' missing from expression"; @@ -684,10 +709,10 @@ static std::int64_t ExpressionValue(const TokenSequence &token, // Parse and evaluate a binary operator and its second operand, if present. int advance{1}; - t = token.GetString(*atToken); + t = token[*atToken].ToString(); if (t == "." && *atToken + 2 < tokens && - token.GetString(*atToken + 2) == ".") { - t += ConvertToLowerCase(token.GetString(*atToken + 1)) + '.'; + token[*atToken + 2].ToString() == ".") { + t += ConvertToLowerCase(token[*atToken + 1].ToString()) + '.'; advance = 3; } auto it = opNameMap.find(t); @@ -795,15 +820,15 @@ static std::int64_t ExpressionValue(const TokenSequence &token, bool Preprocessor::IsIfPredicateTrue(const TokenSequence &expr, size_t first, - size_t exprTokens, std::string *errors) { + size_t exprTokens) { TokenSequence expr1{StripBlanks(expr, first, first + exprTokens)}; TokenSequence expr2; for (size_t j{0}; j < expr1.size(); ++j) { - if (ConvertToLowerCase(expr1.GetString(j)) == "defined") { + if (ConvertToLowerCase(expr1[j].ToString()) == "defined") { CharPointerWithLength name; if (j + 3 < expr1.size() && - expr1.GetString(j + 1) == "(" && - expr1.GetString(j + 3) == ")") { + expr1[j + 1].ToString() == "(" && + expr1[j + 3].ToString() == ")") { name = expr1[j + 2]; j += 3; } else if (j + 1 < expr1.size() && @@ -820,10 +845,13 @@ Preprocessor::IsIfPredicateTrue(const TokenSequence &expr, size_t first, TokenSequence expr3{ReplaceMacros(expr2)}; TokenSequence expr4{StripBlanks(expr3, 0, expr3.size())}; size_t atToken{0}; - bool result{ExpressionValue(expr4, 0, &atToken, errors) != 0}; - if (atToken < expr4.size() && errors->empty()) { - *errors = atToken == 0 ? "could not parse any expression" - : "excess characters after expression"; + std::string error; + bool result{ExpressionValue(expr4, 0, &atToken, &error) != 0}; + if (!error.empty()) { + Complain(error); + } else if (atToken < expr4.size()) { + Complain(atToken == 0 ? "could not parse any expression" + : "excess characters after expression"); } return result; } diff --git a/flang/preprocessor.h b/flang/preprocessor.h index ad9fee1..29f8d1b 100644 --- a/flang/preprocessor.h +++ b/flang/preprocessor.h @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -44,6 +44,7 @@ class CharPointerWithLength { const char *data() const { return data_; } const char &operator[](size_t j) const { return data_[j]; } + bool IsBlank() const; std::string ToString() const { return std::string{data_, bytes_}; } private: @@ -99,18 +100,10 @@ class TokenSequence { return *this; } - size_t GetBytes(size_t token) const { - return (token + 1 >= start_.size() ? char_.size() : start_[token + 1]) - - start_[token]; - } - const char *GetText(size_t token) const { - return &char_[start_[token]]; - } - std::string GetString(size_t token) const { - return std::string(GetText(token), GetBytes(token)); - } CharPointerWithLength operator[](size_t token) const { - return {GetText(token), GetBytes(token)}; + return {&char_[start_[token]], + (token + 1 >= start_.size() ? char_.size() : start_[token + 1]) - + start_[token]}; } void AddChar(char ch) { @@ -129,7 +122,8 @@ class TokenSequence { } void Append(const TokenSequence &); - void EmitWithCaseConversion(CharBuffer *); + void EmitWithCaseConversion(CharBuffer *) const; + std::string ToString() const; bool empty() const { return start_.empty(); } size_t size() const { return start_.size(); } @@ -152,16 +146,6 @@ class TokenSequence { push_back(t.data(), t.size()); } -#if 0 - void push_back(const std::string &s) { - size_t bytes{s.size()}; - for (size_t j{0}; j < bytes; ++j) { - AddChar(s[j]); - } - EndToken(); - } -#endif - void push_back(const std::stringstream &ss) { push_back(ss.str()); } void pop_back() { @@ -224,21 +208,20 @@ class Preprocessor { // return value is false. bool MacroReplacement(const TokenSequence &, TokenSequence *); - // Implements a preprocessor directive; returns an error message, or an - // empty string when successful. - std::string Directive(const TokenSequence &); + // Implements a preprocessor directive; returns true when no fatal error. + bool Directive(const TokenSequence &); private: enum class IsElseActive { No, Yes }; enum class CanDeadElseAppear { No, Yes }; + void Complain(const std::string &); CharPointerWithLength SaveToken(const CharPointerWithLength &); bool IsNameDefined(const CharPointerWithLength &); TokenSequence ReplaceMacros(const TokenSequence &); - std::string SkipDisabledConditionalCode(const std::string &dirName, - IsElseActive); + bool SkipDisabledConditionalCode(const std::string &dirName, IsElseActive); bool IsIfPredicateTrue(const TokenSequence &expr, size_t first, - size_t exprTokens, std::string *errors); + size_t exprTokens); Prescanner &prescanner_; std::list names_; diff --git a/flang/prescan.cc b/flang/prescan.cc index 2c5a27b..9d1a0d9 100644 --- a/flang/prescan.cc +++ b/flang/prescan.cc @@ -398,12 +398,8 @@ bool Prescanner::CommentLinesAndPreprocessorDirectives() { IsFreeFormComment(lineStart_)) { NextLine(); } else if (IsPreprocessorDirectiveLine(lineStart_)) { - auto here = lineStartPosition_; if (std::optional tokens{NextTokenizedLine()}) { - std::string err{preprocessor_.Directive(*tokens)}; - if (!err.empty()) { - *error_ << here << ' ' << err << '\n'; - } + anyFatalErrors_ |= !preprocessor_.Directive(*tokens); } } else { break; diff --git a/flang/prescan.h b/flang/prescan.h index 4e09ed5..22d12f8 100644 --- a/flang/prescan.h +++ b/flang/prescan.h @@ -13,21 +13,23 @@ // preprocessing and INCLUDE lines need not be handled. #include "char-buffer.h" +#include "message.h" #include "position.h" #include "preprocessor.h" #include "source.h" #include -#include namespace Fortran { class Prescanner { public: - explicit Prescanner(std::stringstream *err) - : error_{err}, preprocessor_{*this} {} + explicit Prescanner(Messages &messages) + : messages_{messages}, preprocessor_{*this} {} + Messages &messages() const { return messages_; } const SourceFile &sourceFile() const { return *sourceFile_; } Position position() const { return atPosition_; } + bool anyFatalErrors() const { return anyFatalErrors_; } Prescanner &set_fixedForm(bool yes) { inFixedForm_ = yes; @@ -87,7 +89,8 @@ class Prescanner { bool FreeFormContinuation(); void PayNewlineDebt(CharBuffer *); - std::stringstream *error_; + Messages &messages_; + bool anyFatalErrors_{false}; const char *lineStart_{nullptr}; // next line to process; <= limit_ const char *at_{nullptr}; // next character to process; < lineStart_ int column_{1}; // card image column position of next character