summaryrefslogtreecommitdiff
path: root/graphics/asymptote/camp.y
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /graphics/asymptote/camp.y
Initial commit
Diffstat (limited to 'graphics/asymptote/camp.y')
-rw-r--r--graphics/asymptote/camp.y652
1 files changed, 652 insertions, 0 deletions
diff --git a/graphics/asymptote/camp.y b/graphics/asymptote/camp.y
new file mode 100644
index 0000000000..01bd47ecbc
--- /dev/null
+++ b/graphics/asymptote/camp.y
@@ -0,0 +1,652 @@
+%{
+/*****
+ * 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::ty *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;
+}
+
+%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 NEW
+ IF ELSE WHILE DO FOR BREAK CONTINUE RETURN_
+ THIS 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
+%type <fls> formals
+%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
+
+/* 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()); }
+;
+
+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); }
+;
+
+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 { $$ = 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); }
+;