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

这使得 andornot 的绑定比 ==(以及其他比较运算符)更强。相比之下,将 * 放在 + 之后是正确的,因为乘法确实比加法结合得更紧密。

因为 or 比比较更严格地保留参数,表达式 c == 1 or b == 0 and not a == 0 被分组为 c == (1 or b) == (0 and (not a)) == 0,这是无意义的。这也是语法错误,因为您已正确声明 == 是非关联的。

这些运算符应该位于优先级层次结构的开头,而不是末尾,因为它们需要更松散地绑定。此外,您可能应该尊重通常的约定,其中 andor 绑定得更紧密。 (因为像 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 以外的数字进行比较时具有不同的含义。