| // Inferno utils/cc/cc.y |
| // http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y |
| // |
| // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. |
| // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) |
| // Portions Copyright © 1997-1999 Vita Nuova Limited |
| // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) |
| // Portions Copyright © 2004,2006 Bruce Ellis |
| // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) |
| // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others |
| // Portions Copyright © 2009 The Go Authors. All rights reserved. |
| // |
| // Permission is hereby granted, free of charge, to any person obtaining a copy |
| // of this software and associated documentation files (the "Software"), to deal |
| // in the Software without restriction, including without limitation the rights |
| // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| // copies of the Software, and to permit persons to whom the Software is |
| // furnished to do so, subject to the following conditions: |
| // |
| // The above copyright notice and this permission notice shall be included in |
| // all copies or substantial portions of the Software. |
| // |
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| // THE SOFTWARE. |
| |
| %{ |
| #include <stdio.h> /* if we don't, bison will, and cc.h re-#defines getc */ |
| #include "cc.h" |
| %} |
| %union { |
| Node* node; |
| Sym* sym; |
| Type* type; |
| struct |
| { |
| Type* t; |
| uchar c; |
| } tycl; |
| struct |
| { |
| Type* t1; |
| Type* t2; |
| Type* t3; |
| uchar c; |
| } tyty; |
| struct |
| { |
| char* s; |
| int32 l; |
| } sval; |
| int32 lval; |
| double dval; |
| vlong vval; |
| } |
| %type <sym> ltag |
| %type <lval> gctname gcname cname gname tname |
| %type <lval> gctnlist gcnlist zgnlist |
| %type <type> tlist sbody complex |
| %type <tycl> types |
| %type <node> zarglist arglist zcexpr |
| %type <node> name block stmnt cexpr expr xuexpr pexpr |
| %type <node> zelist elist adecl slist uexpr string lstring |
| %type <node> xdecor xdecor2 labels label ulstmnt |
| %type <node> adlist edecor tag qual qlist |
| %type <node> abdecor abdecor1 abdecor2 abdecor3 |
| %type <node> zexpr lexpr init ilist forexpr |
| |
| %left ';' |
| %left ',' |
| %right '=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE |
| %right '?' ':' |
| %left LOROR |
| %left LANDAND |
| %left '|' |
| %left '^' |
| %left '&' |
| %left LEQ LNE |
| %left '<' '>' LLE LGE |
| %left LLSH LRSH |
| %left '+' '-' |
| %left '*' '/' '%' |
| %right LMM LPP LMG '.' '[' '(' |
| |
| %token <sym> LNAME LTYPE |
| %token <dval> LFCONST LDCONST |
| %token <vval> LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST |
| %token <sval> LSTRING LLSTRING |
| %token LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO |
| %token LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO |
| %token LIF LINT LLONG LREGISTER LRETURN LSHORT LSIZEOF LUSED |
| %token LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED |
| %token LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF |
| %token LRESTRICT LINLINE |
| %% |
| prog: |
| | prog xdecl |
| |
| /* |
| * external declarator |
| */ |
| xdecl: |
| zctlist ';' |
| { |
| dodecl(xdecl, lastclass, lasttype, Z); |
| } |
| | zctlist xdlist ';' |
| | zctlist xdecor |
| { |
| lastdcl = T; |
| firstarg = S; |
| dodecl(xdecl, lastclass, lasttype, $2); |
| if(lastdcl == T || lastdcl->etype != TFUNC) { |
| diag($2, "not a function"); |
| lastdcl = types[TFUNC]; |
| } |
| thisfn = lastdcl; |
| markdcl(); |
| firstdcl = dclstack; |
| argmark($2, 0); |
| } |
| pdecl |
| { |
| argmark($2, 1); |
| } |
| block |
| { |
| Node *n; |
| |
| n = revertdcl(); |
| if(n) |
| $6 = new(OLIST, n, $6); |
| if(!debug['a'] && !debug['Z']) |
| codgen($6, $2); |
| } |
| |
| xdlist: |
| xdecor |
| { |
| dodecl(xdecl, lastclass, lasttype, $1); |
| } |
| | xdecor |
| { |
| $1 = dodecl(xdecl, lastclass, lasttype, $1); |
| } |
| '=' init |
| { |
| doinit($1->sym, $1->type, 0L, $4); |
| } |
| | xdlist ',' xdlist |
| |
| xdecor: |
| xdecor2 |
| | '*' zgnlist xdecor |
| { |
| $$ = new(OIND, $3, Z); |
| $$->garb = simpleg($2); |
| } |
| |
| xdecor2: |
| tag |
| | '(' xdecor ')' |
| { |
| $$ = $2; |
| } |
| | xdecor2 '(' zarglist ')' |
| { |
| $$ = new(OFUNC, $1, $3); |
| } |
| | xdecor2 '[' zexpr ']' |
| { |
| $$ = new(OARRAY, $1, $3); |
| } |
| |
| /* |
| * automatic declarator |
| */ |
| adecl: |
| ctlist ';' |
| { |
| $$ = dodecl(adecl, lastclass, lasttype, Z); |
| } |
| | ctlist adlist ';' |
| { |
| $$ = $2; |
| } |
| |
| adlist: |
| xdecor |
| { |
| dodecl(adecl, lastclass, lasttype, $1); |
| $$ = Z; |
| } |
| | xdecor |
| { |
| $1 = dodecl(adecl, lastclass, lasttype, $1); |
| } |
| '=' init |
| { |
| int32 w; |
| |
| w = $1->sym->type->width; |
| $$ = doinit($1->sym, $1->type, 0L, $4); |
| $$ = contig($1->sym, $$, w); |
| } |
| | adlist ',' adlist |
| { |
| $$ = $1; |
| if($3 != Z) { |
| $$ = $3; |
| if($1 != Z) |
| $$ = new(OLIST, $1, $3); |
| } |
| } |
| |
| /* |
| * parameter declarator |
| */ |
| pdecl: |
| | pdecl ctlist pdlist ';' |
| |
| pdlist: |
| xdecor |
| { |
| dodecl(pdecl, lastclass, lasttype, $1); |
| } |
| | pdlist ',' pdlist |
| |
| /* |
| * structure element declarator |
| */ |
| edecl: |
| tlist |
| { |
| lasttype = $1; |
| } |
| zedlist ';' |
| | edecl tlist |
| { |
| lasttype = $2; |
| } |
| zedlist ';' |
| |
| zedlist: /* extension */ |
| { |
| lastfield = 0; |
| edecl(CXXX, lasttype, S); |
| } |
| | edlist |
| |
| edlist: |
| edecor |
| { |
| dodecl(edecl, CXXX, lasttype, $1); |
| } |
| | edlist ',' edlist |
| |
| edecor: |
| xdecor |
| { |
| lastbit = 0; |
| firstbit = 1; |
| } |
| | tag ':' lexpr |
| { |
| $$ = new(OBIT, $1, $3); |
| } |
| | ':' lexpr |
| { |
| $$ = new(OBIT, Z, $2); |
| } |
| |
| /* |
| * abstract declarator |
| */ |
| abdecor: |
| { |
| $$ = (Z); |
| } |
| | abdecor1 |
| |
| abdecor1: |
| '*' zgnlist |
| { |
| $$ = new(OIND, (Z), Z); |
| $$->garb = simpleg($2); |
| } |
| | '*' zgnlist abdecor1 |
| { |
| $$ = new(OIND, $3, Z); |
| $$->garb = simpleg($2); |
| } |
| | abdecor2 |
| |
| abdecor2: |
| abdecor3 |
| | abdecor2 '(' zarglist ')' |
| { |
| $$ = new(OFUNC, $1, $3); |
| } |
| | abdecor2 '[' zexpr ']' |
| { |
| $$ = new(OARRAY, $1, $3); |
| } |
| |
| abdecor3: |
| '(' ')' |
| { |
| $$ = new(OFUNC, (Z), Z); |
| } |
| | '[' zexpr ']' |
| { |
| $$ = new(OARRAY, (Z), $2); |
| } |
| | '(' abdecor1 ')' |
| { |
| $$ = $2; |
| } |
| |
| init: |
| expr |
| | '{' ilist '}' |
| { |
| $$ = new(OINIT, invert($2), Z); |
| } |
| |
| qual: |
| '[' lexpr ']' |
| { |
| $$ = new(OARRAY, $2, Z); |
| } |
| | '.' ltag |
| { |
| $$ = new(OELEM, Z, Z); |
| $$->sym = $2; |
| } |
| | qual '=' |
| |
| qlist: |
| init ',' |
| | qlist init ',' |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| | qual |
| | qlist qual |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| |
| ilist: |
| qlist |
| | init |
| | qlist init |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| |
| zarglist: |
| { |
| $$ = Z; |
| } |
| | arglist |
| { |
| $$ = invert($1); |
| } |
| |
| |
| arglist: |
| name |
| | tlist abdecor |
| { |
| $$ = new(OPROTO, $2, Z); |
| $$->type = $1; |
| } |
| | tlist xdecor |
| { |
| $$ = new(OPROTO, $2, Z); |
| $$->type = $1; |
| } |
| | '.' '.' '.' |
| { |
| $$ = new(ODOTDOT, Z, Z); |
| } |
| | arglist ',' arglist |
| { |
| $$ = new(OLIST, $1, $3); |
| } |
| |
| block: |
| '{' slist '}' |
| { |
| $$ = invert($2); |
| // if($2 != Z) |
| // $$ = new(OLIST, $2, $$); |
| if($$ == Z) |
| $$ = new(OLIST, Z, Z); |
| } |
| |
| slist: |
| { |
| $$ = Z; |
| } |
| | slist adecl |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| | slist stmnt |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| |
| labels: |
| label |
| | labels label |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| |
| label: |
| LCASE expr ':' |
| { |
| $$ = new(OCASE, $2, Z); |
| } |
| | LDEFAULT ':' |
| { |
| $$ = new(OCASE, Z, Z); |
| } |
| | LNAME ':' |
| { |
| $$ = new(OLABEL, dcllabel($1, 1), Z); |
| } |
| |
| stmnt: |
| error ';' |
| { |
| $$ = Z; |
| } |
| | ulstmnt |
| | labels ulstmnt |
| { |
| $$ = new(OLIST, $1, $2); |
| } |
| |
| forexpr: |
| zcexpr |
| | ctlist adlist |
| { |
| $$ = $2; |
| } |
| |
| ulstmnt: |
| zcexpr ';' |
| | { |
| markdcl(); |
| } |
| block |
| { |
| $$ = revertdcl(); |
| if($$) |
| $$ = new(OLIST, $$, $2); |
| else |
| $$ = $2; |
| } |
| | LIF '(' cexpr ')' stmnt |
| { |
| $$ = new(OIF, $3, new(OLIST, $5, Z)); |
| if($5 == Z) |
| warn($3, "empty if body"); |
| } |
| | LIF '(' cexpr ')' stmnt LELSE stmnt |
| { |
| $$ = new(OIF, $3, new(OLIST, $5, $7)); |
| if($5 == Z) |
| warn($3, "empty if body"); |
| if($7 == Z) |
| warn($3, "empty else body"); |
| } |
| | { markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt |
| { |
| $$ = revertdcl(); |
| if($$){ |
| if($4) |
| $4 = new(OLIST, $$, $4); |
| else |
| $4 = $$; |
| } |
| $$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10); |
| } |
| | LWHILE '(' cexpr ')' stmnt |
| { |
| $$ = new(OWHILE, $3, $5); |
| } |
| | LDO stmnt LWHILE '(' cexpr ')' ';' |
| { |
| $$ = new(ODWHILE, $5, $2); |
| } |
| | LRETURN zcexpr ';' |
| { |
| $$ = new(ORETURN, $2, Z); |
| $$->type = thisfn->link; |
| } |
| | LSWITCH '(' cexpr ')' stmnt |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->vconst = 0; |
| $$->type = types[TINT]; |
| $3 = new(OSUB, $$, $3); |
| |
| $$ = new(OCONST, Z, Z); |
| $$->vconst = 0; |
| $$->type = types[TINT]; |
| $3 = new(OSUB, $$, $3); |
| |
| $$ = new(OSWITCH, $3, $5); |
| } |
| | LBREAK ';' |
| { |
| $$ = new(OBREAK, Z, Z); |
| } |
| | LCONTINUE ';' |
| { |
| $$ = new(OCONTINUE, Z, Z); |
| } |
| | LGOTO ltag ';' |
| { |
| $$ = new(OGOTO, dcllabel($2, 0), Z); |
| } |
| | LUSED '(' zelist ')' ';' |
| { |
| $$ = new(OUSED, $3, Z); |
| } |
| | LSET '(' zelist ')' ';' |
| { |
| $$ = new(OSET, $3, Z); |
| } |
| |
| zcexpr: |
| { |
| $$ = Z; |
| } |
| | cexpr |
| |
| zexpr: |
| { |
| $$ = Z; |
| } |
| | lexpr |
| |
| lexpr: |
| expr |
| { |
| $$ = new(OCAST, $1, Z); |
| $$->type = types[TLONG]; |
| } |
| |
| cexpr: |
| expr |
| | cexpr ',' cexpr |
| { |
| $$ = new(OCOMMA, $1, $3); |
| } |
| |
| expr: |
| xuexpr |
| | expr '*' expr |
| { |
| $$ = new(OMUL, $1, $3); |
| } |
| | expr '/' expr |
| { |
| $$ = new(ODIV, $1, $3); |
| } |
| | expr '%' expr |
| { |
| $$ = new(OMOD, $1, $3); |
| } |
| | expr '+' expr |
| { |
| $$ = new(OADD, $1, $3); |
| } |
| | expr '-' expr |
| { |
| $$ = new(OSUB, $1, $3); |
| } |
| | expr LRSH expr |
| { |
| $$ = new(OASHR, $1, $3); |
| } |
| | expr LLSH expr |
| { |
| $$ = new(OASHL, $1, $3); |
| } |
| | expr '<' expr |
| { |
| $$ = new(OLT, $1, $3); |
| } |
| | expr '>' expr |
| { |
| $$ = new(OGT, $1, $3); |
| } |
| | expr LLE expr |
| { |
| $$ = new(OLE, $1, $3); |
| } |
| | expr LGE expr |
| { |
| $$ = new(OGE, $1, $3); |
| } |
| | expr LEQ expr |
| { |
| $$ = new(OEQ, $1, $3); |
| } |
| | expr LNE expr |
| { |
| $$ = new(ONE, $1, $3); |
| } |
| | expr '&' expr |
| { |
| $$ = new(OAND, $1, $3); |
| } |
| | expr '^' expr |
| { |
| $$ = new(OXOR, $1, $3); |
| } |
| | expr '|' expr |
| { |
| $$ = new(OOR, $1, $3); |
| } |
| | expr LANDAND expr |
| { |
| $$ = new(OANDAND, $1, $3); |
| } |
| | expr LOROR expr |
| { |
| $$ = new(OOROR, $1, $3); |
| } |
| | expr '?' cexpr ':' expr |
| { |
| $$ = new(OCOND, $1, new(OLIST, $3, $5)); |
| } |
| | expr '=' expr |
| { |
| $$ = new(OAS, $1, $3); |
| } |
| | expr LPE expr |
| { |
| $$ = new(OASADD, $1, $3); |
| } |
| | expr LME expr |
| { |
| $$ = new(OASSUB, $1, $3); |
| } |
| | expr LMLE expr |
| { |
| $$ = new(OASMUL, $1, $3); |
| } |
| | expr LDVE expr |
| { |
| $$ = new(OASDIV, $1, $3); |
| } |
| | expr LMDE expr |
| { |
| $$ = new(OASMOD, $1, $3); |
| } |
| | expr LLSHE expr |
| { |
| $$ = new(OASASHL, $1, $3); |
| } |
| | expr LRSHE expr |
| { |
| $$ = new(OASASHR, $1, $3); |
| } |
| | expr LANDE expr |
| { |
| $$ = new(OASAND, $1, $3); |
| } |
| | expr LXORE expr |
| { |
| $$ = new(OASXOR, $1, $3); |
| } |
| | expr LORE expr |
| { |
| $$ = new(OASOR, $1, $3); |
| } |
| |
| xuexpr: |
| uexpr |
| | '(' tlist abdecor ')' xuexpr |
| { |
| $$ = new(OCAST, $5, Z); |
| dodecl(NODECL, CXXX, $2, $3); |
| $$->type = lastdcl; |
| $$->xcast = 1; |
| } |
| | '(' tlist abdecor ')' '{' ilist '}' /* extension */ |
| { |
| $$ = new(OSTRUCT, $6, Z); |
| dodecl(NODECL, CXXX, $2, $3); |
| $$->type = lastdcl; |
| } |
| |
| uexpr: |
| pexpr |
| | '*' xuexpr |
| { |
| $$ = new(OIND, $2, Z); |
| } |
| | '&' xuexpr |
| { |
| $$ = new(OADDR, $2, Z); |
| } |
| | '+' xuexpr |
| { |
| $$ = new(OPOS, $2, Z); |
| } |
| | '-' xuexpr |
| { |
| $$ = new(ONEG, $2, Z); |
| } |
| | '!' xuexpr |
| { |
| $$ = new(ONOT, $2, Z); |
| } |
| | '~' xuexpr |
| { |
| $$ = new(OCOM, $2, Z); |
| } |
| | LPP xuexpr |
| { |
| $$ = new(OPREINC, $2, Z); |
| } |
| | LMM xuexpr |
| { |
| $$ = new(OPREDEC, $2, Z); |
| } |
| | LSIZEOF uexpr |
| { |
| $$ = new(OSIZE, $2, Z); |
| } |
| | LSIGNOF uexpr |
| { |
| $$ = new(OSIGN, $2, Z); |
| } |
| |
| pexpr: |
| '(' cexpr ')' |
| { |
| $$ = $2; |
| } |
| | LSIZEOF '(' tlist abdecor ')' |
| { |
| $$ = new(OSIZE, Z, Z); |
| dodecl(NODECL, CXXX, $3, $4); |
| $$->type = lastdcl; |
| } |
| | LSIGNOF '(' tlist abdecor ')' |
| { |
| $$ = new(OSIGN, Z, Z); |
| dodecl(NODECL, CXXX, $3, $4); |
| $$->type = lastdcl; |
| } |
| | pexpr '(' zelist ')' |
| { |
| $$ = new(OFUNC, $1, Z); |
| if($1->op == ONAME) |
| if($1->type == T) |
| dodecl(xdecl, CXXX, types[TINT], $$); |
| $$->right = invert($3); |
| } |
| | pexpr '[' cexpr ']' |
| { |
| $$ = new(OIND, new(OADD, $1, $3), Z); |
| } |
| | pexpr LMG ltag |
| { |
| $$ = new(ODOT, new(OIND, $1, Z), Z); |
| $$->sym = $3; |
| } |
| | pexpr '.' ltag |
| { |
| $$ = new(ODOT, $1, Z); |
| $$->sym = $3; |
| } |
| | pexpr LPP |
| { |
| $$ = new(OPOSTINC, $1, Z); |
| } |
| | pexpr LMM |
| { |
| $$ = new(OPOSTDEC, $1, Z); |
| } |
| | name |
| | LCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TINT]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LLCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TLONG]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LUCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TUINT]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LULCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TULONG]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LDCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TDOUBLE]; |
| $$->fconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LFCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TFLOAT]; |
| $$->fconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LVLCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TVLONG]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | LUVLCONST |
| { |
| $$ = new(OCONST, Z, Z); |
| $$->type = types[TUVLONG]; |
| $$->vconst = $1; |
| $$->cstring = strdup(symb); |
| } |
| | string |
| | lstring |
| |
| string: |
| LSTRING |
| { |
| $$ = new(OSTRING, Z, Z); |
| $$->type = typ(TARRAY, types[TCHAR]); |
| $$->type->width = $1.l + 1; |
| $$->cstring = $1.s; |
| $$->sym = symstring; |
| $$->etype = TARRAY; |
| $$->class = CSTATIC; |
| } |
| | string LSTRING |
| { |
| char *s; |
| int n; |
| |
| n = $1->type->width - 1; |
| s = alloc(n+$2.l+MAXALIGN); |
| |
| memcpy(s, $1->cstring, n); |
| memcpy(s+n, $2.s, $2.l); |
| s[n+$2.l] = 0; |
| |
| $$ = $1; |
| $$->type->width += $2.l; |
| $$->cstring = s; |
| } |
| |
| lstring: |
| LLSTRING |
| { |
| $$ = new(OLSTRING, Z, Z); |
| $$->type = typ(TARRAY, types[TUSHORT]); |
| $$->type->width = $1.l + sizeof(ushort); |
| $$->rstring = (ushort*)$1.s; |
| $$->sym = symstring; |
| $$->etype = TARRAY; |
| $$->class = CSTATIC; |
| } |
| | lstring LLSTRING |
| { |
| char *s; |
| int n; |
| |
| n = $1->type->width - sizeof(ushort); |
| s = alloc(n+$2.l+MAXALIGN); |
| |
| memcpy(s, $1->rstring, n); |
| memcpy(s+n, $2.s, $2.l); |
| *(ushort*)(s+n+$2.l) = 0; |
| |
| $$ = $1; |
| $$->type->width += $2.l; |
| $$->rstring = (ushort*)s; |
| } |
| |
| zelist: |
| { |
| $$ = Z; |
| } |
| | elist |
| |
| elist: |
| expr |
| | elist ',' elist |
| { |
| $$ = new(OLIST, $1, $3); |
| } |
| |
| sbody: |
| '{' |
| { |
| $<tyty>$.t1 = strf; |
| $<tyty>$.t2 = strl; |
| $<tyty>$.t3 = lasttype; |
| $<tyty>$.c = lastclass; |
| strf = T; |
| strl = T; |
| lastbit = 0; |
| firstbit = 1; |
| lastclass = CXXX; |
| lasttype = T; |
| } |
| edecl '}' |
| { |
| $$ = strf; |
| strf = $<tyty>2.t1; |
| strl = $<tyty>2.t2; |
| lasttype = $<tyty>2.t3; |
| lastclass = $<tyty>2.c; |
| } |
| |
| zctlist: |
| { |
| lastclass = CXXX; |
| lasttype = types[TINT]; |
| } |
| | ctlist |
| |
| types: |
| complex |
| { |
| $$.t = $1; |
| $$.c = CXXX; |
| } |
| | tname |
| { |
| $$.t = simplet($1); |
| $$.c = CXXX; |
| } |
| | gcnlist |
| { |
| $$.t = simplet($1); |
| $$.c = simplec($1); |
| $$.t = garbt($$.t, $1); |
| } |
| | complex gctnlist |
| { |
| $$.t = $1; |
| $$.c = simplec($2); |
| $$.t = garbt($$.t, $2); |
| if($2 & ~BCLASS & ~BGARB) |
| diag(Z, "duplicate types given: %T and %Q", $1, $2); |
| } |
| | tname gctnlist |
| { |
| $$.t = simplet(typebitor($1, $2)); |
| $$.c = simplec($2); |
| $$.t = garbt($$.t, $2); |
| } |
| | gcnlist complex zgnlist |
| { |
| $$.t = $2; |
| $$.c = simplec($1); |
| $$.t = garbt($$.t, $1|$3); |
| } |
| | gcnlist tname |
| { |
| $$.t = simplet($2); |
| $$.c = simplec($1); |
| $$.t = garbt($$.t, $1); |
| } |
| | gcnlist tname gctnlist |
| { |
| $$.t = simplet(typebitor($2, $3)); |
| $$.c = simplec($1|$3); |
| $$.t = garbt($$.t, $1|$3); |
| } |
| |
| tlist: |
| types |
| { |
| $$ = $1.t; |
| if($1.c != CXXX) |
| diag(Z, "illegal combination of class 4: %s", cnames[$1.c]); |
| } |
| |
| ctlist: |
| types |
| { |
| lasttype = $1.t; |
| lastclass = $1.c; |
| } |
| |
| complex: |
| LSTRUCT ltag |
| { |
| dotag($2, TSTRUCT, 0); |
| $$ = $2->suetag; |
| } |
| | LSTRUCT ltag |
| { |
| dotag($2, TSTRUCT, autobn); |
| } |
| sbody |
| { |
| $$ = $2->suetag; |
| if($$->link != T) |
| diag(Z, "redeclare tag: %s", $2->name); |
| $$->link = $4; |
| sualign($$); |
| } |
| | LSTRUCT sbody |
| { |
| taggen++; |
| sprint(symb, "_%d_", taggen); |
| $$ = dotag(lookup(), TSTRUCT, autobn); |
| $$->link = $2; |
| sualign($$); |
| } |
| | LUNION ltag |
| { |
| dotag($2, TUNION, 0); |
| $$ = $2->suetag; |
| } |
| | LUNION ltag |
| { |
| dotag($2, TUNION, autobn); |
| } |
| sbody |
| { |
| $$ = $2->suetag; |
| if($$->link != T) |
| diag(Z, "redeclare tag: %s", $2->name); |
| $$->link = $4; |
| sualign($$); |
| } |
| | LUNION sbody |
| { |
| taggen++; |
| sprint(symb, "_%d_", taggen); |
| $$ = dotag(lookup(), TUNION, autobn); |
| $$->link = $2; |
| sualign($$); |
| } |
| | LENUM ltag |
| { |
| dotag($2, TENUM, 0); |
| $$ = $2->suetag; |
| if($$->link == T) |
| $$->link = types[TINT]; |
| $$ = $$->link; |
| } |
| | LENUM ltag |
| { |
| dotag($2, TENUM, autobn); |
| } |
| '{' |
| { |
| en.tenum = T; |
| en.cenum = T; |
| } |
| enum '}' |
| { |
| $$ = $2->suetag; |
| if($$->link != T) |
| diag(Z, "redeclare tag: %s", $2->name); |
| if(en.tenum == T) { |
| diag(Z, "enum type ambiguous: %s", $2->name); |
| en.tenum = types[TINT]; |
| } |
| $$->link = en.tenum; |
| $$ = en.tenum; |
| } |
| | LENUM '{' |
| { |
| en.tenum = T; |
| en.cenum = T; |
| } |
| enum '}' |
| { |
| $$ = en.tenum; |
| } |
| | LTYPE |
| { |
| $$ = tcopy($1->type); |
| } |
| |
| gctnlist: |
| gctname |
| | gctnlist gctname |
| { |
| $$ = typebitor($1, $2); |
| } |
| |
| zgnlist: |
| { |
| $$ = 0; |
| } |
| | zgnlist gname |
| { |
| $$ = typebitor($1, $2); |
| } |
| |
| gctname: |
| tname |
| | gname |
| | cname |
| |
| gcnlist: |
| gcname |
| | gcnlist gcname |
| { |
| $$ = typebitor($1, $2); |
| } |
| |
| gcname: |
| gname |
| | cname |
| |
| enum: |
| LNAME |
| { |
| doenum($1, Z); |
| } |
| | LNAME '=' expr |
| { |
| doenum($1, $3); |
| } |
| | enum ',' |
| | enum ',' enum |
| |
| tname: /* type words */ |
| LCHAR { $$ = BCHAR; } |
| | LSHORT { $$ = BSHORT; } |
| | LINT { $$ = BINT; } |
| | LLONG { $$ = BLONG; } |
| | LSIGNED { $$ = BSIGNED; } |
| | LUNSIGNED { $$ = BUNSIGNED; } |
| | LFLOAT { $$ = BFLOAT; } |
| | LDOUBLE { $$ = BDOUBLE; } |
| | LVOID { $$ = BVOID; } |
| |
| cname: /* class words */ |
| LAUTO { $$ = BAUTO; } |
| | LSTATIC { $$ = BSTATIC; } |
| | LEXTERN { $$ = BEXTERN; } |
| | LTYPEDEF { $$ = BTYPEDEF; } |
| | LTYPESTR { $$ = BTYPESTR; } |
| | LREGISTER { $$ = BREGISTER; } |
| | LINLINE { $$ = 0; } |
| |
| gname: /* garbage words */ |
| LCONSTNT { $$ = BCONSTNT; } |
| | LVOLATILE { $$ = BVOLATILE; } |
| | LRESTRICT { $$ = 0; } |
| |
| name: |
| LNAME |
| { |
| $$ = new(ONAME, Z, Z); |
| if($1->class == CLOCAL) |
| $1 = mkstatic($1); |
| $$->sym = $1; |
| $$->type = $1->type; |
| $$->etype = TVOID; |
| if($$->type != T) |
| $$->etype = $$->type->etype; |
| $$->xoffset = $1->offset; |
| $$->class = $1->class; |
| $1->aused = 1; |
| } |
| tag: |
| ltag |
| { |
| $$ = new(ONAME, Z, Z); |
| $$->sym = $1; |
| $$->type = $1->type; |
| $$->etype = TVOID; |
| if($$->type != T) |
| $$->etype = $$->type->etype; |
| $$->xoffset = $1->offset; |
| $$->class = $1->class; |
| } |
| ltag: |
| LNAME |
| | LTYPE |
| %% |