Bison/flex 没有括号的逻辑表达式不起作用
Bison/flex logical expression no parentheses not working
当我尝试执行带有圆括号的逻辑顺序时,它可以工作,但没有圆括号时它 returns line 11: syntax error at '=='
那11行是
if c == 1 or b == 0 and not a == 0{
我已经将 and, or, not 定义为标记。如果我在该行使用括号,它可以工作,但没有它们也必须工作。这是我的 parser.y 代码
| adierazpena RAND M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->trueL, $<erref>3);
$<adi>$->trueL = $<adi>4->trueL;
$<adi>$->falseL = $<adi>1->falseL;
$<adi>$->falseL.insert($<adi>$->falseL.end(), $<adi>4->falseL.begin(), $<adi>4->falseL.end());
delete $<adi>1;
delete $<adi>4;
}
| adierazpena ROR M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->falseL, $<erref>3);
$<adi>$->trueL = $<adi>1->trueL;
$<adi>$->trueL.insert($<adi>$->trueL.end(), $<adi>4->trueL.begin(), $<adi>4->trueL.end());
$<adi>$->falseL = $<adi>4->falseL;
delete $<adi>1;
delete $<adi>4;
}
| RNOT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL = $<adi>2->falseL;
$<adi>$->falseL = $<adi>2->trueL;
delete $<adi>2;
}
我也将优先级设置为 %left RAND RNOT ROR
我找不到任何解决方案,如有任何帮助,我们将不胜感激。
如果您需要,这是完整的 parser.y 代码
%{
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
extern int yylex();
extern int yylineno;
extern char *yytext;
void yyerror (const char *msg) {
printf("line %d: %s at '%s'\n", yylineno, msg, yytext) ;
}
#include "Kodea.h"
#include "Lag.h"
Kodea kodea;
%}
/* Hemen erazagutu ikurrek zein atributu-mota izan dezaketen */
%union {
string *izena;
string *mota;
IdLista *izenak;
expressionstruct *adi;
int erref;
skipexitstruct *jauzi;
}
/*
Tokenak erazagutu. Honek tokens.l fitxategiarekin
bat etorri behar du.
Atributu lexikoak ere hemen erazagutu behar dira.
.izena atributua duten tokenak:
*/
%token <izena> TID TINTEGER TFLOAT
/* Atributurik gabeko tokenak: */
%token RINT RFLOAT TASSIG TLBRACE TRBRACE TSEMIC TKOM RDO RPROGRAM RUNTIL RELSE
%token RPROC TLPAR TRPAR TIN TIO RWHILE RFOREVER RSKIP RIF REXIT RREAD
%token TSUM TSUB TMUL TDIV TCEQ TCGT TCLT TCGE TLEOUT TCNE RPRINTLN
%token RAND ROR RNOT
/* Hemen erazagutu atributuak dauzkaten ez-bukaerakoak */
%type <adi> adierazpena
%type <izena> aldagaia
%type <mota> mota par_mota
%type <izenak> id_zerrenda id_zerrendaren_bestea
%type <erref> M
%type <jauzi> sententzia sententzia_zerrenda
%start programa
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
%left RAND RNOT ROR
%%
programa : RPROGRAM TID { kodea.agGehitu("prog " + *$<izena>2); delete $<izena>2;}
erazagupenak azpiprogramen_erazagupena
TLBRACE sententzia_zerrenda TRBRACE {kodea.agGehitu("halt "); kodea.idatzi();}
;
erazagupenak : mota id_zerrenda TSEMIC
{kodea.erazagupenakGehitu(*$<mota>1, *$<izenak>2);delete $<izenak>2;}
erazagupenak
| /* hutsa */
;
id_zerrenda : TID id_zerrendaren_bestea
{
$<izenak>$ = new IdLista;
$<izenak>$ -> push_back(*$<izena>1);
$<izenak>$ -> insert($<izenak>$->end(), $<izenak>2->begin(), $<izenak>2->end());
delete $<izena>1;
delete $<izenak>2;
}
;
id_zerrendaren_bestea : TKOM TID id_zerrendaren_bestea
{
$<izenak>$ = new IdLista;
$<izenak>$ -> push_back(*$<izena>2);
$<izenak>$ -> insert($<izenak>$->end(), $<izenak>3->begin(), $<izenak>3->end());
delete $<izena>2;
delete $<izenak>3;
}
| /* hutsa */ {$<izenak>$ = new IdLista;}
;
mota : RINT {$<mota>$ = new std::string; *$<mota>$ = SINTEGER;}
| RFLOAT {$<mota>$ = new std::string; *$<mota>$ = SFLOAT;}
;
azpiprogramen_erazagupena : azpiprogramaren_erazagupena azpiprogramen_erazagupena
| /* hutsa */
;
azpiprogramaren_erazagupena : RPROC TID {kodea.agGehitu("proc " + *$<izena>2); delete $<izena>2;}
argumentuak erazagupenak azpiprogramen_erazagupena
TLBRACE sententzia_zerrenda TRBRACE {kodea.agGehitu("endproc");}
;
argumentuak : TLPAR par_zerrenda TRPAR
| /* hutsa */
;
par_zerrenda : mota par_mota id_zerrenda
{
kodea.parametroakGehitu(*$<mota>1, *$<izenak>3, *$<mota>2);
delete $<mota>1;
delete $<izenak>3;
delete $<mota>2;
}
par_zerrendaren_bestea
;
par_mota : TIN {$<mota>$ = new std::string; *$<mota>$ = "in";}
| TLEOUT {$<mota>$ = new std::string; *$<mota>$ = "out";}
| TIO {$<mota>$ = new std::string; *$<mota>$ = "in out";}
;
par_zerrendaren_bestea : TSEMIC mota par_mota id_zerrenda
{
kodea.parametroakGehitu(*$<mota>2, *$<izenak>4, *$<mota>3);
delete $<mota>2;
delete $<izenak>4;
delete $<mota>3;
}
par_zerrendaren_bestea
| /* hutsa */
;
sententzia_zerrenda : sententzia sententzia_zerrenda
{
$<jauzi>$ = new skipexitstruct;
$<jauzi>$->skip = $<jauzi>1->skip;
$<jauzi>$->skip.insert($<jauzi>$->skip.end(), $<jauzi>2->skip.begin(), $<jauzi>2->skip.end());
$<jauzi>$->exit = $<jauzi>1->exit;
$<jauzi>$->exit.insert($<jauzi>$->exit.end(), $<jauzi>2->exit.begin(), $<jauzi>2->exit.end());
delete $<jauzi>1;
delete $<jauzi>2;
}
| /* hutsa */ {$<jauzi>$ = new skipexitstruct;}
;
sententzia : aldagaia TASSIG adierazpena TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu(*$<izena>1 + " := " + $<adi>3->izena);
delete $<izena>1;
delete $<adi>3;
}
| RIF adierazpena M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>2->trueL, $<erref>3);
kodea.agOsatu($<adi>2->falseL, $<erref>7);
kodea.agOsatu($<jauzi>5->exit, $<erref>7);
$<jauzi>$->skip = $<jauzi>5->skip;
delete $<adi>2;
}
| RWHILE RFOREVER M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
stringstream ss; ss << $<erref>3;
kodea.agGehitu("goto " + ss.str());
kodea.agOsatu($<jauzi>5->exit, $<erref>7);
$<jauzi>$->skip = $<jauzi>5->skip;
delete $<jauzi>5;
}
| RDO M TLBRACE sententzia_zerrenda TRBRACE RUNTIL M adierazpena RELSE M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>8->trueL, $<erref>10);
kodea.agOsatu($<adi>8->falseL, $<erref>2);
kodea.agOsatu($<jauzi>4->skip, $<erref>7);
kodea.agOsatu($<jauzi>4->exit, $<erref>14);
kodea.agOsatu($<jauzi>12->exit, $<erref>14);
$<jauzi>$->skip = $<jauzi>12->skip;
delete $<adi>8;
delete $<jauzi>4;
delete $<jauzi>12;
}
| RSKIP RIF adierazpena TSEMIC M
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>3->falseL, $<erref>5);
$<jauzi>$->skip = $<adi>3->trueL;
delete $<adi>3;
}
| REXIT TSEMIC
{
$<jauzi>$ = new skipexitstruct;
$<jauzi>$->exit.push_back(kodea.lortuErref());
kodea.agGehitu("goto");
}
| RREAD TLPAR aldagaia TRPAR TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu("read " + *$<izena>3);
}
| RPRINTLN TLPAR aldagaia TRPAR TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu("write " + $<adi>3->izena);
kodea.agGehitu("writeln");
}
;
M : /* produkzio hutsa */ { $<erref>$ = kodea.lortuErref(); }
;
aldagaia : TID {$<izena>$ = $<izena>1;}
;
adierazpena : adierazpena TSUM adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " + " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TSUB adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " - " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TMUL adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " * " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TDIV adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " / " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCEQ adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " = " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCGT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " > " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCLT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " < " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCGE adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " >= " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TLEOUT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " <= " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCNE adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " != " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| aldagaia
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TINTEGER
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TFLOAT
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TLPAR adierazpena TRPAR
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = $<adi>2->izena;
$<adi>$->trueL = $<adi>2->trueL;
$<adi>$->falseL = $<adi>2->falseL;
delete $<izena>2;
}
| adierazpena RAND M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->trueL, $<erref>3);
$<adi>$->trueL = $<adi>4->trueL;
$<adi>$->falseL = $<adi>1->falseL;
$<adi>$->falseL.insert($<adi>$->falseL.end(), $<adi>4->falseL.begin(), $<adi>4->falseL.end());
delete $<adi>1;
delete $<adi>4;
}
| adierazpena ROR M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->falseL, $<erref>3);
$<adi>$->trueL = $<adi>1->trueL;
$<adi>$->trueL.insert($<adi>$->trueL.end(), $<adi>4->trueL.begin(), $<adi>4->trueL.end());
$<adi>$->falseL = $<adi>4->falseL;
delete $<adi>1;
delete $<adi>4;
}
| RNOT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL = $<adi>2->falseL;
$<adi>$->falseL = $<adi>2->trueL;
delete $<adi>2;
}
;
%%
我假设当您说“如果我在该行上使用圆括号它有效”时,您的意思是以下内容按预期工作:
(c == 1) or (b == 0) and not (a == 0)
那是因为你的优先声明顺序错误。
您有以下内容:
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
%left RAND RNOT ROR
这使得 and
、or
和 not
的绑定比 ==
(以及其他比较运算符)更强。相比之下,将 *
放在 +
之后是正确的,因为乘法确实比加法结合得更紧密。
因为 or
比比较更严格地保留参数,表达式 c == 1 or b == 0 and not a == 0
被分组为 c == (1 or b) == (0 and (not a)) == 0
,这是无意义的。这也是语法错误,因为您已正确声明 ==
是非关联的。
这些运算符应该位于优先级层次结构的开头,而不是末尾,因为它们需要更松散地绑定。此外,您可能应该尊重通常的约定,其中 and
比 or
绑定得更紧密。 (因为像 a > 0 and a < 10 or b > 0 and b < 10
这样的逻辑表达式很常见。)所以我建议将其更改为:
%left ROR
%left RAND
%left RNOT
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
有些语言赋予 not
与其他一元运算符相同的优先级,但显然您希望 not a == 0
表示 not (a == 0)
(即 a ≠ 0
)。在 C++ 中,! a == 0
将被分组为 (!a) == 0
,这也意味着应用整数和布尔值之间的转换后的 a ≠ 0
,但与 0 以外的数字进行比较时具有不同的含义。
当我尝试执行带有圆括号的逻辑顺序时,它可以工作,但没有圆括号时它 returns line 11: syntax error at '=='
那11行是
if c == 1 or b == 0 and not a == 0{
我已经将 and, or, not 定义为标记。如果我在该行使用括号,它可以工作,但没有它们也必须工作。这是我的 parser.y 代码
| adierazpena RAND M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->trueL, $<erref>3);
$<adi>$->trueL = $<adi>4->trueL;
$<adi>$->falseL = $<adi>1->falseL;
$<adi>$->falseL.insert($<adi>$->falseL.end(), $<adi>4->falseL.begin(), $<adi>4->falseL.end());
delete $<adi>1;
delete $<adi>4;
}
| adierazpena ROR M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->falseL, $<erref>3);
$<adi>$->trueL = $<adi>1->trueL;
$<adi>$->trueL.insert($<adi>$->trueL.end(), $<adi>4->trueL.begin(), $<adi>4->trueL.end());
$<adi>$->falseL = $<adi>4->falseL;
delete $<adi>1;
delete $<adi>4;
}
| RNOT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL = $<adi>2->falseL;
$<adi>$->falseL = $<adi>2->trueL;
delete $<adi>2;
}
我也将优先级设置为 %left RAND RNOT ROR
我找不到任何解决方案,如有任何帮助,我们将不胜感激。
如果您需要,这是完整的 parser.y 代码
%{
#include <stdio.h>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
extern int yylex();
extern int yylineno;
extern char *yytext;
void yyerror (const char *msg) {
printf("line %d: %s at '%s'\n", yylineno, msg, yytext) ;
}
#include "Kodea.h"
#include "Lag.h"
Kodea kodea;
%}
/* Hemen erazagutu ikurrek zein atributu-mota izan dezaketen */
%union {
string *izena;
string *mota;
IdLista *izenak;
expressionstruct *adi;
int erref;
skipexitstruct *jauzi;
}
/*
Tokenak erazagutu. Honek tokens.l fitxategiarekin
bat etorri behar du.
Atributu lexikoak ere hemen erazagutu behar dira.
.izena atributua duten tokenak:
*/
%token <izena> TID TINTEGER TFLOAT
/* Atributurik gabeko tokenak: */
%token RINT RFLOAT TASSIG TLBRACE TRBRACE TSEMIC TKOM RDO RPROGRAM RUNTIL RELSE
%token RPROC TLPAR TRPAR TIN TIO RWHILE RFOREVER RSKIP RIF REXIT RREAD
%token TSUM TSUB TMUL TDIV TCEQ TCGT TCLT TCGE TLEOUT TCNE RPRINTLN
%token RAND ROR RNOT
/* Hemen erazagutu atributuak dauzkaten ez-bukaerakoak */
%type <adi> adierazpena
%type <izena> aldagaia
%type <mota> mota par_mota
%type <izenak> id_zerrenda id_zerrendaren_bestea
%type <erref> M
%type <jauzi> sententzia sententzia_zerrenda
%start programa
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
%left RAND RNOT ROR
%%
programa : RPROGRAM TID { kodea.agGehitu("prog " + *$<izena>2); delete $<izena>2;}
erazagupenak azpiprogramen_erazagupena
TLBRACE sententzia_zerrenda TRBRACE {kodea.agGehitu("halt "); kodea.idatzi();}
;
erazagupenak : mota id_zerrenda TSEMIC
{kodea.erazagupenakGehitu(*$<mota>1, *$<izenak>2);delete $<izenak>2;}
erazagupenak
| /* hutsa */
;
id_zerrenda : TID id_zerrendaren_bestea
{
$<izenak>$ = new IdLista;
$<izenak>$ -> push_back(*$<izena>1);
$<izenak>$ -> insert($<izenak>$->end(), $<izenak>2->begin(), $<izenak>2->end());
delete $<izena>1;
delete $<izenak>2;
}
;
id_zerrendaren_bestea : TKOM TID id_zerrendaren_bestea
{
$<izenak>$ = new IdLista;
$<izenak>$ -> push_back(*$<izena>2);
$<izenak>$ -> insert($<izenak>$->end(), $<izenak>3->begin(), $<izenak>3->end());
delete $<izena>2;
delete $<izenak>3;
}
| /* hutsa */ {$<izenak>$ = new IdLista;}
;
mota : RINT {$<mota>$ = new std::string; *$<mota>$ = SINTEGER;}
| RFLOAT {$<mota>$ = new std::string; *$<mota>$ = SFLOAT;}
;
azpiprogramen_erazagupena : azpiprogramaren_erazagupena azpiprogramen_erazagupena
| /* hutsa */
;
azpiprogramaren_erazagupena : RPROC TID {kodea.agGehitu("proc " + *$<izena>2); delete $<izena>2;}
argumentuak erazagupenak azpiprogramen_erazagupena
TLBRACE sententzia_zerrenda TRBRACE {kodea.agGehitu("endproc");}
;
argumentuak : TLPAR par_zerrenda TRPAR
| /* hutsa */
;
par_zerrenda : mota par_mota id_zerrenda
{
kodea.parametroakGehitu(*$<mota>1, *$<izenak>3, *$<mota>2);
delete $<mota>1;
delete $<izenak>3;
delete $<mota>2;
}
par_zerrendaren_bestea
;
par_mota : TIN {$<mota>$ = new std::string; *$<mota>$ = "in";}
| TLEOUT {$<mota>$ = new std::string; *$<mota>$ = "out";}
| TIO {$<mota>$ = new std::string; *$<mota>$ = "in out";}
;
par_zerrendaren_bestea : TSEMIC mota par_mota id_zerrenda
{
kodea.parametroakGehitu(*$<mota>2, *$<izenak>4, *$<mota>3);
delete $<mota>2;
delete $<izenak>4;
delete $<mota>3;
}
par_zerrendaren_bestea
| /* hutsa */
;
sententzia_zerrenda : sententzia sententzia_zerrenda
{
$<jauzi>$ = new skipexitstruct;
$<jauzi>$->skip = $<jauzi>1->skip;
$<jauzi>$->skip.insert($<jauzi>$->skip.end(), $<jauzi>2->skip.begin(), $<jauzi>2->skip.end());
$<jauzi>$->exit = $<jauzi>1->exit;
$<jauzi>$->exit.insert($<jauzi>$->exit.end(), $<jauzi>2->exit.begin(), $<jauzi>2->exit.end());
delete $<jauzi>1;
delete $<jauzi>2;
}
| /* hutsa */ {$<jauzi>$ = new skipexitstruct;}
;
sententzia : aldagaia TASSIG adierazpena TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu(*$<izena>1 + " := " + $<adi>3->izena);
delete $<izena>1;
delete $<adi>3;
}
| RIF adierazpena M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>2->trueL, $<erref>3);
kodea.agOsatu($<adi>2->falseL, $<erref>7);
kodea.agOsatu($<jauzi>5->exit, $<erref>7);
$<jauzi>$->skip = $<jauzi>5->skip;
delete $<adi>2;
}
| RWHILE RFOREVER M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
stringstream ss; ss << $<erref>3;
kodea.agGehitu("goto " + ss.str());
kodea.agOsatu($<jauzi>5->exit, $<erref>7);
$<jauzi>$->skip = $<jauzi>5->skip;
delete $<jauzi>5;
}
| RDO M TLBRACE sententzia_zerrenda TRBRACE RUNTIL M adierazpena RELSE M TLBRACE sententzia_zerrenda TRBRACE M TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>8->trueL, $<erref>10);
kodea.agOsatu($<adi>8->falseL, $<erref>2);
kodea.agOsatu($<jauzi>4->skip, $<erref>7);
kodea.agOsatu($<jauzi>4->exit, $<erref>14);
kodea.agOsatu($<jauzi>12->exit, $<erref>14);
$<jauzi>$->skip = $<jauzi>12->skip;
delete $<adi>8;
delete $<jauzi>4;
delete $<jauzi>12;
}
| RSKIP RIF adierazpena TSEMIC M
{
$<jauzi>$ = new skipexitstruct;
kodea.agOsatu($<adi>3->falseL, $<erref>5);
$<jauzi>$->skip = $<adi>3->trueL;
delete $<adi>3;
}
| REXIT TSEMIC
{
$<jauzi>$ = new skipexitstruct;
$<jauzi>$->exit.push_back(kodea.lortuErref());
kodea.agGehitu("goto");
}
| RREAD TLPAR aldagaia TRPAR TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu("read " + *$<izena>3);
}
| RPRINTLN TLPAR aldagaia TRPAR TSEMIC
{
$<jauzi>$ = new skipexitstruct;
kodea.agGehitu("write " + $<adi>3->izena);
kodea.agGehitu("writeln");
}
;
M : /* produkzio hutsa */ { $<erref>$ = kodea.lortuErref(); }
;
aldagaia : TID {$<izena>$ = $<izena>1;}
;
adierazpena : adierazpena TSUM adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " + " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TSUB adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " - " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TMUL adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " * " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TDIV adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = kodea.idBerria();
kodea.agGehitu($<adi>$->izena + " := " + $<adi>1->izena + " / " + $<adi>3->izena);
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCEQ adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " = " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCGT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " > " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCLT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " < " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCGE adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " >= " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TLEOUT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " <= " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| adierazpena TCNE adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL.push_back(kodea.lortuErref());
$<adi>$->falseL.push_back(kodea.lortuErref()+1);
kodea.agGehitu("if " + $<adi>1->izena + " != " + $<adi>3->izena + " goto");
kodea.agGehitu("goto");
delete $<adi>1;
delete $<adi>3;
}
| aldagaia
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TINTEGER
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TFLOAT
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = *$<izena>1;
delete $<izena>1;
}
| TLPAR adierazpena TRPAR
{
$<adi>$ = new expressionstruct;
$<adi>$->izena = $<adi>2->izena;
$<adi>$->trueL = $<adi>2->trueL;
$<adi>$->falseL = $<adi>2->falseL;
delete $<izena>2;
}
| adierazpena RAND M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->trueL, $<erref>3);
$<adi>$->trueL = $<adi>4->trueL;
$<adi>$->falseL = $<adi>1->falseL;
$<adi>$->falseL.insert($<adi>$->falseL.end(), $<adi>4->falseL.begin(), $<adi>4->falseL.end());
delete $<adi>1;
delete $<adi>4;
}
| adierazpena ROR M adierazpena
{
$<adi>$ = new expressionstruct;
kodea.agOsatu($<adi>1->falseL, $<erref>3);
$<adi>$->trueL = $<adi>1->trueL;
$<adi>$->trueL.insert($<adi>$->trueL.end(), $<adi>4->trueL.begin(), $<adi>4->trueL.end());
$<adi>$->falseL = $<adi>4->falseL;
delete $<adi>1;
delete $<adi>4;
}
| RNOT adierazpena
{
$<adi>$ = new expressionstruct;
$<adi>$->trueL = $<adi>2->falseL;
$<adi>$->falseL = $<adi>2->trueL;
delete $<adi>2;
}
;
%%
我假设当您说“如果我在该行上使用圆括号它有效”时,您的意思是以下内容按预期工作:
(c == 1) or (b == 0) and not (a == 0)
那是因为你的优先声明顺序错误。
您有以下内容:
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
%left RAND RNOT ROR
这使得 and
、or
和 not
的绑定比 ==
(以及其他比较运算符)更强。相比之下,将 *
放在 +
之后是正确的,因为乘法确实比加法结合得更紧密。
因为 or
比比较更严格地保留参数,表达式 c == 1 or b == 0 and not a == 0
被分组为 c == (1 or b) == (0 and (not a)) == 0
,这是无意义的。这也是语法错误,因为您已正确声明 ==
是非关联的。
这些运算符应该位于优先级层次结构的开头,而不是末尾,因为它们需要更松散地绑定。此外,您可能应该尊重通常的约定,其中 and
比 or
绑定得更紧密。 (因为像 a > 0 and a < 10 or b > 0 and b < 10
这样的逻辑表达式很常见。)所以我建议将其更改为:
%left ROR
%left RAND
%left RNOT
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
有些语言赋予 not
与其他一元运算符相同的优先级,但显然您希望 not a == 0
表示 not (a == 0)
(即 a ≠ 0
)。在 C++ 中,! a == 0
将被分组为 (!a) == 0
,这也意味着应用整数和布尔值之间的转换后的 a ≠ 0
,但与 0 以外的数字进行比较时具有不同的含义。