我正在尝试编写一个识别特定语法的解析器。我很远,大多数东西都有效。我遇到了Bison解析器的一个问题,但试图让它识别两个相似但不同的结构。 以下是我希望它识别的两种结构:
type_1 IS ENUMERATION OF
BEGIN
element_1,
element_2 := 4
END type_1;
type_2 IS ENUMERATION SIZE 8 OF
BEGIN
element_1,
element_2 := 4
END type_2;
基本上这是针对类似枚举的声明,可以在有或没有元素的bitsize参数的情况下给出。
我写的Bison文件包含两个版本的两个替代品。它们中的每一个都是独立的,或者当它们在另一个之前分开时,它们运作良好。但是,当我将两个描述放入Y文件时,它只识别我的一个声明或另一个。
以下是野牛代码:
enum_type : sized_enum_type { $$=$1; P3; }
| nonsized_enum_type { $$=$1; P3; }
;
sized_enum_type : identifier[L] {P1(37,$L->Get_Line(),$L->Get_Column());}
IS[I] {P2(38,$I.ln,$I.clmn);}
ENUMERATION[N] {P2(43,$N.ln,$N.clmn);}
SIZE[Z] {P2(42,$Z.ln,$Z.clmn);}
INTEGER_VALUE[V] {P2(39,$V.ln,$V.clmn);}
OF[O] {P2(40,$O.ln,$O.clmn);}
TBEGIN[B] {P2(16,$B.ln,$B.clmn);}
enum_element_list[S] {P2(41,$S->Get_Line(),$S->Get_Column());}
TEND[E] {P2(16,$E.ln,$E.clmn);}
identifier[R] {P2(15,$R->Get_Line(),$R->Get_Column());}
SEMICOLON {$$= new AST::AST_Type_Enum( (AST::AST_Code_Identifier *) $L, $V.value ); $$->_Set_Line_And_Column( $I.ln, $I.clmn); P3;}
;
nonsized_enum_type : identifier[L] {P1(37,$L->Get_Line(),$L->Get_Column());}
IS[I] {P2(38,$I.ln,$I.clmn);}
ENUMERATION[N] {P2(39,$N.ln,$N.clmn);}
OF[O] {P2(40,$O.ln,$O.clmn);}
TBEGIN[B] {P2(16,$B.ln,$B.clmn);}
enum_element_list[S] {P2(41,$S->Get_Line(),$S->Get_Column());}
TEND[E] {P2(16,$E.ln,$E.clmn);}
identifier[R] {P2(15,$R->Get_Line(),$R->Get_Column());}
SEMICOLON {$$= new AST::AST_Type_Enum( (AST::AST_Code_Identifier *) $L, -1 ); $$->_Set_Line_And_Column( $I.ln, $I.clmn); P3;}
;
enum_element_list : one_enum { $$=$1; }
| one_enum COMMA enum_element_list { ((AST::AST_Enum_Value *)$1)->Append( (AST::AST_Enum_Value *) $3); $$=$1; }
;
one_enum : identifier[L] {$$= new AST::AST_Enum_Value( (AST::AST_Code_Identifier *) $L, -1 ); $$->_Set_Line_And_Column( $L->Get_Line(),$L->Get_Column()); P3;}
| identifier[L] {P1(17,$L->Get_Line(),$L->Get_Column());}
ASSIGNMENT_SHALLOW_COPY[A] {P2(42,$A.ln, $A.clmn);}
INTEGER_VALUE[I] {$$= new AST::AST_Enum_Value( (AST::AST_Code_Identifier *) $L, $I.value ); $$->_Set_Line_And_Column( $L->Get_Line(),$L->Get_Column()); P3;}
;
我不认为每个规则部分右侧的C语句是必要的,但我仍然将它们包括在内。
当我在源代码上运行编译的解析器时,它抱怨它期望令牌SIZE。当我交换nonsized_enum_type和sized_enum_type的规则(不是enum_type规则的右边,规则的完整源代码顺序,将一个规则移到另一个规则之下),然后它识别没有大小的另一个形式。当我在我的代码中包含SIZE 8部分时,它会抱怨它期待另一种形式(OF expected)。
所以我的问题是:如何编写一个解析两个部分的解析器规则?
生成的代码不应该识别出一条规则无处可去,然后尝试另一条规则吗?似乎第二条规则从未尝试过。
谢谢大家
答案 0 :(得分:1)
将所有这些中规则操作(MRA)插入到语法中会削弱解析器。由于您未包含P1
和P2
的定义,因此很难知道您为何需要MRA,但实际上不太可能需要执行特定的减少操作在令牌IS
和ENUMERATION
之间,而不是稍后执行缩减操作。
具体地,问题可以减少到以下。考虑两个产品(仅限于他们的第一个MRA):
sized_enum_type : identifier[L] {P1(37,$L->Get_Line(),$L->Get_Column());}
nonsized_enum_type : identifier[L] {P1(37,$L->Get_Line(),$L->Get_Column());}
每个MRA都使用标签生成实现。从左到右解析的逻辑是在移位下一个令牌之前必须执行所有缩减。在上述两种情况下,下一个令牌都是IS
,但看到IS
并未说明应执行哪个缩减。因此,野牛将报告减少/减少冲突,然后选择定义文件中首先出现的生产。另一个减少将被有效地消除,这使得其余的生产无法实现。
两种减少行动恰好相同,但野牛不知道。从野牛的角度来看,所有的MRA都是独一无二的。实际上,MRA的使用要求语法 - 至少在该特定点 - 是LL(1),从而消除了LR(1)解析算法的所有优点。
你可以通过左因素来避免这个问题,但我强烈建议你尽量减少对MRAs的依赖。对于构建AST,MRA几乎不需要,并且它们具有非平凡的成本以及降低解析器处理非LL(1)语法的能力。