野牛:结构不好

时间:2012-05-13 18:24:06

标签: c++ parsing bison yacc lex

我在野牛中做了一个完整的解析器(当然还有flex中的lexer),我昨天才注意到我的解析器中存在问题。在If结构中实际上。

以下是我的解析器中的规则:http://pastebin.com/TneESwUx

此处无法识别单个IF,如果我将“%prec IFX”替换为“END”,则通过添加新标记“END”(flex中为"end" return END;),它可以正常工作。但我不想要一个新的“结束”关键字,这就是为什么我不使用这个解决方案。

请帮帮我。

2 个答案:

答案 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,那就是正确的。括号不必关闭。但是如果添加)怎么办?哪个(正在关闭?

这非常无法判断哪个IFELSE匹配。

如果您将END添加到IF的语法(无论是否存在ELSE),那么就像是有一个右括号。 IFEND()类似。

当然,你在风格上不想在你的语言中使用单词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短语结构规则,因为您的语句会直接生成{}中包含的短语。如果采用这种方法,你将不得不破解它。