我正在使用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
第一个问题(已解决)是它解析了变量声明而不是构造函数声明,尽管我在类本身的范围内没有变量声明(即我只在构造函数的块内部)。这已经解决了。
尽管如此,如果我提供以下class abc { some1 abc; john doe; }
,则表示syntax error, unexpected SEMICOLON, expecting LP
。因此,第19行的角色会导致问题。
这是 .y 文件(仅 classBody 规则)
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
;
以下是完整 .y 文件的octal representation。
答案 0 :(得分:2)
基本问题是constructor_declmore
可能为空,var_decl
和constructor_decl
都可以ID
开头。
这是一个问题,因为在解析器识别constructor_decl
之前,它需要减少(空)constructor_declmore
。但它显然无法做到这种减少,除非它知道var_declmore
已经完成。
因此当它看到ID
时,它必须在两个动作中的一个之间做出决定:
减少空constructor_declmore
,从而确定不再有var_decl
s;或
转移ID
以开始解析新的var_decl
。
在没有优先权声明的情况下(这里没有帮助),bison / yacc总是解决转移/减少冲突,转而支持转移行动。因此,在这种情况下,它会假定Foo
是ID
,它会启动var_decl
,从而导致您注意到的错误消息。
还应该查看语法产生的减少/减少冲突。它来自method_declmore: method_decl
规则,该规则与创建method_declmore
的其他可能方式冲突,首先是空method_declmore
,然后添加method_decl
。