When I try to execute a logical order with parentheses it works, but without them it returns line 11: syntax error at '=='
That 11 line is
if c == 1 or b == 0 and not a == 0{
I have defined and, or, not as tokens. If I use parentheses on that line it works, but it has to work also without them. This is my parser.y code for those
| 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;
}
I also have set priorities as %left RAND RNOT ROR
I can´t find any solution for this, any help would be appreciated.
In case you need it, this is the whole parser.y code
%{
#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;
}
;
%%
I assume that when you say "If I use parentheses on that line it works", you mean that the following works as expected:
(c == 1) or (b == 0) and not (a == 0)
That's because your precedence declarations are in the wrong order.
You have the following:
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
%left RAND RNOT ROR
That makes and
, or
and not
bind more strongly than ==
(and the other comparison operators). By contrast, putting *
after +
is correct because multiplication does bind more strongly than addition.
Because or
holds onto arguments more tightly than comparisons, the expression c == 1 or b == 0 and not a == 0
is grouped as c == (1 or b) == (0 and (not a)) == 0
, which is nonsensical. It's also a syntax error, because you have correctly declared ==
to be non-associative.
Those operators should come at the beginning of the precedence hierarchy, not the end, because they need to bind more loosely. Also, you should probably respect usual conventions, in which and
binds more tightly than or
. (Because it's common to write logical expressions like a > 0 and a < 10 or b > 0 and b < 10
.) So I'd suggest changing it to:
%left ROR
%left RAND
%left RNOT
%nonassoc TCEQ TCGT TCLT TCGE TLEOUT TCNE
%left TSUM TSUB
%left TMUL TDIV
Some languages give not
the same precedence as other unary operators, but it's clear that you want not a == 0
to mean not (a == 0)
(that is, a ≠ 0
). In C++, ! a == 0
would be grouped as (!a) == 0
, which also means a ≠ 0
after the conversions between integer and boolean are applied, but which will have different meaning for comparisons against numbers other than 0.