【发布时间】:2011-05-07 22:14:08
【问题描述】:
我正在尝试在我的 flex (.l) 文件中解析 C 样式的多行 cmets:
%s ML_COMMENT
%%
...
<INITIAL>"/*" BEGIN(ML_COMMENT);
<ML_COMMENT>"*/" BEGIN(INITIAL);
<ML_COMMENT>[.\n]+ { }
我没有返回任何标记,而且我的语法 (.y) 没有以任何方式解决 cmets。
当我运行我的可执行文件时,我得到一个解析错误:
$ ./a.out
/*
abc
def
Parse error: parse error
$ echo "/* foo */" | ./a.out
Parse error: parse error
(我的 yyerror 函数执行 printf("Parse error: %s\n"),这是冗余错误消息的前半部分的来源)。
我可以看到为什么第二个示例失败了,因为整个输入都是注释,并且由于语法忽略了 cmets,因此没有语句。因此输入不是一个有效的程序。但是第一部分在我完成评论之前就抛出了一个解析错误。
同样令人困惑:
$ ./a.out
/* foo */
a = b;
Parse error: parse error
在这种情况下,注释在实际有效输入之前关闭(没有注释,解析就好了)。失败实际上发生在解析“a”之后,而不是在尝试解析赋值“a = b;”之后。如果我在自己的行上输入“a”,它仍然会引发错误。
鉴于错误消息是解析器错误而不是扫描仪错误,我的 .y 文件中是否缺少一些重要的信息?还是我在传播到解析器端的扫描仪规则中做错了什么?
编辑:按照@Rudi的建议,我打开调试发现:
$ ./a.out
Starting parse
Entering state 0
Reading a token: /*
foo
Next token is 44 (IDENTIFER)
Shifting token 44 (IDENTIFER), Entering state 4
Reducing via rule 5 (line 130), IDENTIFER -> identifier
state stack now 0
Entering state 5
我关闭了调试,发现/* foo */ = bar;确实和foo = bar;解析一样。我正在使用 flex 2.5.4;它没有给我任何关于我尝试使用的有状态规则的警告。
【问题讨论】:
-
我将 flex 重新标记为 gnu-flex。您的扫描仪规则看起来不错。解析错误表明对解析器的令牌输入无效。您可能想发布一些相应的 Bison 规则。此外,将 printf() 语句放入您的 bison 规则中可能是一个好主意,这样您就可以看到解析器在扫描令牌期间正在尝试哪些规则。
-
为您的扫描仪创建一个单独的测试工具也是一个好主意。这样,您就可以将扫描仪缺陷与解析器缺陷隔离开来。任何扫描仪-解析器系统都足够复杂,当您真正想要的是执行单元测试时,您不需要通过执行集成测试来注入额外的复杂性......
-
-
我建议 - 有理由不这样做 - 只是编写一个 Perl 预处理器来咀嚼 cmets。
标签: c comments bison multiline flex-lexer