我已经用柠檬语(类似于YACC(整理了一个语法,但它产生了S/R冲突。 我不习惯 LALR 解析,不明白问题是什么,也不明白如何解决。 语法是:
%right EQUALS.
%right RIGHT_ASSIGN LEFT_ASSIGN MOD_ASSIGN DIV_ASSIGN MUL_ASSIGN.
%right QUESTION COLON.
%left EQ_OP.
%left NE_OP LE_OP GE_OP LCARET RCARET.
%left PLUS MINUS.
%left STAR PERCENT FSLASH.
%right UNA.
%left DOT PTR_OP.
%left UN.
%left LBRACKET LSBRACKET RBRACKET RSBRACKET.
%right DOTACCESS.
file ::= statement_list EOF.
statement_break ::= EOL.
statement_list ::= statement statement_break.
statement_list ::= statement_list statement statement_break.
statement ::= expr.
statement ::= assign_expr argument_expr_list. [UN]
primary_expr
::= IDENTIFIER.
primary_expr
::= CONSTANT.
primary_expr
::= STRING_LITERAL.
primary_expr
::= LBRACKET expr RBRACKET.
postfix_expr
::= primary_expr.
postfix_expr
::= postfix_expr LSBRACKET expr RSBRACKET. [UN]
postfix_expr
::= postfix_expr LBRACKET RBRACKET. [UN]
postfix_expr
::= postfix_expr LBRACKET argument_expr_list RBRACKET. [UN]
postfix_expr
::= postfix_expr DOT IDENTIFIER. [DOTACCESS]
postfix_expr
::= postfix_expr PTR_OP IDENTIFIER. [DOTACCESS]
postfix_expr
::= postfix_expr INC_OP.
postfix_expr
::= postfix_expr DEC_OP.
argument_expr_list
::= assign_expr.
argument_expr_list
::= argument_expr_list COMMA assign_expr.
unary_expr
::= postfix_expr.
unary_expr
::= unary_operator cast_expr. [UNA]
unary_expr
::= SIZEOF unary_expr. [UN]
unary_expr
::= SIZEOF LBRACKET type_name RBRACKET. [UN]
unary_operator
::= EXCLAMATION.
cast_expr
::= unary_expr.
cast_expr
::= LBRACKET type_name RBRACKET cast_expr. [UNA]
mul_expr
::= cast_expr.
mul_expr
::= mul_expr STAR cast_expr.
mul_expr
::= mul_expr FSLASH cast_expr.
mul_expr
::= mul_expr PERCENT cast_expr.
add_expr
::= mul_expr.
add_expr
::= add_expr PLUS mul_expr.
add_expr
::= add_expr MINUS mul_expr.
shift_expr
::= add_expr.
shift_expr
::= shift_expr LEFT_OP add_expr.
shift_expr
::= shift_expr RIGHT_OP add_expr.
rel_expr
::= shift_expr.
rel_expr
::= rel_expr LCARET shift_expr.
rel_expr
::= rel_expr RCARET shift_expr.
rel_expr
::= rel_expr LE_OP shift_expr.
rel_expr
::= rel_expr GE_OP shift_expr.
eq_expr
::= rel_expr.
eq_expr
::= eq_expr EQ_OP rel_expr.
eq_expr
::= eq_expr NE_OP rel_expr.
and_expr
::= eq_expr.
and_expr
::= and_expr AND eq_expr.
excl_or_expr
::= and_expr.
excl_or_expr
::= excl_or_expr HAT and_expr.
incl_or_expr
::= excl_or_expr.
incl_or_expr
::= incl_or_expr BAR excl_or_expr.
log_and_expr
::= incl_or_expr.
log_and_expr
::= log_and_expr AND_OP incl_or_expr.
log_or_expr
::= log_and_expr.
log_or_expr
::= log_or_expr OR_OP log_and_expr.
cond_expr
::= log_or_expr.
cond_expr
::= log_or_expr QUESTION expr COLON cond_expr.
assign_expr
::= cond_expr.
assign_expr
::= unary_expr assign_op assign_expr.
assign_op
::= EQUALS. [EQUALS]
assign_op
::= MUL_ASSIGN. [EQUALS]
assign_op
::= DIV_ASSIGN. [EQUALS]
assign_op
::= MOD_ASSIGN. [EQUALS]
assign_op
::= ADD_ASSIGN. [EQUALS]
assign_op
::= SUB_ASSIGN. [EQUALS]
assign_op
::= LEFT_ASSIGN. [EQUALS]
assign_op
::= RIGHT_ASSIGN. [EQUALS]
assign_op
::= AND_ASSIGN. [EQUALS]
assign_op
::= XOR_ASSIGN. [EQUALS]
assign_op
::= OR_ASSIGN. [EQUALS]
expr
::= assign_expr.
expr
::= expr COMMA assign_expr.
type_name
::= TYPE.
柠檬的输出是:
State 4:
primary_expr ::= * IDENTIFIER
primary_expr ::= * CONSTANT
primary_expr ::= * STRING_LITERAL
primary_expr ::= * LBRACKET expr RBRACKET
postfix_expr ::= * primary_expr
postfix_expr ::= * postfix_expr LSBRACKET expr RSBRACKET
postfix_expr ::= * postfix_expr LBRACKET RBRACKET
postfix_expr ::= postfix_expr LBRACKET * RBRACKET
postfix_expr ::= * postfix_expr LBRACKET argument_expr_list RBRACKET
postfix_expr ::= postfix_expr LBRACKET * argument_expr_list RBRACKET
postfix_expr ::= * postfix_expr DOT IDENTIFIER
postfix_expr ::= * postfix_expr PTR_OP IDENTIFIER
postfix_expr ::= * postfix_expr INC_OP
postfix_expr ::= * postfix_expr DEC_OP
argument_expr_list ::= * assign_expr
argument_expr_list ::= * argument_expr_list COMMA assign_expr
unary_expr ::= * postfix_expr
unary_expr ::= * unary_operator cast_expr
unary_expr ::= * SIZEOF unary_expr
unary_expr ::= * SIZEOF LBRACKET type_name RBRACKET
unary_operator ::= * EXCLAMATION
cast_expr ::= * unary_expr
cast_expr ::= * LBRACKET type_name RBRACKET cast_expr
mul_expr ::= * cast_expr
mul_expr ::= * mul_expr STAR cast_expr
mul_expr ::= * mul_expr FSLASH cast_expr
mul_expr ::= * mul_expr PERCENT cast_expr
add_expr ::= * mul_expr
add_expr ::= * add_expr PLUS mul_expr
add_expr ::= * add_expr MINUS mul_expr
shift_expr ::= * add_expr
shift_expr ::= * shift_expr LEFT_OP add_expr
shift_expr ::= * shift_expr RIGHT_OP add_expr
rel_expr ::= * shift_expr
rel_expr ::= * rel_expr LCARET shift_expr
rel_expr ::= * rel_expr RCARET shift_expr
rel_expr ::= * rel_expr LE_OP shift_expr
rel_expr ::= * rel_expr GE_OP shift_expr
eq_expr ::= * rel_expr
eq_expr ::= * eq_expr EQ_OP rel_expr
eq_expr ::= * eq_expr NE_OP rel_expr
and_expr ::= * eq_expr
and_expr ::= * and_expr AND eq_expr
excl_or_expr ::= * and_expr
excl_or_expr ::= * excl_or_expr HAT and_expr
incl_or_expr ::= * excl_or_expr
incl_or_expr ::= * incl_or_expr BAR excl_or_expr
log_and_expr ::= * incl_or_expr
log_and_expr ::= * log_and_expr AND_OP incl_or_expr
log_or_expr ::= * log_and_expr
log_or_expr ::= * log_or_expr OR_OP log_and_expr
cond_expr ::= * log_or_expr
cond_expr ::= * log_or_expr QUESTION expr COLON cond_expr
assign_expr ::= * cond_expr
assign_expr ::= * unary_expr assign_op assign_expr
LBRACKET shift 2
RBRACKET shift-reduce 12 postfix_expr ::= postfix_expr LBRACKET RBRACKET
IDENTIFIER shift-reduce 6 primary_expr ::= IDENTIFIER
CONSTANT shift-reduce 7 primary_expr ::= CONSTANT
STRING_LITERAL shift-reduce 8 primary_expr ::= STRING_LITERAL
SIZEOF shift 32
EXCLAMATION shift-reduce 24 unary_operator ::= EXCLAMATION
assign_expr shift 43 /* because assign_expr==argument_expr_list */
argument_expr_list shift 43
primary_expr shift 36 /* because primary_expr==postfix_expr */
postfix_expr shift 36
unary_expr shift 33
unary_operator shift 31
cast_expr shift 42 /* because cast_expr==mul_expr */
mul_expr shift 42
add_expr shift 55
shift_expr shift 54
rel_expr shift 39
eq_expr shift 47
and_expr shift 69
excl_or_expr shift 68
incl_or_expr shift 66
log_and_expr shift 64
log_or_expr shift 45
cond_expr shift 43 /* because cond_expr==assign_expr */
State 20:
primary_expr ::= * IDENTIFIER
primary_expr ::= * CONSTANT
primary_expr ::= * STRING_LITERAL
primary_expr ::= * LBRACKET expr RBRACKET
postfix_expr ::= * primary_expr
postfix_expr ::= * postfix_expr LSBRACKET expr RSBRACKET
postfix_expr ::= * postfix_expr LBRACKET RBRACKET
postfix_expr ::= * postfix_expr LBRACKET argument_expr_list RBRACKET
postfix_expr ::= * postfix_expr DOT IDENTIFIER
postfix_expr ::= * postfix_expr PTR_OP IDENTIFIER
postfix_expr ::= * postfix_expr INC_OP
postfix_expr ::= * postfix_expr DEC_OP
unary_expr ::= * postfix_expr
unary_expr ::= * unary_operator cast_expr
unary_expr ::= * SIZEOF unary_expr
unary_expr ::= * SIZEOF LBRACKET type_name RBRACKET
unary_operator ::= * EXCLAMATION
cast_expr ::= * unary_expr
cast_expr ::= * LBRACKET type_name RBRACKET cast_expr
mul_expr ::= * cast_expr
mul_expr ::= * mul_expr STAR cast_expr
mul_expr ::= * mul_expr FSLASH cast_expr
mul_expr ::= * mul_expr PERCENT cast_expr
add_expr ::= * mul_expr
add_expr ::= * add_expr PLUS mul_expr
add_expr ::= * add_expr MINUS mul_expr
shift_expr ::= * add_expr
shift_expr ::= * shift_expr LEFT_OP add_expr
shift_expr ::= * shift_expr RIGHT_OP add_expr
rel_expr ::= rel_expr LE_OP * shift_expr
LBRACKET shift 2
IDENTIFIER shift-reduce 6 primary_expr ::= IDENTIFIER
CONSTANT shift-reduce 7 primary_expr ::= CONSTANT
STRING_LITERAL shift-reduce 8 primary_expr ::= STRING_LITERAL
SIZEOF shift 32
EXCLAMATION shift-reduce 24 unary_operator ::= EXCLAMATION
primary_expr shift 36 /* because primary_expr==postfix_expr */
postfix_expr shift 36
unary_expr shift 42 /* because unary_expr==mul_expr */
unary_operator shift 31
cast_expr shift 42 /* because cast_expr==mul_expr */
mul_expr shift 42
add_expr shift 55
shift_expr shift 49
State 36:
postfix_expr ::= postfix_expr * LSBRACKET expr RSBRACKET
postfix_expr ::= postfix_expr * LBRACKET RBRACKET
postfix_expr ::= postfix_expr * LBRACKET argument_expr_list RBRACKET
postfix_expr ::= postfix_expr * DOT IDENTIFIER
postfix_expr ::= postfix_expr * PTR_OP IDENTIFIER
postfix_expr ::= postfix_expr * INC_OP
postfix_expr ::= postfix_expr * DEC_OP
(20) unary_expr ::= postfix_expr *
DOT shift 61
PTR_OP shift 60
LBRACKET shift 4
LBRACKET reduce 20 ** Parsing conflict **
LSBRACKET shift 7
INC_OP shift-reduce 16 postfix_expr ::= postfix_expr INC_OP
DEC_OP shift-reduce 17 postfix_expr ::= postfix_expr DEC_OP
{default} reduce 20 unary_expr ::= postfix_expr
您可以在"状态 36"中找到冲突(我剔除了多余的输出(。我相信它应该可以通过优先规则解决,但我无法弄清楚如何解决。
冲突来自规则
statement ::= assign_expr argument_expr_list. [UN]
在我看来,这是完全没有必要的。从这种生产中获得的任何statement
也可以来自
statement: expr.
所以语法是模棱两可的:
assign_expr
的一个例子是a = b
(unary_expr assign_op assign_expr
(。另一个例子是a = sin(0.5)
.由于我们也有statement ::= expr
(和expr ::= assign_expr
(,a = sin(0.5)
可以通过两种方式解析为statement
:作为assign_expr
a = sin(0.5)
,直接简化为expr
,或作为assign_expr
a = sin
后跟argument_expr_list
。在我看来,第二种情况永远没有用,应该从语法中删除生产。但也许你脑海中有一些特定的语义。
你的语法充满了优先级声明,这些声明可能不会造成任何伤害,但我怀疑这些优先级声明中的任何一个是否有任何影响。当然,报告的特定移位/减少冲突无法通过任何优先级声明来解决,因为可能的减少是没有声明优先级的单位规则。(unary_expr ::= postfix_expr.
(给予它一个武断的优先顺序可能会解决冲突,但在我看来,它似乎不太可能以有用的方式解决冲突;它不能以有益的方式解决冲突。无论您如何解决它,其他一些规则都将变得不可用,这是一个不好的迹象。