如何使用 antlr 4 匹配 EOF 条件?

问题描述 投票:0回答:1

我是ANTLR的新手,目前正在ANTLR 4中编写一个酷语的词典。http:/theory.stanford.edu~aikensoftwarecoolcool-manual.pdf。.

我试图实现的一个很酷的语言规则是检测注释(可能是嵌套)或字符串常量内的EOF,并报告为错误。

这是我写的规则。

ERROR :  '(*' (COMMENT|~['(*'|'*)'])*? (~['*)']) EOF {reportError("EOF in comment");} 
        |'"' (~[\n"])* EOF {reportError("EOF in string");};
fragment COMMENT     : '(*' (COMMENT|~['(*'|'*)'])*? '*)'

这里的片段comment是我使用的一个递归规则。

函数 报告错误 上面使用的错误报告如下。

public void reportError(String errorString){
        setText(errorString);
        setType(ERROR);
}

但是当我在下面的测试文件上运行它时:

"Test String

它给出了以下输出:

line 1:0 token recognition error at: '"Test String\n'
#name "helloworld.cl"

很明显,带有 EOF 的字符串没有被识别,并且没有检测到 ERROR。

谁能帮我指出我哪里出错了,因为EOF(因此,错误规则)在某种程度上没有被lexer检测到。

如果有什么不清楚的地方,请指出来。

comments antlr4 eof lexer string-constant
1个回答
0
投票
'"' (~[\n"])* EOF

这里是 ~[\n"]* 部分将停止在第一个 \n" 或在文件的最后。

如果它停在 "的规则不匹配,因为 EOF 不匹配,而这正是我们想要的,因为字符串的文字是正确终止的。

如果它停在文件的结尾,那么随后的 EOF 会匹配,你会得到一个 ERROR 令牌。所以这也是你想要的。

但如果它停在一个 \nజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజజ EOF 将不匹配,你也不会得到一个错误标记,尽管在这种情况下你会想要一个。而且由于你的输入以 \n这正是你在这里遇到的情况。所以除了 EOF,你也应该允许错误的字符串字元以 \n:

'"' (~[\n"])* ('\n' | EOF)

0
投票

你不需要一个专门的 ERROR 规则,你可以直接在错误监听器中使用未完成的字符串来处理这种特殊情况。你可以直接在你的错误监听器中用未完成的字符串来处理这种特殊情况。不过,你的注释规则不应该是一个片段,因为它必须自己识别一个必须处理的词素(片段规则而是只在其他词典规则中使用的规则)。

当词法器到达一个字符串但由于输入结束而无法完成时,你可以在你的错误监听器中从当前词法器状态中获取违规输入。然后你可以检查一下,看看到底是什么东西没有完成,就像我这里对MySQL中的3种引号文本类型所做的那样。

void LexerErrorListener::syntaxError(Recognizer *recognizer, Token *, size_t line,
                                     size_t charPositionInLine, const std::string &, std::exception_ptr ep) {
  // The passed in string is the ANTLR generated error message which we want to improve here.
  // The token reference is always null in a lexer error.
  std::string message;
  try {
    std::rethrow_exception(ep);
  } catch (LexerNoViableAltException &) {
    Lexer *lexer = dynamic_cast<Lexer *>(recognizer);
    CharStream *input = lexer->getInputStream();
    std::string text = lexer->getErrorDisplay(input->getText(misc::Interval(lexer->tokenStartCharIndex, input->index())));
    if (text.empty())
      text = " "; // Should never happen.

    switch (text[0]) {
      case '/':
        message = "Unfinished multiline comment";
        break;
      case '"':
        message = "Unfinished double quoted string literal";
        break;
      case '\'':
        message = "Unfinished single quoted string literal";
        break;
      case '`':
        message = "Unfinished back tick quoted string literal";
        break;

      default:
        // Hex or bin string?
        if (text.size() > 1 && text[1] == '\'' && (text[0] == 'x' || text[0] == 'b')) {
          message = std::string("Unfinished ") + (text[0] == 'x' ? "hex" : "binary") + " string literal";
          break;
        }

        // Something else the lexer couldn't make sense of (likely there is no rule that accepts this input).
        message = "\"" + text + "\" is no valid input at all";
        break;
    }
    owner->addError(message, 0, lexer->tokenStartCharIndex, line, charPositionInLine,
                    input->index() - lexer->tokenStartCharIndex);
  }
}

这段代码来自于 MySQL Workbench中的解析器模块.

© www.soinside.com 2019 - 2024. All rights reserved.