%{
#include "cc.h"
%}
%union {
Node* node;
Sym* sym;
Type* type;
struct
{
Type* t;
char c;
} tycl;
struct
{
Type* t1;
Type* t2;
} tyty;
struct
{
char* s;
long l;
} sval;
long 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
%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
%%
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:
{
$$ = Z;
}
| adecl ctlist ';'
{
$$ = dodecl(adecl, lastclass, lasttype, Z);
if($1 != Z)
if($$ != Z)
$$ = new(OLIST, $1, $$);
else
$$ = $1;
}
| adecl ctlist adlist ';'
{
$$ = $1;
if($3 != Z) {
$$ = $3;
if($1 != Z)
$$ = new(OLIST, $1, $3);
}
}
adlist:
xdecor
{
dodecl(adecl, lastclass, lasttype, $1);
$$ = Z;
}
| xdecor
{
$1 = dodecl(adecl, lastclass, lasttype, $1);
}
'=' init
{
long 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:
'{' adecl slist '}'
{
$$ = invert($3);
if($2 != Z)
$$ = new(OLIST, $2, $$);
if($$ == Z)
$$ = new(OLIST, Z, Z);
}
slist:
{
$$ = Z;
}
| 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);
}
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");
}
| LFOR '(' zcexpr ';' zcexpr ';' zcexpr ')' stmnt
{
$$ = new(OFOR, new(OLIST, $5, new(OLIST, $3, $7)), $9);
}
| 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;
}
| '(' 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;
}
| LLCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TLONG];
$$->vconst = $1;
}
| LUCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TUINT];
$$->vconst = $1;
}
| LULCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TULONG];
$$->vconst = $1;
}
| LDCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TDOUBLE];
$$->fconst = $1;
}
| LFCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TFLOAT];
$$->fconst = $1;
}
| LVLCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TVLONG];
$$->vconst = $1;
}
| LUVLCONST
{
$$ = new(OCONST, Z, Z);
$$->type = types[TUVLONG];
$$->vconst = $1;
}
| 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;
strf = T;
strl = T;
lastbit = 0;
firstbit = 1;
}
edecl '}'
{
$$ = strf;
strf = $<tyty>2.t1;
strl = $<tyty>2.t2;
}
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;
suallign($$);
}
| LSTRUCT sbody
{
taggen++;
sprint(symb, "_%d_", taggen);
$$ = dotag(lookup(), TSTRUCT, autobn);
$$->link = $2;
suallign($$);
}
| 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;
suallign($$);
}
| LUNION sbody
{
taggen++;
sprint(symb, "_%d_", taggen);
$$ = dotag(lookup(), TUNION, autobn);
$$->link = $2;
suallign($$);
}
| 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; }
gname: /* garbage words */
LCONSTNT { $$ = BCONSTNT; }
| LVOLATILE { $$ = BVOLATILE; }
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
%%
|