1184 lines
16 KiB
Plaintext
1184 lines
16 KiB
Plaintext
%{
|
|
#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;
|
|
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 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
|
|
{
|
|
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:
|
|
'{' 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[TRUNE]);
|
|
$$->type->width = $1.l + sizeof(Rune);
|
|
$$->rstring = (Rune*)$1.s;
|
|
$$->sym = symstring;
|
|
$$->etype = TARRAY;
|
|
$$->class = CSTATIC;
|
|
}
|
|
| lstring LLSTRING
|
|
{
|
|
char *s;
|
|
int n;
|
|
|
|
n = $1->type->width - sizeof(Rune);
|
|
s = alloc(n+$2.l+MAXALIGN);
|
|
|
|
memcpy(s, $1->rstring, n);
|
|
memcpy(s+n, $2.s, $2.l);
|
|
*(Rune*)(s+n+$2.l) = 0;
|
|
|
|
$$ = $1;
|
|
$$->type->width += $2.l;
|
|
$$->rstring = (Rune*)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
|
|
%%
|