summaryrefslogtreecommitdiff
path: root/src/cmd/cc/cc.y
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
committerOndřej Surý <ondrej@sury.org>2011-09-13 13:13:40 +0200
commit5ff4c17907d5b19510a62e08fd8d3b11e62b431d (patch)
treec0650497e988f47be9c6f2324fa692a52dea82e1 /src/cmd/cc/cc.y
parent80f18fc933cf3f3e829c5455a1023d69f7b86e52 (diff)
downloadgolang-upstream/60.tar.gz
Imported Upstream version 60upstream/60
Diffstat (limited to 'src/cmd/cc/cc.y')
-rw-r--r--src/cmd/cc/cc.y1215
1 files changed, 1215 insertions, 0 deletions
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
new file mode 100644
index 000000000..515a80372
--- /dev/null
+++ b/src/cmd/cc/cc.y
@@ -0,0 +1,1215 @@
+// 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
+%%