我在野牛中做了一个完整的解析器(当然还有flex中的lexer),我昨天才注意到我的解析器中存在问题。在If结构中实际上。
以下是我的解析器中的规则:http://pastebin.com/TneESwUx
此处无法识别单个IF,如果我将“%prec IFX”替换为“END”,则通过添加新标记“END”(flex中为"end" return END;
),它可以正常工作。但我不想要一个新的“结束”关键字,这就是为什么我不使用这个解决方案。
请帮帮我。
答案 0 :(得分:2)
'处理这种规则的正确方法不是优先级,它是重构使用可选的else部分,以便解析器可以使用令牌先行来决定如何解析。我会设计这样的东西:
stmt : IF '(' expression ')' stmts else_part
| /* other statement productions here */
else_part : /* optional */
| ELSE stmts
stmts : stmt
| '{' stmt_list '}'
| '{' '}'
stmt_list : stmt
| stmt_list ';' stmt
(这种特殊套管stmts
的方法,而不是允许stmt
包含块可能在制作方面不是最佳的,并且可能会在您的语言中引入奇怪,但没有更多细节,这很难要肯定地说。bison
可以生成一个报告,向您展示它生成的解析器是如何工作的;您可能想要研究它。还要注意意外的转移/减少冲突,特别是任何减少/减少冲突。)
请注意,在这种语法中,shift / reduce冲突完全正常; LALR(1)解析器的意思是将这些冲突用作特征,通过单个标记向前看以解决冲突。它们是专门报告的,因此您可以更容易地检测到您 想要的那些,并通过错误地将语法分解来引入。
您的IfExpression
也需要重构才能匹配;诀窍是else_part
应该为$$
生成某种条件表达式,并且在IF
的制作中你测试$6
(对应else_part
)并调用相应的IfExpression
构造函数。
答案 1 :(得分:1)
你的语法含糊不清,所以你必须忍受转变/减少冲突。 END
令牌通过确保IF
语句始终正确关闭(如一对括号)来消除歧义。
括号在这里做了一个很好的比喻。假设你有这样的语法:
maybe_closed_parens : '(' stuff
| '(' stuff ')'
;
stuff
本身会生成一些语法符号,其中一个是maybe_closed_parens
。
因此,如果您输入((((((whatever
,那就是正确的。括号不必关闭。但是如果添加)
怎么办?哪个(
正在关闭?
这非常无法判断哪个IF
与ELSE
匹配。
如果您将END
添加到IF
的语法(无论是否存在ELSE
),那么就像是有一个右括号。 IF
和END
与(
和)
类似。
当然,你在风格上不想在你的语言中使用单词END
,因为你已经有了花括号的块,这基本上是Pascal BEGIN
的替代拼写, END
。您的}
已经是END
个关键字。
所以你可以做的是强加IF
只接受复合语句(即完全支撑)的规则:
if_statement : IF condition compound_statement
| IF condition compound_statement ELSE compound_statement
现在不可能有一个歧义,如果你喜欢z,因为大括号必须存在:if x { if y { w } else { z } } or if x { if y { w } } else { z }
。
我似乎记得Perl是一种做出这种选择的语言的例子。这不是一个坏主意,因为它不仅消除了你的歧义,更重要的是它消除了程序的含糊之处。
我发现您的语法中没有compound_statement
短语结构规则,因为您的语句会直接生成{
和}
中包含的短语。如果采用这种方法,你将不得不破解它。