%{
/*****
* camp.y
* Andy Hammerlindl 08/12/2002
*
* The grammar of the camp language.
*****/
#include "errormsg.h"
#include "exp.h"
#include "newexp.h"
#include "dec.h"
#include "fundec.h"
#include "stm.h"
#include "modifier.h"
#include "opsymbols.h"
// Avoid error messages with unpatched bison-1.875:
#ifndef __attribute__
#define __attribute__(x)
#endif
// Used when a position needs to be determined and no token is
// available. Defined in camp.l.
position lexerPos();
bool lexerEOF();
int yylex(void); /* function prototype */
void yyerror(const char *s)
{
if (!lexerEOF()) {
em.error(lexerPos());
em << s;
em.cont();
}
}
// Check if the symbol given is "keyword". Returns true in this case and
// returns false and reports an error otherwise.
bool checkKeyword(position pos, symbol sym)
{
if (sym != symbol::trans("keyword")) {
em.error(pos);
em << "expected 'keyword' here";
return false;
}
return true;
}
namespace absyntax { file *root; }
using namespace absyntax;
using sym::symbol;
using mem::string;
%}
%union {
position pos;
bool boo;
struct {
position pos;
sym::symbol sym;
} ps;
absyntax::name *n;
absyntax::varinit *vi;
absyntax::arrayinit *ai;
absyntax::exp *e;
absyntax::stringExp *stre;
absyntax::specExp *se;
absyntax::joinExp *j;
absyntax::explist *elist;
absyntax::argument arg;
absyntax::arglist *alist;
absyntax::slice *slice;
absyntax::dimensions *dim;
absyntax::astType *t;
absyntax::decid *di;
absyntax::decidlist *dil;
absyntax::decidstart *dis;
absyntax::runnable *run;
struct {
position pos;
trans::permission val;
} perm;
struct {
position pos;
trans::modifier val;
} mod;
absyntax::modifierList *ml;
//absyntax::program *prog;
absyntax::vardec *vd;
//absyntax::vardecs *vds;
absyntax::dec *d;
absyntax::idpair *ip;
absyntax::idpairlist *ipl;
absyntax::stm *s;
absyntax::block *b;
absyntax::stmExpList *sel;
//absyntax::funheader *fh;
absyntax::formal *fl;
absyntax::formals *fls;
absyntax::typeParam *tp;
absyntax::typeParamList *tps;
}
%token <ps> ID SELFOP
DOTS COLONS DASHES INCR LONGDASH
CONTROLS TENSION ATLEAST CURL
COR CAND BAR AMPERSAND EQ NEQ LT LE GT GE CARETS
'+' '-' '*' '/' '%' '#' '^' OPERATOR
%token <pos> LOOSE ASSIGN '?' ':'
DIRTAG JOIN_PREC AND
'{' '}' '(' ')' '.' ',' '[' ']' ';' ELLIPSIS
ACCESS UNRAVEL IMPORT INCLUDE FROM QUOTE STRUCT TYPEDEF USING NEW
IF ELSE WHILE DO FOR BREAK CONTINUE RETURN_
THIS_TOK EXPLICIT
GARBAGE
%token <e> LIT
%token <stre> STRING
%token <perm> PERM
%token <mod> MODIFIER
%right ASSIGN SELFOP
%right '?' ':'
%left COR
%left CAND
%left BAR
%left AMPERSAND
%left EQ NEQ
%left LT LE GT GE
%left OPERATOR
%left CARETS
%left JOIN_PREC DOTS COLONS DASHES INCR LONGDASH
%left DIRTAG CONTROLS TENSION ATLEAST AND
%left CURL '{' '}'
%left '+' '-'
%left '*' '/' '%' '#' LIT
%left UNARY
%right '^'
%left EXP_IN_PARENS_RULE
%left '(' ')'
%type <b> fileblock bareblock block
%type <n> name
%type <run> runnable
%type <ml> modifiers
%type <d> dec fundec typedec
%type <ps> strid
%type <ip> idpair stridpair
%type <ipl> idpairlist stridpairlist
%type <vd> vardec barevardec
%type <t> type celltype
%type <dim> dims
%type <dil> decidlist
%type <di> decid
%type <dis> decidstart
%type <vi> varinit
%type <ai> arrayinit basearrayinit varinits
%type <fl> formal decdec
%type <fls> formals decdeclist
%type <e> value exp fortest
%type <arg> argument
%type <slice> slice
%type <j> join basicjoin
%type <e> tension controls
%type <se> dir
%type <elist> dimexps
%type <alist> arglist tuple
%type <s> stm stmexp blockstm
%type <run> forinit
%type <sel> forupdate stmexplist
%type <boo> explicitornot
%type <tp> typeparam
%type <tps> typeparamlist
/* There are four shift/reduce conflicts:
* the dangling ELSE in IF (exp) IF (exp) stm ELSE stm
* new ID
* the argument id=exp is taken as an argument instead of an assignExp
* explicit cast
*/
%expect 4
/* Enable grammar debugging. */
/*%debug*/
%%
file:
fileblock { absyntax::root = $1; }
;
fileblock:
/* empty */ { $$ = new file(lexerPos(), false); }
| fileblock runnable
{ $$ = $1; $$->add($2); }
;
bareblock:
/* empty */ { $$ = new block(lexerPos(), true); }
| bareblock runnable
{ $$ = $1; $$->add($2); }
;
name:
ID { $$ = new simpleName($1.pos, $1.sym); }
| name '.' ID { $$ = new qualifiedName($2, $1, $3.sym); }
| '%' { $$ = new simpleName($1.pos,
symbol::trans("operator answer")); }
;
runnable:
dec { $$ = $1; }
| stm { $$ = $1; }
| modifiers dec
{ $$ = new modifiedRunnable($1->getPos(), $1, $2); }
| modifiers stm
{ $$ = new modifiedRunnable($1->getPos(), $1, $2); }
;
modifiers:
MODIFIER { $$ = new modifierList($1.pos); $$->add($1.val); }
| PERM { $$ = new modifierList($1.pos); $$->add($1.val); }
| modifiers MODIFIER
{ $$ = $1; $$->add($2.val); }
| modifiers PERM
{ $$ = $1; $$->add($2.val); }
;
dec:
vardec { $$ = $1; }
| fundec { $$ = $1; }
| typedec { $$ = $1; }
| ACCESS stridpairlist ';'
{ $$ = new accessdec($1, $2); }
| FROM name UNRAVEL idpairlist ';'
{ $$ = new unraveldec($1, $2, $4); }
| FROM name UNRAVEL '*' ';'
{ $$ = new unraveldec($1, $2, WILDCARD); }
| UNRAVEL name ';' { $$ = new unraveldec($1, $2, WILDCARD); }
| FROM strid ACCESS idpairlist ';'
{ $$ = new fromaccessdec($1, $2.sym, $4); }
| FROM strid ACCESS '*' ';'
{ $$ = new fromaccessdec($1, $2.sym, WILDCARD); }
| IMPORT stridpair ';'
{ $$ = new importdec($1, $2); }
| INCLUDE ID ';' { $$ = new includedec($1, $2.sym); }
| INCLUDE STRING ';'
{ $$ = new includedec($1, $2->getString()); }
// Experimental - templated imports.
| TYPEDEF IMPORT '(' typeparamlist ')' ';'
{ $$ = new receiveTypedefDec($1, $4); }
| IMPORT TYPEDEF '(' typeparamlist ')' ';'
{ $$ = new badDec($1, $1,
"Expected 'typedef import(<types>);'");
}
/* ACCESS strid '(' decdeclist ')' 'as' ID */
| ACCESS strid '(' decdeclist ')' ID ID ';'
{ $$ = new templateAccessDec(
$1, $2.sym, $4, $6.sym, $7.sym, $6.pos
); }
| ACCESS strid '(' decdeclist ')' ';'
{ $$ = new badDec($1, $6, "expected 'as'"); }
| IMPORT strid '(' decdeclist ')' ';'
{ $$ = new badDec($1, $1,
"Parametrized imports disallowed to reduce naming "
"conflicts. Try "
"'access <module>(<type parameters>) as <newname>;'."
); }
| FROM strid '(' decdeclist ')' ACCESS idpairlist ';'
{ $$ = new fromaccessdec($1, $2.sym, $7, $4); }
;
// List mapping dec to dec as in "Key=string, Value=int"
decdec:
ID ASSIGN type
{ $$ = new formal(
$1.pos, $3, new decidstart($1.pos, $1.sym)
); }
| type { $$ = new formal($1->getPos(), $1, nullptr); } // ultimately log error
;
decdeclist:
decdec
{ $$ = new formals($1->getPos()); $$->add($1); }
| decdeclist ',' decdec
{ $$ = $1; $$->add($3); }
;
typeparam:
ID { $$ = new typeParam($1.pos, $1.sym); }
;
typeparamlist:
typeparam
{ $$ = new typeParamList($1->getPos()); $$->add($1); }
| typeparamlist ',' typeparam
{ $$ = $1; $$->add($3); }
;
idpair:
ID { $$ = new idpair($1.pos, $1.sym); }
/* ID 'as' ID */
| ID ID ID { $$ = new idpair($1.pos, $1.sym, $2.sym , $3.sym); }
;
idpairlist:
idpair { $$ = new idpairlist(); $$->add($1); }
| idpairlist ',' idpair
{ $$ = $1; $$->add($3); }
;
strid:
ID { $$ = $1; }
| STRING { $$.pos = $1->getPos();
$$.sym = symbol::literalTrans($1->getString()); }
;
stridpair:
ID { $$ = new idpair($1.pos, $1.sym); }
/* strid 'as' ID */
| strid ID ID { $$ = new idpair($1.pos, $1.sym, $2.sym , $3.sym); }
;
stridpairlist:
stridpair { $$ = new idpairlist(); $$->add($1); }
| stridpairlist ',' stridpair
{ $$ = $1; $$->add($3); }
;
vardec:
barevardec ';' { $$ = $1; }
;
barevardec:
type decidlist { $$ = new vardec($1->getPos(), $1, $2); }
;
type:
celltype { $$ = $1; }
| name dims { $$ = new arrayTy($1, $2); }
;
celltype:
name { $$ = new nameTy($1); }
;
dims:
'[' ']' { $$ = new dimensions($1); }
| dims '[' ']' { $$ = $1; $$->increase(); }
;
dimexps:
'[' exp ']' { $$ = new explist($1); $$->add($2); }
| dimexps '[' exp ']'
{ $$ = $1; $$->add($3); }
;
decidlist:
decid { $$ = new decidlist($1->getPos()); $$->add($1); }
| decidlist ',' decid
{ $$ = $1; $$->add($3); }
;
decid:
decidstart { $$ = new decid($1->getPos(), $1); }
| decidstart ASSIGN varinit
{ $$ = new decid($1->getPos(), $1, $3); }
;
decidstart:
ID { $$ = new decidstart($1.pos, $1.sym); }
| ID dims { $$ = new decidstart($1.pos, $1.sym, $2); }
| ID '(' ')' { $$ = new fundecidstart($1.pos, $1.sym, 0,
new formals($2)); }
| ID '(' formals ')'
{ $$ = new fundecidstart($1.pos, $1.sym, 0, $3); }
;
varinit:
exp { $$ = $1; }
| arrayinit { $$ = $1; }
;
block:
'{' bareblock '}'
{ $$ = $2; }
;
arrayinit:
'{' '}' { $$ = new arrayinit($1); }
| '{' ELLIPSIS varinit '}'
{ $$ = new arrayinit($1); $$->addRest($3); }
| '{' basearrayinit '}'
{ $$ = $2; }
| '{' basearrayinit ELLIPSIS varinit '}'
{ $$ = $2; $$->addRest($4); }
;
basearrayinit:
',' { $$ = new arrayinit($1); }
| varinits { $$ = $1; }
| varinits ',' { $$ = $1; }
;
varinits:
varinit { $$ = new arrayinit($1->getPos());
$$->add($1);}
| varinits ',' varinit
{ $$ = $1; $$->add($3); }
;
formals:
formal { $$ = new formals($1->getPos()); $$->add($1); }
| ELLIPSIS formal { $$ = new formals($1); $$->addRest($2); }
| formals ',' formal
{ $$ = $1; $$->add($3); }
| formals ELLIPSIS formal
{ $$ = $1; $$->addRest($3); }
;
explicitornot:
EXPLICIT { $$ = true; }
| { $$ = false; }
;
formal:
explicitornot type
{ $$ = new formal($2->getPos(), $2, 0, 0, $1, 0); }
| explicitornot type decidstart
{ $$ = new formal($2->getPos(), $2, $3, 0, $1, 0); }
| explicitornot type decidstart ASSIGN varinit
{ $$ = new formal($2->getPos(), $2, $3, $5, $1, 0); }
/* The uses of ID below are 'keyword' qualifiers before the parameter name. */
| explicitornot type ID decidstart
{ bool k = checkKeyword($3.pos, $3.sym);
$$ = new formal($2->getPos(), $2, $4, 0, $1, k); }
| explicitornot type ID decidstart ASSIGN varinit
{ bool k = checkKeyword($3.pos, $3.sym);
$$ = new formal($2->getPos(), $2, $4, $6, $1, k); }
;
fundec:
type ID '(' ')' blockstm
{ $$ = new fundec($3, $1, $2.sym, new formals($3), $5); }
| type ID '(' formals ')' blockstm
{ $$ = new fundec($3, $1, $2.sym, $4, $6); }
;
typedec:
STRUCT ID block { $$ = new recorddec($1, $2.sym, $3); }
| TYPEDEF vardec { $$ = new typedec($1, $2); }
// See definition for decidstart. Following C++, "The syntax of the type-id
// that names type T is exactly the syntax of a declaration of a variable or
// function of type T, with the identifier omitted."
//
http://en.cppreference.com/w/cpp/language/type#Type_naming
| USING ID ASSIGN type ';'
{ decidstart *dis = new decidstart($2.pos, $2.sym);
$$ = new typedec($1, dis, $4); }
| USING ID ASSIGN type '(' ')' ';'
{ decidstart *dis = new fundecidstart($2.pos, $2.sym,
0, new formals($5));
$$ = new typedec($1, dis, $4); }
| USING ID ASSIGN type '(' formals ')' ';'
{ decidstart *dis = new fundecidstart($2.pos, $2.sym, 0, $6);
$$ = new typedec($1, dis, $4); }
;
slice:
':' { $$ = new slice($1, 0, 0); }
| exp ':' { $$ = new slice($2, $1, 0); }
| ':' exp { $$ = new slice($1, 0, $2); }
| exp ':' exp { $$ = new slice($2, $1, $3); }
;
value:
value '.' ID { $$ = new fieldExp($2, $1, $3.sym); }
| name '[' exp ']' { $$ = new subscriptExp($2,
new nameExp($1->getPos(), $1), $3); }
| value '[' exp ']'{ $$ = new subscriptExp($2, $1, $3); }
| name '[' slice ']' { $$ = new sliceExp($2,
new nameExp($1->getPos(), $1), $3); }
| value '[' slice ']'{ $$ = new sliceExp($2, $1, $3); }
| name '(' ')' { $$ = new callExp($2,
new nameExp($1->getPos(), $1),
new arglist()); }
| name '(' arglist ')'
{ $$ = new callExp($2,
new nameExp($1->getPos(), $1),
$3); }
| value '(' ')' { $$ = new callExp($2, $1, new arglist()); }
| value '(' arglist ')'
{ $$ = new callExp($2, $1, $3); }
| '(' exp ')' %prec EXP_IN_PARENS_RULE
{ $$ = $2; }
| '(' name ')' %prec EXP_IN_PARENS_RULE
{ $$ = new nameExp($2->getPos(), $2); }
| THIS_TOK { $$ = new thisExp($1); }
;
argument:
exp { $$.name = symbol::nullsym; $$.val=$1; }
| ID ASSIGN exp { $$.name = $1.sym; $$.val=$3; }
;
arglist:
argument { $$ = new arglist(); $$->add($1); }
| ELLIPSIS argument
{ $$ = new arglist(); $$->addRest($2); }
| arglist ',' argument
{ $$ = $1; $$->add($3); }
| arglist ELLIPSIS argument
{ $$ = $1; $$->addRest($3); }
;
/* A list of two or more expressions, separated by commas. */
tuple:
exp ',' exp { $$ = new arglist(); $$->add($1); $$->add($3); }
| tuple ',' exp { $$ = $1; $$->add($3); }
;
exp:
name { $$ = new nameExp($1->getPos(), $1); }
| value { $$ = $1; }
| LIT { $$ = $1; }
| STRING { $$ = $1; }
/* This is for scaling expressions such as 105cm */
| LIT exp { $$ = new scaleExp($1->getPos(), $1, $2); }
| '(' name ')' exp
{ $$ = new castExp($2->getPos(), new nameTy($2), $4); }
| '(' name dims ')' exp
{ $$ = new castExp($2->getPos(), new arrayTy($2, $3), $5); }
| '+' exp %prec UNARY
{ $$ = new unaryExp($1.pos, $2, $1.sym); }
| '-' exp %prec UNARY
{ $$ = new unaryExp($1.pos, $2, $1.sym); }
| OPERATOR exp { $$ = new unaryExp($1.pos, $2, $1.sym); }
| exp '+' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '-' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '*' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '/' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '%' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '#' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp '^' exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp LT exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp LE exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp GT exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp GE exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp EQ exp { $$ = new equalityExp($2.pos, $1, $2.sym, $3); }
| exp NEQ exp { $$ = new equalityExp($2.pos, $1, $2.sym, $3); }
| exp CAND exp { $$ = new andExp($2.pos, $1, $2.sym, $3); }
| exp COR exp { $$ = new orExp($2.pos, $1, $2.sym, $3); }
| exp CARETS exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp AMPERSAND exp{ $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp BAR exp{ $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp OPERATOR exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| exp INCR exp { $$ = new binaryExp($2.pos, $1, $2.sym, $3); }
| NEW celltype
{ $$ = new newRecordExp($1, $2); }
| NEW celltype dimexps
{ $$ = new newArrayExp($1, $2, $3, 0, 0); }
| NEW celltype dimexps dims
{ $$ = new newArrayExp($1, $2, $3, $4, 0); }
| NEW celltype dims
{ $$ = new newArrayExp($1, $2, 0, $3, 0); }
| NEW celltype dims arrayinit
{ $$ = new newArrayExp($1, $2, 0, $3, $4); }
| NEW celltype '(' ')' blockstm
{ $$ = new newFunctionExp($1, $2, new formals($3), $5); }
| NEW celltype dims '(' ')' blockstm
{ $$ = new newFunctionExp($1,
new arrayTy($2->getPos(), $2, $3),
new formals($4),
$6); }
| NEW celltype '(' formals ')' blockstm
{ $$ = new newFunctionExp($1, $2, $4, $6); }
| NEW celltype dims '(' formals ')' blockstm
{ $$ = new newFunctionExp($1,
new arrayTy($2->getPos(), $2, $3),
$5,
$7); }
| exp '?' exp ':' exp
{ $$ = new conditionalExp($2, $1, $3, $5); }
| exp ASSIGN exp { $$ = new assignExp($2, $1, $3); }
| '(' tuple ')' { $$ = new callExp($1, new nameExp($1, SYM_TUPLE), $2); }
| exp join exp %prec JOIN_PREC
{ $2->pushFront($1); $2->pushBack($3); $$ = $2; }
| exp dir %prec DIRTAG
{ $2->setSide(camp::OUT);
joinExp *jexp =
new joinExp($2->getPos(), SYM_DOTS);
$$=jexp;
jexp->pushBack($1); jexp->pushBack($2); }
| INCR exp %prec UNARY
{ $$ = new prefixExp($1.pos, $2, SYM_PLUS); }
| DASHES exp %prec UNARY
{ $$ = new prefixExp($1.pos, $2, SYM_MINUS); }
/* Illegal - will be caught during translation. */
| exp INCR %prec UNARY
{ $$ = new postfixExp($2.pos, $1, SYM_PLUS); }
| exp SELFOP exp { $$ = new selfExp($2.pos, $1, $2.sym, $3); }
| QUOTE '{' fileblock '}'
{ $$ = new quoteExp($1, $3); }
;
// This verbose definition is because leaving empty as an expansion for dir
// made a whack of reduce/reduce errors.
join:
DASHES { $$ = new joinExp($1.pos,$1.sym); }
| basicjoin %prec JOIN_PREC
{ $$ = $1; }
| dir basicjoin %prec JOIN_PREC
{ $1->setSide(camp::OUT);
$$ = $2; $$->pushFront($1); }
| basicjoin dir %prec JOIN_PREC
{ $2->setSide(camp::IN);
$$ = $1; $$->pushBack($2); }
| dir basicjoin dir %prec JOIN_PREC
{ $1->setSide(camp::OUT); $3->setSide(camp::IN);
$$ = $2; $$->pushFront($1); $$->pushBack($3); }
;
dir:
'{' CURL exp '}' { $$ = new specExp($2.pos, $2.sym, $3); }
| '{' exp '}' { $$ = new specExp($1, symbol::opTrans("spec"), $2); }
| '{' exp ',' exp '}'
{ $$ = new specExp($1, symbol::opTrans("spec"),
new pairExp($3, $2, $4)); }
| '{' exp ',' exp ',' exp '}'
{ $$ = new specExp($1, symbol::opTrans("spec"),
new tripleExp($3, $2, $4, $6)); }
;
basicjoin:
DOTS { $$ = new joinExp($1.pos, $1.sym); }
| DOTS tension DOTS
{ $$ = new joinExp($1.pos, $1.sym); $$->pushBack($2); }
| DOTS controls DOTS
{ $$ = new joinExp($1.pos, $1.sym); $$->pushBack($2); }
| COLONS { $$ = new joinExp($1.pos, $1.sym); }
| LONGDASH { $$ = new joinExp($1.pos, $1.sym); }
;
tension:
TENSION exp { $$ = new binaryExp($1.pos, $2, $1.sym,
new booleanExp($1.pos, false)); }
| TENSION exp AND exp
{ $$ = new ternaryExp($1.pos, $2, $1.sym, $4,
new booleanExp($1.pos, false)); }
| TENSION ATLEAST exp
{ $$ = new binaryExp($1.pos, $3, $1.sym,
new booleanExp($2.pos, true)); }
| TENSION ATLEAST exp AND exp
{ $$ = new ternaryExp($1.pos, $3, $1.sym, $5,
new booleanExp($2.pos, true)); }
;
controls:
CONTROLS exp { $$ = new unaryExp($1.pos, $2, $1.sym); }
| CONTROLS exp AND exp
{ $$ = new binaryExp($1.pos, $2, $1.sym, $4); }
;
stm:
';' { $$ = new emptyStm($1); }
| blockstm { $$ = $1; }
| stmexp ';' { $$ = $1; }
| IF '(' exp ')' stm
{ $$ = new ifStm($1, $3, $5); }
| IF '(' exp ')' stm ELSE stm
{ $$ = new ifStm($1, $3, $5, $7); }
| WHILE '(' exp ')' stm
{ $$ = new whileStm($1, $3, $5); }
| DO stm WHILE '(' exp ')' ';'
{ $$ = new doStm($1, $2, $5); }
| FOR '(' forinit ';' fortest ';' forupdate ')' stm
{ $$ = new forStm($1, $3, $5, $7, $9); }
| FOR '(' type ID ':' exp ')' stm
{ $$ = new extendedForStm($1, $3, $4.sym, $6, $8); }
| BREAK ';' { $$ = new breakStm($1); }
| CONTINUE ';' { $$ = new continueStm($1); }
| RETURN_ ';' { $$ = new returnStm($1); }
| RETURN_ exp ';' { $$ = new returnStm($1, $2); }
;
stmexp:
exp { $$ = new expStm($1->getPos(), $1); }
;
blockstm:
block { $$ = new blockStm($1->getPos(), $1); }
;
forinit:
/* empty */ { $$ = 0; }
| stmexplist { $$ = $1; }
| barevardec { $$ = $1; }
;
fortest:
/* empty */ { $$ = 0; }
| exp { $$ = $1; }
;
forupdate:
/* empty */ { $$ = 0; }
| stmexplist { $$ = $1; }
;
stmexplist:
stmexp { $$ = new stmExpList($1->getPos()); $$->add($1); }
| stmexplist ',' stmexp
{ $$ = $1; $$->add($3); }
;