我想得到:(20 +( - 3))* 3 /(20/3)/ 2等于4.现在它等于17.
所以基本上它正在做(20/3)然后将其除以2,然后将3除以[(20/3)/ 2],然后将其乘以17.不确定如何将我的语法/规则/优先级改为让它正确阅读。任何指导都将不胜感激,谢谢。
%%
start: PROGRAMtoken IDtoken IStoken compoundstatement
compoundstatement: BEGINtoken {print_header();} statement semi ENDtoken {print_end();}
semi: SEMItoken statement semi
|
statement: IDtoken EQtoken exp
{ regs[$1] = $3; }
| PRINTtoken exp
{ cout << $2 << endl; }
| declaration
declaration: VARtoken IDtoken comma
comma: COMMAtoken IDtoken comma
|
exp: exp PLUStoken term
{ $$ = $1 + $3; }
| exp MINUStoken term
{ $$ = $1 - $3; }
| term
{ $$ = $1; }
| MINUStoken term
{ $$ = -$2;}
term: factor
{ $$ = $1;
}
| factor TIMEStoken term
{$$ = $1 * $3;
}
| factor DIVIDEtoken term
{ $$ = $1 / $3;
}
factor: ICONSTtoken
{ $$ = $1;}
| IDtoken
{ $$ = regs[$1]; }
| LPARENtoken exp RPARENtoken
{ $$ = $2;}
%%
我的代币和类型如下:
%token BEGINtoken
%token COMMAtoken
%left DIVIDEtoken
%left TIMEStoken
%token ENDtoken
%token EOFtoken
%token EQtoken
%token <value> ICONSTtoken
%token <value> IDtoken
%token IStoken
%token LPARENtoken
%left PLUStoken MINUStoken
%token PRINTtoken
%token PROGRAMtoken
%token RPARENtoken
%token SEMItoken
%token VARtoken
%type <value> exp
%type <value> term
%type <value> factor
答案 0 :(得分:1)
你真的希望有人努力工作来给你一个答案,这就是为什么问题已经持续了一年。请阅读此帮助页面:https://stackoverflow.com/help/how-to-ask,特别是关于简化问题的部分。语法文件中有许多规则不需要重现问题。我们不需要:
%token BEGINtoken
%token COMMAtoken
%token ENDtoken
%token EOFtoken
%token EQtoken
%token <value> IDtoken
%token IStoken
%token PROGRAMtoken
%token VARtoken
%%
start: PROGRAMtoken IDtoken IStoken compoundstatement
compoundstatement: BEGINtoken {print_header();} statement semi ENDtoken {print_end();}
semi: SEMItoken statement semi
|
| declaration
declaration: VARtoken IDtoken comma
comma: COMMAtoken IDtoken comma
|
您可能刚刚删除了这些令牌和规则,以了解运营商优先级问题的核心。我们不需要任何变量,声明,赋值或程序结构来说明失败。学习简化是有能力的调试和编程的心脏。如果你做了这个简化,那么更多人会有回答。我说的不是OP,而是那些会遇到类似问题的人!
我想知道学校在设置这项任务是什么,因为我在同一个愚蠢的问题上看到了相当数量的yacc问题。我怀疑每年会有更多的人来这里,所以回答这个问题会对他们有所帮助。我知道检查语法的问题是什么,但是为了测试我的解决方案,我必须编写一个有效的词法分析器,一些符号表例程,一个主程序和其他辅助代码。再一次,解决问题的另一个障碍。
让我们了解问题的核心。您有这些令牌声明:
%left DIVIDEtoken
%left TIMEStoken
%left PLUStoken MINUStoken
这些告诉yacc,如果操作员关联左边的任何规则是不明确的。您对这些运营商的规则是:
exp: exp PLUStoken term
{ $$ = $1 + $3; }
| exp MINUStoken term
{ $$ = $1 - $3; }
| term
{ $$ = $1; }
| MINUStoken term
{ $$ = -$2;}
term: factor
{ $$ = $1;
}
| factor TIMEStoken term
{$$ = $1 * $3;
}
| factor DIVIDEtoken term
{ $$ = $1 / $3;
}
但是,这些规则不不明确,因此不需要运算符优先级声明。 Yacc将遵循您使用的非模糊语法。这些规则的编写方式,告诉yacc操作符具有正确的关联性,这与您想要的相反。现在,从您的示例中的简单算法可以清楚地看出,运算符是以正确的关联方式计算的,而您希望相反。那里有很大的线索吗?
行。如何改变关联性?一种方法是再次使语法不明确,以便使用%left
声明,或者只是翻转规则以反转关联性。这就是我所做的:
exp: term PLUStoken exp
{ $$ = $1 + $3; }
| term MINUStoken exp
{ $$ = $1 - $3; }
| term
{ $$ = $1; }
| MINUStoken term
{ $$ = -$2;}
term: factor
{ $$ = $1;
}
| term TIMEStoken factor
{$$ = $1 * $3;
}
| term DIVIDEtoken factor
{ $$ = $1 / $3;
}
你看到我在那里做了什么吗?我围绕操作员旋转了语法规则。
现在有更多的免责声明。我说这是一个 dumb 练习。动态解释表达式是对yacc工具的不良使用,而不是真正的编译器或解释器中发生的事情。在实际实现中,将构建解析树,并且将在树行走期间执行值计算。这样就可以解决未声明变量的问题(这也发生在本练习中)。使用regs
数组来存储值也很愚蠢,因为显然有一个辅助符号表用于返回符号的唯一整数ID。在真正的编译器/解释器中,这些值也将存储在该符号表中。
我希望本教程能帮助进一步的学生在课堂作业中理解这些解析问题。