【问题标题】:Why the last rule matching in my lex file, when I have better rules?当我有更好的规则时,为什么我的 lex 文件中的最后一条规则匹配?
【发布时间】:2019-11-09 15:57:43
【问题描述】:

我有一个lex 文件,里面有我的规则,例如:

PROGRAM           return Parser::PROGRAM;
PROGRAM_END       return Parser::PROGRAM_END;
VARIABLES:        return Parser::VARIABLES;
INSTRUCTIONS:     return Parser::INSTRUCTIONS; 
SKIP              return Parser::SKIP;
.           {
                std::cerr << lineno() << ": ERROR." << std::endl;
                exit(1);
            }

当我尝试使用完全编译的(使用yacc 文件等)版本时,即使测试文件正确,也仅在测试文件上使用最后一条规则。

例如,这是这些规则的测试文件:

PROGRAM fst
INSTRUCTIONS:
    SKIP
PROGRAM_END

对于这个文件,我只得到:1: ERROR

为什么会这样,我该如何解决?

【问题讨论】:

  • 您的输入不包含&lt;&lt;=&gt;,您错了只使用了最后一条规则,或者您的真实代码中发生了其他事情这在您发布的摘录中不可见。没有看到minimal reproducible example就不可能说出来。
  • @sepp2k 我用一个例子和这个例子的必要规则更新了我的问题。
  • 你怎么知道PROGRAM 规则在那个例子中没有运行?如果您在该规则中添加一条打印语句,我相信您会看到它的输出。无论如何,如果您希望它仍然对包含未知字符的输入执行某些操作(除了退出并显示错误消息),您可能不应该在未知字符上退出程序。我还建议在.-rule 中打印有问题的输入。
  • @sepp2k 我知道,因为yacc 文件应该打印每个被捕获的规则。如果我用YYText() 打印,那么什么也没有:1: ERROR:
  • 如果您在. 规则中打印违规字符,您可能会发现。我无法告诉您真实代码中缺少哪些规则,因为我没有看到您的真实代码,但我可以告诉您,在您的示例中,第一个未知字符将是 PRORGAMfst 之间的空格。

标签: regex bison yacc lex bisonc++


【解决方案1】:

如 cmets 所示,几乎可以肯定,PROGRAM 开始被识别为令牌并传递给解析器。然而,在几乎所有情况下,解析器都会立即请求另一个标记,输入序列中的下一个字符是空格,它与最后一条规则匹配。该规则打印一条错误消息并调用exit(),终止应用程序。 (这通常不是一个好主意,但我想这只是一个测试程序。)这就是您将获得的所有输出。

如果您在调用 (f)lex 时指定了-d 命令行参数,那么将生成一个调试扫描器,它会在扫描器工作时报告其进度。这是查看扫描仪中发生的情况的一种非常简单的方法。 Bison 还具有调试模式,如bison manual 中所述。这些工具使用起来非常简单,强烈推荐。

例如,这里是一个快速测试台:

%{
#include <iostream>
#include <cstdlib>
class Parser {
  public:
    enum Token {
      PROGRAM = 257,
      PROGRAM_END, VARIABLES, INSTRUCTIONS, SKIP
    };
};
%}
%option batch noyywrap yylineno c++
%%
PROGRAM           return Parser::PROGRAM;
PROGRAM_END       return Parser::PROGRAM_END;
VARIABLES:        return Parser::VARIABLES;
INSTRUCTIONS:     return Parser::INSTRUCTIONS; 
SKIP              return Parser::SKIP;
.                 {
                    std::cerr << lineno() << ": ERROR." << std::endl;
                    exit(1);
                  }
%%
int main() {
  yyFlexLexer lexer{};
  lexer.set_debug(1);
  while(lexer.yylex() != 0) { }
  return 0;
}

还有一个示例运行:

$ g++ lex.yy.cc && ./a.out<<<"PROGRAM fst"
--(end of buffer or a NUL)
--accepting rule at line 14("PROGRAM")
--accepting rule at line 19(" ")
1: ERROR.

这清楚地表明扫描器确实首先生成了PROGRAM 令牌,然后才以空格字符退出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 2012-05-16
    • 2012-01-28
    • 2015-09-20
    • 1970-01-01
    相关资源
    最近更新 更多