我有一些野牛语法:
input: /* empty */
| input command
;
command:
builtin
| external
;
builtin:
CD { printf("Changing to home directory...\n"); }
| CD WORD { printf("Changing to directory %s\n", $2); }
;
我想知道如何让Bison不接受(YYACCEPT?)某事作为command
,直到它读取所有输入。所以我可以在下面使用所有这些规则来使用递归或其他任何构建的东西,这会产生一个有效的命令或一些不起作用的东西。
我正在使用上面的代码进行的一个简单测试就是输入“cd mydir mydir”。野牛解析CD
和WORD
然后“嘿!这是一个命令,把它放到顶部!”。然后它找到的下一个标记只是WORD
,它没有规则,然后报告错误。
我希望它阅读整行并意识到CD WORD WORD
不是规则,然后报告错误。我想我错过了一些明显的东西,非常感谢任何帮助 - 谢谢!
此外 - 我尝试使用input command NEWLINE
或类似内容,但它仍然将CD WORD
作为命令推送到顶部,然后分别解析额外的WORD
。
答案 0 :(得分:2)
有时我通过压扁我的语法处理这些案件。
在你的情况下,为你的词法分析器为换行符和命令分隔符(;)添加标记可能是有意义的,这样你就可以明确地将它们放入你的Bison语法中,这样解析器就可以期待命令的完整输入行了。接受作为一个命令。
sep: NEWLINE | SEMICOLON
;
command: CD sep
| CD WORD sep
;
或者,对于像真实shell这样的任意参数列表:
args:
/* empty */
| args WORD
;
command:
CD args sep
;
答案 1 :(得分:1)
不要直接调用操作,而是先构建一个抽象语法树。然后根据结果和您的偏好,您可以执行部分操作,也可以不执行任何操作。如果在构建树期间出现解析错误,您可能需要使用%destructor指令告诉bison如何进行清理。
这实际上是一种正确的方法,因为你可以完全控制内容和逻辑,而你让bison只需要解析它。
答案 2 :(得分:0)
通常,事情并没有按照你描述的方式完成。
对于Bison / Yakk / Lex,人们通常会仔细设计他们的语法以完全满足他们的需要。因为Bison / Yakk / Lex自然greedy有正则表达式,所以这对你有帮助。
那么,相反如何。
由于您一次解析整个行,我认为我们可以利用这一事实来修改语法。
input : /* empty */
| line
command-break : command-break semi-colon
| semi-colon
line : commands new-line
commands : commands command-break command
| commands command-break command command-break
| command
| command command-break
...
new-line
,'分号is defined in your
lex source as something like
\ n ,
\ t``这应该为您提供您正在寻找的命令的UNIX样式语法。各种各样的事情是可能的,它有点膨胀,允许多个分号,并没有考虑到空白,但你应该得到这个想法。
Lex和Yakk是一个强大的工具,我发现它们非常有趣 - 至少,当你没有在截止日期之前。
答案 3 :(得分:0)
难道你不能只改变规则匹配操作以附加到你想要执行的操作列表中吗?然后在处理完整个输入之后,根据您是否看到任何解析错误,决定是否要执行该操作列表中的操作。