Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

Commit d0cafbc3 authored by POTTIER Francois's avatar POTTIER Francois
Browse files

New test grammar, ocaml_lua_parser.

parent b94e6c83
Pipeline #170836 passed with stages
in 26 seconds
Grammar has 31 nonterminal symbols, among which 1 start symbols.
Grammar has 52 terminal symbols.
Grammar has 106 productions.
nullable(varlist) = false
nullable(var) = false
nullable(tableconstructor) = false
nullable(statlist) = true
nullable(stat) = false
nullable(retstat) = false
nullable(prog) = false
nullable(primary) = false
nullable(parlist) = false
nullable(namelist) = false
nullable(label) = false
nullable(key) = false
nullable(ident) = false
nullable(functiondef) = false
nullable(functioncall) = false
nullable(funcname) = false
nullable(funcbody) = false
nullable(fname) = false
nullable(fieldsep) = false
nullable(fields) = false
nullable(fieldlist) = false
nullable(field) = false
nullable(explist) = false
nullable(exp) = false
nullable(elseifps) = false
nullable(elseifp) = false
nullable(chunk) = true
nullable(bracket) = false
nullable(block) = true
nullable(args) = false
nullable(OSC) = true
first(varlist) = LPAR IDENT
first(var) = LPAR IDENT
first(tableconstructor) = LCB
first(statlist) = WHILE SEMI REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR DO DCOLON
first(stat) = WHILE REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR DO DCOLON
first(retstat) = RETURN BREAK
first(prog) = WHILE SEMI RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF DO DCOLON BREAK
first(primary) = STR_CONST NUM_CONST LPAR LCB FUNCTION ELLIPSIS BOOL
first(parlist) = IDENT ELLIPSIS
first(namelist) = IDENT
first(label) = DCOLON
first(key) = LB DOT
first(ident) = IDENT
first(functiondef) = FUNCTION
first(functioncall) = LPAR IDENT
first(funcname) = IDENT
first(funcbody) = LPAR
first(fname) = IDENT
first(fieldsep) = SEMI COMMA
first(fields) = STR_CONST NUM_CONST NOT MINUS LPAR LCB LB IDENT HASH FUNCTION ELLIPSIS BOOL
first(fieldlist) = STR_CONST NUM_CONST NOT MINUS LPAR LCB LB IDENT HASH FUNCTION ELLIPSIS BOOL
first(field) = STR_CONST NUM_CONST NOT MINUS LPAR LCB LB IDENT HASH FUNCTION ELLIPSIS BOOL
first(explist) = STR_CONST NUM_CONST NOT MINUS LPAR LCB IDENT HASH FUNCTION ELLIPSIS BOOL
first(exp) = STR_CONST NUM_CONST NOT MINUS LPAR LCB IDENT HASH FUNCTION ELLIPSIS BOOL
first(elseifps) = ELSEIF
first(elseifp) = ELSEIF
first(chunk) = WHILE SEMI RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR DO DCOLON BREAK
first(bracket) = LPAR
first(block) = WHILE SEMI RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR DO DCOLON BREAK
first(args) = STR_CONST LPAR LCB
first(OSC) = SEMI
minimal(varlist) = (* 1 *) IDENT
minimal(var) = (* 1 *) IDENT
minimal(tableconstructor) = (* 2 *) LCB RCB
minimal(statlist) = (* 0 *)
minimal(stat) = (* 2 *) IDENT STR_CONST
minimal(retstat) = (* 1 *) RETURN
minimal(prog) = (* 1 *) EOF
minimal(primary) = (* 1 *) BOOL
minimal(parlist) = (* 1 *) IDENT
minimal(namelist) = (* 1 *) IDENT
minimal(label) = (* 3 *) DCOLON IDENT DCOLON
minimal(key) = (* 2 *) DOT IDENT
minimal(ident) = (* 1 *) IDENT
minimal(functiondef) = (* 4 *) FUNCTION LPAR RPAR END
minimal(functioncall) = (* 2 *) IDENT STR_CONST
minimal(funcname) = (* 1 *) IDENT
minimal(funcbody) = (* 3 *) LPAR RPAR END
minimal(fname) = (* 1 *) IDENT
minimal(fieldsep) = (* 1 *) COMMA
minimal(fields) = (* 1 *) BOOL
minimal(fieldlist) = (* 1 *) BOOL
minimal(field) = (* 1 *) BOOL
minimal(explist) = (* 1 *) BOOL
minimal(exp) = (* 1 *) BOOL
minimal(elseifps) = (* 3 *) ELSEIF BOOL THEN
minimal(elseifp) = (* 3 *) ELSEIF BOOL THEN
minimal(chunk) = (* 0 *)
minimal(bracket) = (* 3 *) LPAR BOOL RPAR
minimal(block) = (* 0 *)
minimal(args) = (* 1 *) STR_CONST
minimal(OSC) = (* 0 *)
follow(varlist) = COMMA ASSIGN
follow(var) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK ASSIGN AND
follow(tableconstructor) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK AND
follow(statlist) = WHILE UNTIL RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON BREAK
follow(stat) = WHILE UNTIL SEMI RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON BREAK
follow(retstat) = UNTIL SEMI EOF END ELSEIF ELSE
follow(prog) = #
follow(primary) = WHILE UNTIL THEN SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DO DIV DCOLON COMMA CAT CARAT BREAK AND
follow(parlist) = RPAR
follow(namelist) = WHILE UNTIL SEMI RPAR RETURN REPEAT LPAR LOCAL IN IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON COMMA BREAK ASSIGN
follow(label) = WHILE UNTIL SEMI RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON BREAK
follow(key) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK ASSIGN AND
follow(ident) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IN IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK ASSIGN AND
follow(functiondef) = WHILE UNTIL THEN SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DO DIV DCOLON COMMA CAT CARAT BREAK AND
follow(functioncall) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK AND
follow(funcname) = LPAR
follow(funcbody) = WHILE UNTIL THEN SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DO DIV DCOLON COMMA CAT CARAT BREAK AND
follow(fname) = LPAR DOT COLON
follow(fieldsep) = STR_CONST RCB NUM_CONST NOT MINUS LPAR LCB LB IDENT HASH FUNCTION ELLIPSIS BOOL
follow(fields) = SEMI RCB COMMA
follow(fieldlist) = RCB
follow(field) = SEMI RCB COMMA
follow(explist) = WHILE UNTIL SEMI RPAR RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON COMMA BREAK
follow(exp) = WHILE UNTIL THEN SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DO DIV DCOLON COMMA CAT CARAT BREAK AND
follow(elseifps) = END ELSEIF ELSE
follow(elseifp) = END ELSEIF ELSE
follow(chunk) = UNTIL EOF END ELSEIF ELSE
follow(bracket) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK AND
follow(block) = UNTIL END ELSEIF ELSE
follow(args) = WHILE UNTIL THEN STR_CONST SEMI RPAR RETURN REPEAT RCB RB PLUS OR NE MULT MOD MINUS LT LPAR LOCAL LE LCB LB IF IDENT GT GOTO GE FUNCTION FOR EQ EOF END ELSEIF ELSE DOT DO DIV DCOLON COMMA COLON CAT CARAT BREAK AND
follow(OSC) = WHILE UNTIL RETURN REPEAT LPAR LOCAL IF IDENT GOTO FUNCTION FOR EOF END ELSEIF ELSE DO DCOLON BREAK
Built an LR(0) automaton with 213 states.
The grammar is not SLR(1) -- 24 states have a conflict.
The construction mode is pager.
Built an LR(1) automaton with 213 states.
274 shift/reduce conflicts were silently solved.
66 out of 213 states have a default reduction.
86 out of 213 states are represented.
0 out of 86 symbols keep track of their start position.
0 out of 86 symbols keep track of their end position.
56 out of 107 productions exploit shiftreduce optimization.
0 out of 213 states can peek at an error.
570 functions before inlining, 70 functions after inlining.
(* https://raw.githubusercontent.com/drjdn/ocaml_lua_parser/master/src/lib/parser.mly *)
(*
The MIT License
Copyright (c) 2020 Jason D. Nielsen <drjdnielsen@gmail.com>
*)
%{
open Ast
%}
%token <string> NUM_CONST STR_CONST BOOL IDENT
%token PLUS MINUS MULT DIV MOD CARAT GT LT GE LE EQ NE ASSIGN DOT CAT
%token ELLIPSIS COLON DCOLON SEMI COMMA HASH LCB RCB LPAR RPAR LB RB AND
%token BREAK DO ELSE ELSEIF END FOR FUNCTION IF IN LOCAL NOT OR REPEAT
%token RETURN THEN UNTIL WHILE GOTO EOF NOARG
%nonassoc NOARG
%nonassoc LPAR
%left OR
%left AND
%left LT GT LE GE NE EQ
%right CAT
%left PLUS MINUS
%left MULT DIV MOD
%left NOT HASH
%right CARAT
%start <Ast.ast> prog
%%
prog:
| chunk EOF { $1 }
;
chunk:
| statlist retstat OSC { Slist((extract_list $1) @ [$2]) }
| statlist { $1 }
;
statlist:
| OSC { Slist([]) }
| statlist stat OSC { Slist((extract_list $1) @ [$2]) }
;
block:
| chunk { $1 }
;
stat:
| varlist ASSIGN explist { Assign($1, $3) }
| functioncall %prec NOARG { $1 }
| label { $1 }
| GOTO ident { Goto($2) }
| DO block END { Do($2) }
| WHILE exp DO block END { While($2, $4) }
| REPEAT block UNTIL exp { Repeat($2, $4) }
| IF exp THEN block END { If1($2, $4) }
| IF exp THEN block ELSE block END { If2($2, $4, $6) }
| IF exp THEN block elseifps END { If3($2, $4, $5) }
| IF exp THEN block elseifps ELSE block END { If4($2, $4, $5, $7) }
| FOR ident ASSIGN exp COMMA exp DO block END { For1($2, $4, $6, $8) }
| FOR ident ASSIGN exp COMMA exp COMMA exp DO block END { For2($2, $4, $6, $8, $10) }
| FOR namelist IN explist DO block END { Forin($2, $4, $6) }
| FUNCTION funcname funcbody { Function($2, $3) }
| LOCAL FUNCTION ident funcbody { Lfunction($3, $4) }
| LOCAL namelist { Lnames($2) }
| LOCAL namelist ASSIGN explist { Lassign($2, $4) }
;
elseifp:
| ELSEIF exp THEN block { Elseif($2, $4) }
;
elseifps:
| elseifp { Slist([$1]) }
| elseifps elseifp { Slist((extract_list $1) @ [$2]) }
;
retstat:
| RETURN { Return(Elist([])) }
| RETURN explist { Return($2) }
| BREAK { Break }
;
label:
| DCOLON ident DCOLON { Label($2) }
;
funcname:
| fname { $1 }
| fname COLON ident { Member($1, $3) }
;
varlist:
| var { Elist([$1]) }
| varlist COMMA var { Elist((extract_list $1) @ [$3]) }
;
var:
| ident { $1 }
| bracket key { Clist([$1; $2]) }
| functioncall key { Clist([$1; $2]) }
| var key { Clist([$1; $2]) }
;
key:
| LB exp RB { Key1($2) }
| DOT ident { Key2($2) }
;
fname:
| ident { FNlist([$1]) }
| fname DOT ident { FNlist((extract_list $1) @ [$3]) }
;
namelist:
| ident { Elist([$1]) }
| namelist COMMA ident { Elist((extract_list $1) @ [$3]) }
;
explist:
| exp { Elist([$1]) }
| explist COMMA exp { Elist((extract_list $1) @ [$3]) }
;
exp:
| primary { $1 }
| var %prec NOARG { $1 }
| functioncall %prec NOARG { $1 }
| exp OR exp { Binop("or", $1, $3) }
| exp AND exp { Binop("and", $1, $3) }
| exp LT exp { Binop("<", $1, $3) }
| exp GT exp { Binop(">", $1, $3) }
| exp LE exp { Binop("<=", $1, $3) }
| exp GE exp { Binop(">=", $1, $3) }
| exp NE exp { Binop("~=", $1, $3) }
| exp EQ exp { Binop("==", $1, $3) }
| exp CAT exp { Binop("..", $1, $3) }
| exp PLUS exp { Binop("+", $1, $3) }
| exp MINUS exp { Binop("-", $1, $3) }
| exp MULT exp { Binop("*", $1, $3) }
| exp DIV exp { Binop("/", $1, $3) }
| exp MOD exp { Binop("%", $1, $3) }
| exp CARAT exp { Binop("^", $1, $3) }
| NOT exp { Unop("not ", $2) }
| HASH exp { Unop("#", $2) }
| MINUS exp %prec NOT { Unop("- ", $2) }
;
primary:
| BOOL { Bool($1) }
| NUM_CONST { Number($1) }
| STR_CONST { String($1) }
| ELLIPSIS { Ellipsis }
| functiondef { $1 }
| tableconstructor { $1 }
| bracket %prec NOARG { $1 }
;
bracket:
| LPAR exp RPAR { Pexp($2) }
;
functioncall:
| bracket args { Clist([$1; $2]) }
| bracket COLON ident args { Mcall($1, $3, $4) }
| var args { Clist([$1; $2]) }
| var COLON ident args { Mcall($1, $3, $4) }
| functioncall args { Clist((extract_list $1) @ [$2]) }
| functioncall COLON ident args { Mcall($1, $3, $4) }
;
args:
| LPAR RPAR { Args(Elist([])) }
| LPAR explist RPAR { Args($2) }
| tableconstructor { $1 }
| STR_CONST { String($1) }
;
functiondef:
| FUNCTION funcbody { FunctionE($2) }
;
funcbody:
| LPAR RPAR block END { Fbody(Elist([]), $3) }
| LPAR parlist RPAR block END { Fbody($2, $4) }
;
parlist:
| namelist { $1 }
| namelist COMMA ELLIPSIS { Vargs($1) }
| ELLIPSIS { Ellipsis }
;
tableconstructor:
| LCB RCB { Table(Elist([])) }
| LCB fieldlist RCB { Table($2) }
;
fieldlist:
| fields { $1 }
| fields fieldsep { $1 }
;
fields:
| field { Elist([$1]) }
| fields fieldsep field { Elist((extract_list $1) @ [$3]) }
;
field:
| LB exp RB ASSIGN exp { Fassign($2, $5) }
| ident ASSIGN exp { Assign($1, $3) }
| exp { $1 }
;
fieldsep:
| COMMA {}
| SEMI {}
;
ident:
| IDENT { Ident($1) }
;
OSC :
| {}
| SEMI {}
;
%{
open Ast
%}
%start prog
%token AND
%token ASSIGN
%token <string> BOOL
%token BREAK
%token CARAT
%token CAT
%token COLON
%token COMMA
%token DCOLON
%token DIV
%token DO
%token DOT
%token ELLIPSIS
%token ELSE
%token ELSEIF
%token END
%token EOF
%token EQ
%token FOR
%token FUNCTION
%token GE
%token GOTO
%token GT
%token HASH
%token <string> IDENT
%token IF
%token IN
%token LB
%token LCB
%token LE
%token LOCAL
%token LPAR
%token LT
%token MINUS
%token MOD
%token MULT
%token NE
%token NOARG
%token NOT
%token <string> NUM_CONST
%token OR
%token PLUS
%token RB
%token RCB
%token REPEAT
%token RETURN
%token RPAR
%token SEMI
%token <string> STR_CONST
%token THEN
%token UNTIL
%token WHILE
%nonassoc NOARG
%nonassoc LPAR
%left OR
%left AND
%left EQ GE GT LE LT NE
%right CAT
%left MINUS PLUS
%left DIV MOD MULT
%left HASH NOT
%right CARAT
%type <Ast.ast> prog
%%
prog:
_1 = chunk _2 = EOF
{ ( _1 )}
chunk:
_1 = statlist _2 = retstat _3 = OSC
{ ( Slist((extract_list _1) @ [_2]) )}
| _1 = statlist
{ ( _1 )}
statlist:
_1 = OSC
{ ( Slist([]) )}
| _1 = statlist _2 = stat _3 = OSC
{ ( Slist((extract_list _1) @ [_2]) )}
block:
_1 = chunk
{ ( _1 )}
stat:
_1 = varlist _2 = ASSIGN _3 = explist
{ ( Assign(_1, _3) )}
| _1 = functioncall %prec NOARG
{ ( _1 )}
| _1 = label
{ ( _1 )}
| _1 = GOTO _2 = ident
{ ( Goto(_2) )}
| _1 = DO _2 = block _3 = END
{ ( Do(_2) )}
| _1 = WHILE _2 = exp _3 = DO _4 = block _5 = END
{ ( While(_2, _4) )}
| _1 = REPEAT _2 = block _3 = UNTIL _4 = exp
{ ( Repeat(_2, _4) )}
| _1 = IF _2 = exp _3 = THEN _4 = block _5 = END
{ ( If1(_2, _4) )}
| _1 = IF _2 = exp _3 = THEN _4 = block _5 = ELSE _6 = block _7 = END
{ ( If2(_2, _4, _6) )}
| _1 = IF _2 = exp _3 = THEN _4 = block _5 = elseifps _6 = END
{ ( If3(_2, _4, _5) )}
| _1 = IF _2 = exp _3 = THEN _4 = block _5 = elseifps _6 = ELSE _7 = block _8 = END
{ ( If4(_2, _4, _5, _7) )}
| _1 = FOR _2 = ident _3 = ASSIGN _4 = exp _5 = COMMA _6 = exp _7 = DO _8 = block _9 = END
{ ( For1(_2, _4, _6, _8) )}
| _1 = FOR _2 = ident _3 = ASSIGN _4 = exp _5 = COMMA _6 = exp _7 = COMMA _8 = exp _9 = DO _10 = block _11 = END
{ ( For2(_2, _4, _6, _8, _10) )}
| _1 = FOR _2 = namelist _3 = IN _4 = explist _5 = DO _6 = block _7 = END
{ ( Forin(_2, _4, _6) )}
| _1 = FUNCTION _2 = funcname _3 = funcbody
{ ( Function(_2, _3) )}
| _1 = LOCAL _2 = FUNCTION _3 = ident _4 = funcbody
{ ( Lfunction(_3, _4) )}
| _1 = LOCAL _2 = namelist
{ ( Lnames(_2) )}
| _1 = LOCAL _2 = namelist _3 = ASSIGN _4 = explist
{ ( Lassign(_2, _4) )}
elseifp:
_1 = ELSEIF _2 = exp _3 = THEN _4 = block
{ ( Elseif(_2, _4) )}
elseifps:
_1 = elseifp
{ ( Slist([_1]) )}
| _1 = elseifps _2 = elseifp
{ ( Slist((extract_list _1) @ [_2]) )}
retstat:
_1 = RETURN
{ ( Return(Elist([])) )}
| _1 = RETURN _2 = explist
{ ( Return(_2) )}
| _1 = BREAK
{ ( Break )}
label:
_1 = DCOLON _2 = ident _3 = DCOLON
{ ( Label(_2) )}
funcname:
_1 = fname
{ ( _1 )}
| _1 = fname _2 = COLON _3 = ident
{ ( Member(_1, _3) )}
varlist:
_1 = var
{ ( Elist([_1]) )}
| _1 = varlist _2 = COMMA _3 = var
{ ( Elist((extract_list _1) @ [_3]) )}
var:
_1 = ident
{ ( _1 )}
| _1 = bracket _2 = key
{ ( Clist([_1; _2]) )}
| _1 = functioncall _2 = key
{ ( Clist([_1; _2]) )}
| _1 = var _2 = key
{ ( Clist([_1; _2]) )}
key:
_1 = LB _2 = exp _3 = RB
{ ( Key1(_2) )}
| _1 = DOT _2 = ident
{ ( Key2(_2) )}
fname:
_1 = ident
{ ( FNlist([_1]) )}
| _1 = fname _2 = DOT _3 = ident
{ ( FNlist((extract_list _1) @ [_3]) )}
namelist:
_1 = ident
{ ( Elist([_1]) )}
| _1 = namelist _2 = COMMA _3 = ident
{ ( Elist((extract_list _1) @ [_3]) )}
explist:
_1 = exp
{ ( Elist([_1]) )}
| _1 = explist _2 = COMMA _3 = exp
{ ( Elist((extract_list _1) @ [_3]) )}
exp:
_1 = primary
{ ( _1 )}
| _1 = var %prec NOARG
{ ( _1 )}
| _1 = functioncall %prec NOARG
{ ( _1 )}
| _1 = exp _2 = OR _3 = exp
{ ( Binop("or", _1, _3) )}
| _1 = exp _2 = AND _3 = exp
{ ( Binop("and", _1, _3) )}
| _1 = exp _2 = LT _3 = exp
{ ( Binop("<", _1, _3) )}
| _1 = exp _2 = GT _3 = exp
{ ( Binop(">", _1, _3) )}
| _1 = exp _2 = LE _3 = exp
{ ( Binop("<=", _1, _3) )}
| _1 = exp _2 = GE _3 = exp
{ ( Binop(">=", _1, _3) )}
| _1 = exp _2 = NE _3 = exp
{ ( Binop("~=", _1, _3) )}
| _1 = exp _2 = EQ _3 = exp
{ ( Binop("==", _1, _3) )}
| _1 = exp _2 = CAT _3 = exp
{ ( Binop("..", _1, _3) )}
| _1 = exp _2 = PLUS _3 = exp
{ ( Binop("+", _1, _3) )}
| _1 = exp _2 = MINUS _3 = exp
{ ( Binop("-", _1, _3) )}
| _1 = exp _2 = MULT _3 = exp
{ ( Binop("*", _1, _3) )}
| _1 = exp _2 = DIV _3 = exp
{ ( Binop("/", _1, _3) )}
| _1 = exp _2 = MOD _3 = exp
{ ( Binop("%", _1, _3) )}
| _1 = exp _2 = CARAT _3 = exp
{ ( Binop("^", _1, _3) )}
| _1 = NOT _2 = exp
{ ( Unop("not ", _2) )}
| _1 = HASH _2 = exp
{ ( Unop("#", _2) )}
| _1 = MINUS _2 = exp %prec NOT
{ ( Unop("- ", _2) )}
primary:
_1 = BOOL
{ ( Bool(_1) )}
| _1 = NUM_CONST