我正在使用bison(3.0.4)和lexer来实现Decaf编程语言的(部分)语法。我只是在实现类内部的内容。
因此,我的任务很简单:将每个生成规则(作为字符串)存储在树中,然后打印出来。
例如,如果您有以下代码行作为输入
class Foo { Foo(int arg1) { some2 a; } }
你(必须)得到以下输出
<ClassDecl> --> class identifier <classBody>
<ClassBody> --> { <VariableDecl>* <ConstructorDecl>* <MethodDecl>* }
<ConstructorDecl> --> identifier ( <ParameterList> ) <Block>
<ParameterList> --> <Parameter> <, Parameter>*
<Parameter> --> <Type> identifier
<Type> --> <SimpleType>
<SimpleType> --> int
<Block> --> { <LocalVariableDecl>* <Statement>* }
<LocalVariableDecl> --> <Type> identifier ;
<Type> --> <SimpleType>
<SimpleType> --> identifier
第一个问题(解决了)是,它解析了变量声明,而不是 构造函数声明然而,如果我给出下面的 这是.y文件(仅classBody规则) 以下是完整.y文件的要点。class abc { some1 abc; john doe; }
,它表示syntax error, unexpected SEMICOLON, expecting LP
。因此,第19行的字符导致了问题。class_decl:
CLASS ID LC class_body RC
;
/* FIXME: Gotta add more grammar here */
class_body: var_declmore constructor_declmore method_declmore
| var_declmore constructor_declmore
| var_declmore method_declmore
| constructor_declmore method_declmore
| method_declmore
| var_declmore
| constructor_declmore
| %empty
;
var_declmore: var_decl
| var_declmore var_decl
;
constructor_declmore: constructor_decl
| constructor_declmore constructor_decl
;
var_decl: type ID SEMICOLON
| type ID error
;
constructor_decl: ID LP parameter_list RP block
| ID error parameter_list RP block
;
关键问题是constructor_declmore
可以为空,并且var_decl
和constructor_decl
都可以以ID
开头。
这是一个问题,因为在解析器能够识别constructor_decl
之前,它需要减少一个(空的)constructor_declmore
。但是,除非它知道var_declmore
已经完成,否则它显然不能进行这种减少。
因此,当它看到ID
时,它必须在以下两种操作之一之间做出决定:
-
减少一个空的
constructor_declmore
,从而决定不再有var_decl
;或 -
移位
ID
,以便开始解析新的var_decl
。
在没有优先级声明的情况下(这在这里没有帮助),bison/yacc总是解决移位/减少冲突,以支持移位操作。因此,在这种情况下,它假设Foo
是启动var_decl
的ID
,从而导致您注意到的错误消息。
语法产生的reduce/reduce冲突也应该考虑一下。它来自method_declmore: method_decl
规则,它与创建method_declmore
的另一种可能方式相冲突,即从一个空的method_declmore
开始,然后添加一个method_decl
。