0

我是 ANTLR 新手,目前正在为 ANTLR 4 中的酷语言编写词法分析器。有关酷语言的更多信息,请参阅http://theory.stanford.edu/~aiken/software/cool/cool-manual.pdf

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

这是我写的规则:

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

这里的片段 COMMENT 是我使用的递归规则。

上面使用的函数reportError报告错误,如下所示:

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(因此,错误规则)在某种程度上没有被词法分析器检测到。

如果有不清楚的地方,请务必提及。

4

2 回答 2

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

此处,该~[\n"]*部分将在文件的开头\n"结尾处停止。

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

如果它在文件末尾停止,则后续EOF将匹配并且您将获得一个ERROR令牌。所以这也是你想要的。

但是,如果它停在 a \n,则EOF将不匹配,即使在这种情况下您想要一个,您也不会得到错误令牌。由于您的输入以 结尾\n,这正是您在这里遇到的情况。因此,除了 之外EOF,您还应该允许错误的字符串文字以 结尾\n

'"' (~[\n"])* ('\n' | EOF)
于 2020-06-07T08:44:48.207 回答
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 中的解析器模块

于 2020-06-07T09:03:12.783 回答