我尝试以下yacc代码并接收shift / reduce错误。我对这个很陌生
The Purpose of the code is to prepare the syntax for if - else with logical operators also incorporated
%{
#include<stdio.h>
#include"lex.yy.c"
int syntax_status=0;
%}
%token IF ELS id EE LE GE closep openp num openb closeb SP logicop
%start S
%%
S : S SP IF SP openp SP EXP SP closep SP openb SP closeb SP ELS SP openb SP closeb SP {syntax_status=1;}
| S SP IF SP openp SP EXP SP closep SP openb SP closeb SP {syntax_status = 1;}
|
;
EXP : EXP CMP logicop CMP
| EXP CMP
|
;
CMP : CMP id EE id
| CMP id LE id
| CMP id GE id
| CMP id EE num
| CMP id GE num
| CMP id LE num
| CMP num EE id
| CMP num GE id
| CMP num LE id
|
;
%%
int main()
{
printf("\n\n\n Enter the Syntax : ");
yyparse();
if(syntax_status==1)
{
printf("\n\n\n The Syntax is Correct ");
}
else
{
printf("\n\n\n The Syntax is Imcorrect");
}
return 0;
}
yyerror(char *s)
{
syntax_status=0;
}
此对应yacc代码的Lex程序如下 :
%{
#include<stdio.h>
#include"y.tab.h"
%}
IF (if)
ELS (else)
iden [a-zA-Z][a-zA-Z0-9]*
num [0-9]+
space [ ]*
%%
{IF} { return IF; }
{ELS} {return ELSE;}
{iden} {return id;}
(==) {return EE;}
(<=) { return LE;}
(>=) { return GE;}
")" { return closep;}
"(" { return openp;}
{num} { return num;}
{space} { return SP; }
"{" { return openb;}
"}" { return closeb;}
"||"|"&&"|"!=" {return logicop;}
%%
答案 0 :(得分:2)
CMP和EXP规则看起来都很成问题。采取这种最右边的推导,例如:
EXP ==> (by EXP -> CMP)
EXP CMP ==> (by CMP -> CMP id EE id)
EXP CMP id EE id ==> (by CMP -> CMP id EE id)
EXP CMP id EE id id EE id ==> (by CMP -> epsilon)
EXP id EE id id EE id ==> (by EXP -> epsilon )
id EE id id EE id ==>
id == id id == id
我很确定这不是你想要的。它还在语法中引入了歧义:可以通过这种不同的最右边推导得到相同的终端串:
EXP ==> (by EXP -> CMP)
EXP CMP ==> (by CMP -> CMP id EE id)
EXP CMP id EE id ==> (by CMP -> epsilon)
EXP id EE id ==> (by EXP -> CMP)
EXP CMP id EE id ==> (by CMP -> CMP id EE id)
EXP CMP id EE id id EE id ==> (by CMP -> epsilon)
EXP id EE id id EE id ==> (by EXP-> epsilon)
id EE id id EE id ==>
id == id id == id
你知道,yacc无法知道id == id id == id
是真的exp exp
还是exp
。此外,exp-&gt; epsilon规则允许使用像if(){}
这样的表达式,这不是很好。
现在,请考虑以下语法:
exp -> exp logicop cmp | cmp
cmp -> rvalue < rvalue | rvalue > rvalue ...
rvalue -> id | num
但它也可以这样做:
exp -> exp op exp | rvalue
op -> "||" | "&&" | "<" | ">" ...
后者是传统的做法,但你需要语义检查以确保操作数是正确的类型,而前一个语法确保在语法层面上。从长远来看(一旦引入布尔变量),第二种方法更为可取,因为类型安全是语义问题,而不是语法问题。
另一方面注意:空格似乎与您的语言不相关,但是lex将它们交给yacc。你可以通过说
让lex丢弃词汇层面的空格{space} //nothing after a pattern discards the matched characters
这样可以省去在yacc中写出所有SP的麻烦。
答案 1 :(得分:1)
您需要指定运算符的优先级和关联性:例如,请参阅here。我引用了教派。 6
作为这些声明行为的一个例子,描述
%right '='
%left '+' '-'
%left '*' '/'
%%
expr : expr '=' expr
| expr '+' expr
| expr '-' expr
| expr '*' expr
| expr '/' expr
| NAME
;
可能用于构造输入
a = b = c*d - e - f*g
如下:
a = ( b = ( ((c*d)-e) - (f*g) ) )
您的CMP
运营商必须以类似的方式定义,并且您的logicop
应该被划分。要获得布尔表达式中的常规读数,通常不会表现为一元减号,和*一样,或者像+一样。
HTH