| // 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 <u.h> | |
| #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 | |
| %% |