我正在尝试在Bison输入文件中描述此语法: https://courses.engr.illinois.edu/cs421/sp2011/mps/mp2/minijavasyntax.pdf
这是我的意见:
%start Program
%token KW_CLASS KW_EXTENDS KW_PUBLIC KW_STATIC KW_BOOLEAN KW_STRING KW_FLOAT KW_INT EOF
%token KW_IF KW_WHILE KW_BREAK KW_CONTINUE KW_SWITCH KW_CASE KW_DEFAULT KW_RETURN
%token KW_NEW KW_THIS KW_NULL KW_TRUE KW_FALSE KW_PRINTLN
%token IDENT INT_LITERAL FLOAT_LITERAL STRING_LITERAL
%nonassoc "THEN"
%nonassoc KW_ELSE
%right "STATEMENTS"
%right OP_ASSIGN
%left OP_OR
%left OP_AND
%nonassoc CMP_EQ CMP_NEQ
%nonassoc CMP_GT CMP_LT CMP_GTE CMP_LTE
%left OP_ADD OP_MINUS
%left OP_MULT OP_DIV OP_MOD
%right OP_NOT OP_UNARY "NEW"
%left "FUNCALL" "SUBSCRIPT" '.'
%nonassoc '('
%nonassoc ')'
%%
Program: ClassDeclp EOF
;
ClassDeclp: ClassDecl
| ClassDeclp ClassDecl
;
ClassDecl: KW_CLASS IDENT ExtendsFrom
'{' VarDecls MethodDecls '}'
;
ExtendsFrom: /*empty*/
| KW_EXTENDS IDENT
;
VarDecls: /*empty*/
| VarDecls VarDecl
;
VarDecl: Type IDENT ';'
| KW_STATIC Type IDENT ';' /*Co the sua thanh AcessModifier Type IDENT*/
;
MethodDecls: /*empty*/
| MethodDecls MethodDecl
;
MethodDecl: KW_PUBLIC Type IDENT
'('MethodParams')'
'{'VarDecls Statements KW_RETURN Expression ';' '}'
;
MethodParams: /*empty*/
| MethodParams ',' MethodParam
;
MethodParam: Type IDENT;
Type : Type '['']'
| KW_BOOLEAN
| KW_STRING
| KW_FLOAT
| KW_INT
| IDENT
;
Statements: Statements Statement %prec "STATEMENTS"
| /*empty*/ %prec "STATEMENT"
;
Statementp: Statements Statement %prec "STATEMENTS"
;
Statement: '{'Statements'}'
| KW_IF '(' Expression ')' Statement %prec "THEN"
| KW_IF '(' Expression ')' Statement KW_ELSE Statement
| KW_WHILE '(' Expression ')'Statement
| KW_PRINTLN '(' Expression ')' ';'
| IDENT OP_ASSIGN Expression ';'
| KW_BREAK ';'
| KW_CONTINUE ';'
| IDENT %prec "SUBSCRIPT" '['Expression']' '=' Expression ';'
| KW_SWITCH '(' Expression ')' '{'
Cases
KW_DEFAULT ':' Statementp '}'
;
Cases: Cases Case
| /*empty*/
;
Case: KW_CASE INT_LITERAL ':' Statementp
;
Expression: Expression OP_OR Expression
| Expression OP_AND Expression
| Expression CMP_EQ Expression
| Expression CMP_NEQ Expression
| Expression CMP_GT Expression
| Expression CMP_GTE Expression
| Expression CMP_LT Expression
| Expression CMP_LTE Expression
| Expression OP_ADD Expression
| Expression OP_MINUS Expression
| Expression OP_MULT Expression
| Expression OP_DIV Expression
| Expression OP_MOD Expression
| '-' Expression %prec OP_UNARY
| OP_NOT Expression
| Expression %prec "SUBSCRIPT" '['Expression']'
| Expression '.'"length"
| Expression '.' IDENT %prec "FUNCALL" '(' ParamList ')'
| INT_LITERAL
| FLOAT_LITERAL
| STRING_LITERAL
| KW_NULL
| KW_TRUE
| KW_FALSE
| IDENT
| KW_THIS
| KW_NEW Type '[' Expression ']' %prec "NEW"
| KW_NEW IDENT '('')' %prec "NEW"
| '(' Expression ')'
;
ParamList: /*empty*/
| ParamList ',' Expression
| Expression
;
%%
main(int argc, char** argv[])
{
extern FILE *yyin;
++argv; --argc;
yyin = fopen(argv[0], "r");
yydebug = 1;
errors = 0;
yyparse();
}
yyerror(char *s)
{
printf("%s\n", s);
}
/* Co 3 conflict RR can xu ly khi bien thuoc kieu bool
giua BoolExpr va Expresstion */
编译时我遇到了两个16冲突。 其中一个冲突,我用--report = lookahead:
运行了Bison OP_NOT Expression . [OP_OR, OP_AND, CMP_EQ, CMP_NEQ, CMP_GT, CMP_LT, CMP_GTE, CMP_LTE, OP_ADD, OP_MINUS, OP_MULT, OP_DIV, OP_MOD, ')', ';', ',', '[', ']']
我所期望的是'['不在OP_NOT前瞻标记中,因为SUBSCRIPT优先级必须高于Operator! 其他冲突就像这样。我该怎么解决呢 TKS
答案 0 :(得分:1)
这不是优先权如何运作。
编辑:如果您发现下面的描述令人困惑,或者您不想浏览这么多英文文本,您可以采取我的常规建议: Don&#tt使用优先级。你几乎总能编写一个不需要优先级声明的明确语法。如果你这样做,你就不需要了解优先权。 (虽然,老实说,如果你理解LR解析的工作原理并不复杂。) / EDIT
优先级总是比较可能的缩减(即右手边与当前解析器堆栈顶部匹配的制作)和前瞻符号。
在这一点上:
Expression : Expression · '[' Expression ']'
唯一可能的解析器操作是移位,因为只有在该点位于右侧末尾时才会发生缩减。
然而,在出现这一点的其中一个州,还有另一个产品:
Expression : OP_NOT Expression ·
这个可以减少,因为这一点已经结束了。
由于这两个点都处于相同的状态,因此它们必须都是有效的。这意味着我们正在考虑:
OP_NOT Expression · '[' Expression ']'
我们正在努力弄清楚要做什么。我们可以将OP_NOT Expression
缩减为Expression
,此时我们可以:
Expression · '[' Expression ']'
或者我们可以转移' ['留下我们
OP_NOT Expression '[' · Expression ']'
由于这两种情况都是可能的,因此存在转移/减少冲突。 Yacc / Bison将尝试使用优先规则解决该冲突(如果存在)。特别是,它需要比较可能减少的生产的优先级:
Expression : OP_NOT Expression
和符号可能会移位:'['
。
但是,彻底查看优先级声明会显示没有为'['
分配优先级。因此,yacc / bison无法针对生产进行测试(其优先级由右侧的最后一个终端OP_NOT
定义,因为没有%prec
声明。
如果您希望后缀下标运算符([
表达式']')具有比前缀运算符OP_NOT
更高的优先级,则必须为{{声明优先级1}}高于[
。
顺便说一下,我不明白这里的不一致之处。您可以将OP_NOT
用于!
(OP_NOT
用于-
,依此类推),这样更容易阅读,也更少工作。
您似乎认为
中的OP_MINUS
声明
%prec
是相关的。它不是。只有在解析器可以减少Expression %prec "SUBSCRIPT" '['Expression']'
时才适用。但它也毫无意义,因为你不需要创建一个假终端来保持该产品的优先权;它的优先级由右侧的最后一个终端Expression '[' Expression ']'
定义,因此您只能为该终端声明一个优先级。
需要声明']'
中的假令牌,因为Expression : OP_MINUS Expression %prec OP_UNARY
有两个不同的优先级,或者更准确,因为'-'
具有与OP_MINUS Expression
不同的优先级。但是,你实际上并不需要发明假令牌;您可以使用任何具有正确优先级的令牌,例如Expresson OP_MINUS Expression
或OP_NOT
。
如果没有足够的话,我试图在几个不同的答案中解释这一点。 Here's one以及here's another one和here's another one。另外,here's one by Chris Dodd以及the bison manual中的文档。如果你很幸运,你可能会用自己的语言找到一个描述,通过使用最适合你的互联网搜索引擎或者如果你有一个教授与你的教授交谈。
顺便说一下,先行报告会告诉您哪些符号可能跟随给定的作品。优先顺序对此没有影响。 OP_NEW
肯定可以关注[
。优先级告诉解析器是减少还是移位,但是可能触发reduce或shift的令牌肯定在先行集中。