add LCC - a better C-Compiler for WEGA
This commit is contained in:
parent
d16dd1e868
commit
a2e3f134dd
|
|
@ -0,0 +1,976 @@
|
|||
%{
|
||||
static char SCCSID[] = "~(#) cgram.y: 2.1 83/07/08";
|
||||
%}
|
||||
%term NAME 2
|
||||
%term STRING 3
|
||||
%term ICON 4
|
||||
%term FCON 5
|
||||
%term PLUS 6
|
||||
%term MINUS 8
|
||||
%term MUL 11
|
||||
%term AND 14
|
||||
%term OR 17
|
||||
%term ER 19
|
||||
%term QUEST 21
|
||||
%term COLON 22
|
||||
%term ANDAND 23
|
||||
%term OROR 24
|
||||
|
||||
/* special interfaces for yacc alone */
|
||||
/* These serve as abbreviations of 2 or more ops:
|
||||
ASOP =, = ops
|
||||
RELOP LE,LT,GE,GT
|
||||
EQUOP EQ,NE
|
||||
DIVOP DIV,MOD
|
||||
SHIFTOP LS,RS
|
||||
ICOP ICR,DECR
|
||||
UNOP NOT,COMPL
|
||||
STROP DOT,STREF
|
||||
|
||||
*/
|
||||
%term ASOP 25
|
||||
%term RELOP 26
|
||||
%term EQUOP 27
|
||||
%term DIVOP 28
|
||||
%term SHIFTOP 29
|
||||
%term INCOP 30
|
||||
%term UNOP 31
|
||||
%term STROP 32
|
||||
|
||||
/* reserved words, etc */
|
||||
%term TYPE 33
|
||||
%term CLASS 34
|
||||
%term STRUCT 35
|
||||
%term RETURN 36
|
||||
%term GOTO 37
|
||||
%term IF 38
|
||||
%term ELSE 39
|
||||
%term SWITCH 40
|
||||
%term BREAK 41
|
||||
%term CONTINUE 42
|
||||
%term WHILE 43
|
||||
%term DO 44
|
||||
%term FOR 45
|
||||
%term DEFAULT 46
|
||||
%term CASE 47
|
||||
%term SIZEOF 48
|
||||
%term ENUM 49
|
||||
|
||||
/* little symbols, etc. */
|
||||
/* namely,
|
||||
|
||||
LP (
|
||||
RP )
|
||||
|
||||
LC {
|
||||
RC }
|
||||
|
||||
LB [
|
||||
RB ]
|
||||
|
||||
CM ,
|
||||
SM ;
|
||||
|
||||
*/
|
||||
|
||||
%term LP 50
|
||||
%term RP 51
|
||||
%term LC 52
|
||||
%term RC 53
|
||||
%term LB 54
|
||||
%term RB 55
|
||||
%term CM 56
|
||||
%term SM 57
|
||||
%term ASSIGN 58
|
||||
%term ASM 59
|
||||
|
||||
/* at last count, there were 7 shift/reduce, 1 reduce/reduce conflicts
|
||||
/* these involved:
|
||||
if/else
|
||||
recognizing functions in various contexts, including declarations
|
||||
error recovery
|
||||
*/
|
||||
|
||||
%left CM
|
||||
%right ASOP ASSIGN
|
||||
%right QUEST COLON
|
||||
%left OROR
|
||||
%left ANDAND
|
||||
%left OR
|
||||
%left ER
|
||||
%left AND
|
||||
%left EQUOP
|
||||
%left RELOP
|
||||
%left SHIFTOP
|
||||
%left PLUS MINUS
|
||||
%left MUL DIVOP
|
||||
%right UNOP
|
||||
%right INCOP SIZEOF
|
||||
%left LB LP STROP
|
||||
%{
|
||||
# include "mfile1.h"
|
||||
%}
|
||||
|
||||
/* define types */
|
||||
%start ext_def_list
|
||||
|
||||
%type <intval> con_e ifelprefix ifprefix whprefix forprefix doprefix switchpart
|
||||
enum_head str_head name_lp
|
||||
%type <nodep> e .e term attributes oattributes type enum_dcl struct_dcl
|
||||
cast_type null_decl funct_idn declarator fdeclarator
|
||||
nfdeclarator elist
|
||||
|
||||
%token <intval> CLASS NAME STRUCT RELOP CM DIVOP PLUS MINUS SHIFTOP MUL AND OR
|
||||
ER ANDAND OROR ASSIGN STROP INCOP UNOP ICON
|
||||
%token <nodep> TYPE
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
static int fake = 0;
|
||||
static char fakename[NCHNAM+1];
|
||||
%}
|
||||
|
||||
ext_def_list: ext_def_list external_def
|
||||
| /* EMPTY */
|
||||
{
|
||||
#ifndef LINT
|
||||
beg_file();
|
||||
#endif
|
||||
ftnend();
|
||||
}
|
||||
;
|
||||
external_def: data_def
|
||||
{ curclass = SNULL; blevel = 0; }
|
||||
| error
|
||||
{ curclass = SNULL; blevel = 0; }
|
||||
| ASM SM
|
||||
{ asmout(); curclass = SNULL; blevel = 0; }
|
||||
;
|
||||
data_def: oattributes SM
|
||||
{ $1->in.op = FREE; }
|
||||
| oattributes init_dcl_list SM
|
||||
{ $1->in.op = FREE; }
|
||||
| oattributes fdeclarator
|
||||
{ defid( tymerge($1,$2),
|
||||
curclass==STATIC?STATIC:EXTDEF ); }
|
||||
function_body
|
||||
{
|
||||
if( blevel ) cerror( "function level error" );
|
||||
if( reached ) retstat |= NRETVAL;
|
||||
$1->in.op = FREE;
|
||||
ftnend();
|
||||
}
|
||||
;
|
||||
|
||||
function_body: arg_dcl_list compoundstmt
|
||||
{ regvar = 0; } /* clear out arguments */
|
||||
;
|
||||
|
||||
arg_dcl_list: arg_dcl_list attributes declarator_list SM
|
||||
{ curclass = SNULL; $2->in.op = FREE; }
|
||||
| arg_dcl_list attributes SM
|
||||
/* to permit structs in decl. lists */
|
||||
{ curclass = SNULL; $2->in.op = FREE; }
|
||||
| /* EMPTY */ { blevel = 1; }
|
||||
;
|
||||
|
||||
stmt_list: stmt_list statement
|
||||
| /* EMPTY */
|
||||
{ bccode();
|
||||
locctr(PROG);
|
||||
}
|
||||
;
|
||||
|
||||
dcl_stat_list : dcl_stat_list attributes SM
|
||||
{ $2->in.op = FREE; }
|
||||
| dcl_stat_list attributes init_dcl_list SM
|
||||
{ $2->in.op = FREE; }
|
||||
| /* EMPTY */
|
||||
;
|
||||
|
||||
oattributes: attributes
|
||||
| /* empty */
|
||||
{ $$ = mkty(INT,0,INT); curclass = SNULL; }
|
||||
;
|
||||
attributes: class type
|
||||
{ $$ = $2; }
|
||||
| type class
|
||||
| class
|
||||
{ $$ = mkty(INT,0,INT); }
|
||||
| type
|
||||
{ curclass = SNULL ; }
|
||||
| type class type
|
||||
{ $1->in.type = types( $1->in.type, $3->in.type,
|
||||
UNDEF );
|
||||
$3->in.op = FREE;
|
||||
}
|
||||
;
|
||||
|
||||
class: CLASS
|
||||
{ curclass = $1; }
|
||||
;
|
||||
|
||||
type: TYPE
|
||||
| TYPE TYPE
|
||||
{ $1->in.type = types( $1->in.type, $2->in.type, UNDEF );
|
||||
$2->in.op = FREE;
|
||||
}
|
||||
| TYPE TYPE TYPE
|
||||
{ $1->in.type = types( $1->in.type, $2->in.type, $3->in.type );
|
||||
$2->in.op = $3->in.op = FREE;
|
||||
}
|
||||
| struct_dcl
|
||||
| enum_dcl
|
||||
;
|
||||
|
||||
enum_dcl: enum_head LC moe_list optcomma RC
|
||||
{ $$ = dclstruct($1); }
|
||||
| ENUM NAME
|
||||
{ $$ = rstruct($2,0); stwart = instruct; }
|
||||
;
|
||||
|
||||
enum_head: ENUM
|
||||
{ $$ = bstruct(-1,0); stwart = SEENAME; }
|
||||
| ENUM NAME
|
||||
{ $$ = bstruct($2,0); stwart = SEENAME; }
|
||||
;
|
||||
|
||||
moe_list: moe
|
||||
| moe_list CM moe
|
||||
;
|
||||
|
||||
moe: NAME
|
||||
{ moedef( $1 ); }
|
||||
| NAME ASSIGN con_e
|
||||
{ strucoff = $3; moedef( $1 ); }
|
||||
;
|
||||
|
||||
struct_dcl: str_head LC type_dcl_list optsemi RC
|
||||
{ $$ = dclstruct($1); }
|
||||
| STRUCT NAME
|
||||
{ $$ = rstruct($2,$1); }
|
||||
;
|
||||
|
||||
str_head: STRUCT
|
||||
{ $$ = bstruct(-1,$1); stwart=0; }
|
||||
| STRUCT NAME
|
||||
{ $$ = bstruct($2,$1); stwart=0; }
|
||||
;
|
||||
|
||||
type_dcl_list: type_declaration
|
||||
| type_dcl_list SM type_declaration
|
||||
;
|
||||
|
||||
type_declaration: type declarator_list
|
||||
{ curclass = SNULL; stwart=0; $1->in.op = FREE; }
|
||||
| type
|
||||
{ if( curclass != MOU ){
|
||||
curclass = SNULL;
|
||||
}
|
||||
else {
|
||||
sprintf( fakename, "$%dFAKE", fake++ );
|
||||
defid( tymerge($1, bdty(NAME,NIL,
|
||||
lookup( fakename, SMOS ))), curclass );
|
||||
werror("union member must be named");
|
||||
}
|
||||
stwart = 0;
|
||||
$1->in.op = FREE;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
declarator_list: declarator
|
||||
{ defid( tymerge($<nodep>0,$1), curclass);
|
||||
stwart = instruct; }
|
||||
| declarator_list CM {$<nodep>$=$<nodep>0;} declarator
|
||||
{ defid( tymerge($<nodep>0,$4), curclass);
|
||||
stwart = instruct; }
|
||||
;
|
||||
declarator: nfdeclarator
|
||||
| nfdeclarator COLON con_e
|
||||
%prec CM
|
||||
{ if( !(instruct&INSTRUCT) )
|
||||
uerror( "field outside of structure" );
|
||||
if( $3<0 || $3 >= FIELD ){
|
||||
uerror( "illegal field size" );
|
||||
$3 = 1;
|
||||
}
|
||||
defid( tymerge($<nodep>0,$1), FIELD|$3 );
|
||||
$$ = NIL;
|
||||
}
|
||||
| COLON con_e
|
||||
%prec CM
|
||||
{ if( !(instruct&INSTRUCT) )
|
||||
uerror( "field outside of structure" );
|
||||
/* alignment or hole */
|
||||
falloc( stab, $2, -1, $<nodep>0 );
|
||||
$$ = NIL;
|
||||
}
|
||||
| error
|
||||
{ $$ = NIL; }
|
||||
;
|
||||
|
||||
/* int (a)(); is not a function --- sorry! */
|
||||
nfdeclarator: MUL nfdeclarator
|
||||
{ umul:
|
||||
$$ = bdty( UNARY MUL, $2, 0 ); }
|
||||
| nfdeclarator LP RP
|
||||
{ uftn:
|
||||
$$ = bdty( UNARY CALL, $1, 0 ); }
|
||||
| nfdeclarator LB RB
|
||||
{ uary:
|
||||
$$ = bdty( LB, $1, 0 ); }
|
||||
| nfdeclarator LB con_e RB
|
||||
{ bary:
|
||||
if( (int)$3 <= 0 )
|
||||
werror( "zero or negative subscript" );
|
||||
$$ = bdty( LB, $1, $3 ); }
|
||||
| NAME
|
||||
{ $$ = bdty( NAME, NIL, $1 ); }
|
||||
| LP nfdeclarator RP
|
||||
{ $$=$2; }
|
||||
;
|
||||
fdeclarator: MUL fdeclarator
|
||||
{ goto umul; }
|
||||
| fdeclarator LP RP
|
||||
{ goto uftn; }
|
||||
| fdeclarator LB RB
|
||||
{ goto uary; }
|
||||
| fdeclarator LB con_e RB
|
||||
{ goto bary; }
|
||||
| LP fdeclarator RP
|
||||
{ $$ = $2; }
|
||||
| name_lp name_list RP
|
||||
{
|
||||
if( blevel!=0 )
|
||||
uerror(
|
||||
"function declaration in bad context");
|
||||
$$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
|
||||
stwart = 0;
|
||||
}
|
||||
| name_lp RP
|
||||
{
|
||||
$$ = bdty( UNARY CALL, bdty(NAME,NIL,$1), 0 );
|
||||
stwart = 0;
|
||||
}
|
||||
;
|
||||
|
||||
name_lp: NAME LP
|
||||
{
|
||||
/* turn off typedefs for argument names */
|
||||
stwart = SEENAME;
|
||||
if( stab[$1].sclass == SNULL )
|
||||
stab[$1].stype = FTN;
|
||||
}
|
||||
;
|
||||
|
||||
name_list: NAME
|
||||
{ ftnarg( $1 ); stwart = SEENAME; }
|
||||
| name_list CM NAME
|
||||
{ ftnarg( $3 ); stwart = SEENAME; }
|
||||
| error
|
||||
;
|
||||
/* always preceeded by attributes: thus the $<nodep>0's */
|
||||
init_dcl_list: init_declarator
|
||||
%prec CM
|
||||
| init_dcl_list CM {$<nodep>$=$<nodep>0;} init_declarator
|
||||
;
|
||||
/* always preceeded by attributes */
|
||||
xnfdeclarator: nfdeclarator
|
||||
{ defid( $1 = tymerge($<nodep>0,$1), curclass);
|
||||
beginit($1->tn.rval);
|
||||
}
|
||||
| error
|
||||
;
|
||||
/* always preceeded by attributes */
|
||||
init_declarator: nfdeclarator
|
||||
{ nidcl( tymerge($<nodep>0,$1) ); }
|
||||
| fdeclarator
|
||||
{ defid( tymerge($<nodep>0,$1), uclass(curclass) );
|
||||
}
|
||||
| xnfdeclarator ASSIGN e
|
||||
%prec CM
|
||||
{ doinit( $3 );
|
||||
endinit(); }
|
||||
| xnfdeclarator ASSIGN LC init_list optcomma RC
|
||||
{ endinit(); }
|
||||
| error
|
||||
;
|
||||
|
||||
init_list: initializer
|
||||
%prec CM
|
||||
| init_list CM initializer
|
||||
;
|
||||
initializer: e
|
||||
%prec CM
|
||||
{ doinit( $1 ); }
|
||||
| ibrace init_list optcomma RC
|
||||
{ irbrace(); }
|
||||
;
|
||||
|
||||
optcomma : /* empty */
|
||||
| CM
|
||||
;
|
||||
|
||||
optsemi : /* empty */
|
||||
| SM
|
||||
;
|
||||
|
||||
ibrace : LC
|
||||
{ ilbrace(); }
|
||||
;
|
||||
|
||||
/* STATEMENTS */
|
||||
|
||||
compoundstmt: begin dcl_stat_list stmt_list RC
|
||||
{
|
||||
clearst(blevel);
|
||||
if (--blevel == 1)
|
||||
{
|
||||
clearst(blevel);
|
||||
blevel = 0;
|
||||
}
|
||||
checkst(blevel);
|
||||
autooff = *--psavbc;
|
||||
regvar = *--psavbc;
|
||||
}
|
||||
;
|
||||
|
||||
begin: LC
|
||||
{ if( blevel == 1 ) dclargs();
|
||||
++blevel;
|
||||
if( psavbc > &asavbc[BCSZ-2] )
|
||||
cerror( "nesting too deep" );
|
||||
*psavbc++ = regvar;
|
||||
*psavbc++ = autooff;
|
||||
}
|
||||
;
|
||||
|
||||
statement: e SM
|
||||
{ ecomp( $1 ); }
|
||||
| ASM SM
|
||||
{ asmout(); }
|
||||
| compoundstmt
|
||||
| ifprefix statement
|
||||
{ deflab($1);
|
||||
reached = 1;
|
||||
}
|
||||
| ifelprefix statement
|
||||
{ if( $1 != NOLAB ){
|
||||
deflab( $1 );
|
||||
reached = 1;
|
||||
}
|
||||
}
|
||||
| whprefix statement
|
||||
{ branch((int)( contlab));
|
||||
deflab( brklab );
|
||||
if( (flostat&FBRK) || !(flostat&FLOOP)) reached = 1;
|
||||
else reached = 0;
|
||||
resetbc(0);
|
||||
}
|
||||
| doprefix statement WHILE LP e RP SM
|
||||
{ deflab( contlab );
|
||||
if( flostat & FCONT ) reached = 1;
|
||||
ecomp( buildtree( CBRANCH,
|
||||
buildtree( NOT, $5, NIL ), bcon( $1 ) ) );
|
||||
deflab( brklab );
|
||||
reached = 1;
|
||||
resetbc(0);
|
||||
}
|
||||
| forprefix .e RP statement
|
||||
{ deflab( contlab );
|
||||
if( flostat&FCONT ) reached = 1;
|
||||
if( $2 ) ecomp( $2 );
|
||||
branch((int)($1));
|
||||
deflab( brklab );
|
||||
if( (flostat&FBRK) || !(flostat&FLOOP) ) reached=1;
|
||||
else reached=0;
|
||||
resetbc(0);
|
||||
}
|
||||
| switchpart statement
|
||||
{ if( reached ) branch((int)(brklab));
|
||||
deflab( $1 );
|
||||
swend();
|
||||
deflab(brklab);
|
||||
if( (flostat&FBRK) || !(flostat&FDEF) ) reached=1;
|
||||
resetbc(FCONT);
|
||||
}
|
||||
| BREAK SM
|
||||
{ if( brklab == NOLAB ) uerror( "illegal break");
|
||||
else if(reached) branch((int)(brklab));
|
||||
flostat |= FBRK;
|
||||
if( brkflag ) goto rch;
|
||||
reached = 0;
|
||||
}
|
||||
| CONTINUE SM
|
||||
{ if( contlab == NOLAB ) uerror( "illegal continue");
|
||||
else branch((int)(contlab));
|
||||
flostat |= FCONT;
|
||||
goto rch;
|
||||
}
|
||||
| RETURN SM
|
||||
{ retstat |= NRETVAL;
|
||||
branch((int)(retlab));
|
||||
rch:
|
||||
if( !reached ) werror( "statement not reached");
|
||||
reached = 0;
|
||||
}
|
||||
| RETURN e SM
|
||||
{ register NODE *temp;
|
||||
TWORD indtype();
|
||||
idname = curftn;
|
||||
temp = buildtree( NAME, NIL, NIL );
|
||||
if(temp->in.type == (FTN|VOID))
|
||||
lerror(
|
||||
"void function %s cannot return value",
|
||||
stab[idname].sname);
|
||||
temp->in.type = DECREF( temp->in.type );
|
||||
temp->in.type = indtype( temp->in.type );
|
||||
temp->tn.op = RNODE; /* node for return */
|
||||
temp = buildtree( ASSIGN, temp, $2 );
|
||||
ecomp( temp );
|
||||
retstat |= RETVAL;
|
||||
branch((int)(retlab));
|
||||
reached = 0;
|
||||
}
|
||||
| GOTO NAME SM
|
||||
{ register NODE *q;
|
||||
q = block( FREE, NIL, NIL, INT|ARY, 0, INT );
|
||||
q->tn.rval = idname = $2;
|
||||
defid( q, ULABEL );
|
||||
stab[idname].suse = -lineno;
|
||||
branch((int)(stab[idname].offset));
|
||||
goto rch;
|
||||
}
|
||||
| SM
|
||||
| error SM
|
||||
| error RC
|
||||
| label statement
|
||||
;
|
||||
label: NAME COLON
|
||||
{ register NODE *q;
|
||||
q = block( FREE, NIL, NIL, INT|ARY, 0, LABEL );
|
||||
q->tn.rval = $1;
|
||||
defid( q, LABEL );
|
||||
reached = 1;
|
||||
}
|
||||
| CASE e COLON
|
||||
{ addcase($2);
|
||||
reached = 1;
|
||||
}
|
||||
| DEFAULT COLON
|
||||
{ reached = 1;
|
||||
adddef();
|
||||
flostat |= FDEF;
|
||||
}
|
||||
;
|
||||
doprefix: DO
|
||||
{ savebc();
|
||||
if( !reached ) werror( "loop not entered at top");
|
||||
brklab = getlab();
|
||||
contlab = getlab();
|
||||
deflab( $$ = getlab() );
|
||||
reached = 1;
|
||||
}
|
||||
;
|
||||
ifprefix: IF LP e RP
|
||||
{ ecomp( buildtree( CBRANCH, $3, bcon( $$=getlab()) ) ) ;
|
||||
reached = 1;
|
||||
}
|
||||
;
|
||||
ifelprefix: ifprefix statement ELSE
|
||||
{ if( reached ) branch((int)($$ = getlab()));
|
||||
else $$ = NOLAB;
|
||||
deflab( $1 );
|
||||
reached = 1;
|
||||
}
|
||||
;
|
||||
|
||||
whprefix: WHILE LP e RP
|
||||
{ savebc();
|
||||
if( !reached ) werror( "loop not entered at top");
|
||||
if( $3->in.op == ICON && $3->tn.lval != 0 ) flostat = FLOOP;
|
||||
deflab( contlab = getlab() );
|
||||
reached = 1;
|
||||
brklab = getlab();
|
||||
if( flostat == FLOOP ) tfree( $3 );
|
||||
else ecomp( buildtree( CBRANCH, $3, bcon( brklab) ) );
|
||||
}
|
||||
;
|
||||
forprefix: FOR LP .e SM .e SM
|
||||
{ if( $3 ) ecomp( $3 );
|
||||
else if( !reached ) werror( "loop not entered at top");
|
||||
savebc();
|
||||
contlab = getlab();
|
||||
brklab = getlab();
|
||||
deflab( $$ = getlab() );
|
||||
reached = 1;
|
||||
if( $5 )
|
||||
ecomp( buildtree( CBRANCH, $5, bcon( brklab) ));
|
||||
else flostat |= FLOOP;
|
||||
}
|
||||
;
|
||||
switchpart: SWITCH LP e RP
|
||||
{ register NODE *temp;
|
||||
savebc();
|
||||
temp = block( SNODE, NIL, NIL, INT, 0, INT );
|
||||
temp = buildtree( ASSIGN, temp, $3 );
|
||||
brklab = getlab();
|
||||
ecomp( temp );
|
||||
branch((int)($$ = getlab()));
|
||||
swstart();
|
||||
reached = 0;
|
||||
}
|
||||
;
|
||||
/* EXPRESSIONS */
|
||||
con_e: { $<intval>$=instruct; stwart=instruct=0; } e
|
||||
%prec CM
|
||||
{ $$ = icons( $2 ); instruct=$<intval>1; }
|
||||
;
|
||||
.e: e
|
||||
|
|
||||
{ $$=0; }
|
||||
;
|
||||
elist: e
|
||||
%prec CM
|
||||
| elist CM e
|
||||
{ goto bop; }
|
||||
;
|
||||
|
||||
e: e RELOP e
|
||||
{
|
||||
preconf:
|
||||
if( yychar==RELOP || yychar==EQUOP || yychar==AND
|
||||
|| yychar==OR || yychar==ER ){
|
||||
precplaint:
|
||||
if( hflag ) werror(
|
||||
"precedence confusion possible: parenthesize!"
|
||||
);
|
||||
}
|
||||
bop:
|
||||
$$ = buildtree( $2, $1, $3 );
|
||||
}
|
||||
| e CM e
|
||||
{ $2 = COMOP;
|
||||
goto bop;
|
||||
}
|
||||
| e DIVOP e
|
||||
{ goto bop; }
|
||||
| e PLUS e
|
||||
{ if(yychar==SHIFTOP) goto precplaint; else goto bop; }
|
||||
| e MINUS e
|
||||
{ if(yychar==SHIFTOP ) goto precplaint; else goto bop; }
|
||||
| e SHIFTOP e
|
||||
{ if(yychar==PLUS||yychar==MINUS) goto precplaint; else goto bop; }
|
||||
| e MUL e
|
||||
{ goto bop; }
|
||||
| e EQUOP e
|
||||
{ goto preconf; }
|
||||
| e AND e
|
||||
{ if( yychar==RELOP||yychar==EQUOP ) goto preconf; else goto bop; }
|
||||
| e OR e
|
||||
{ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
|
||||
| e ER e
|
||||
{ if(yychar==RELOP||yychar==EQUOP) goto preconf; else goto bop; }
|
||||
| e ANDAND e
|
||||
{ goto bop; }
|
||||
| e OROR e
|
||||
{ goto bop; }
|
||||
| e MUL ASSIGN e
|
||||
{ abop:
|
||||
$$ = buildtree( ASG $2, $1, $4 );
|
||||
}
|
||||
| e DIVOP ASSIGN e
|
||||
{ goto abop; }
|
||||
| e PLUS ASSIGN e
|
||||
{ goto abop; }
|
||||
| e MINUS ASSIGN e
|
||||
{ goto abop; }
|
||||
| e SHIFTOP ASSIGN e
|
||||
{ goto abop; }
|
||||
| e AND ASSIGN e
|
||||
{ goto abop; }
|
||||
| e OR ASSIGN e
|
||||
{ goto abop; }
|
||||
| e ER ASSIGN e
|
||||
{ goto abop; }
|
||||
| e QUEST e COLON e
|
||||
{ $$=buildtree(QUEST, $1, buildtree( COLON, $3, $5 ) );
|
||||
}
|
||||
| e ASOP e
|
||||
{ werror( "old-fashioned assignment operator" );
|
||||
goto bop; }
|
||||
| e ASSIGN e
|
||||
{ goto bop; }
|
||||
| term
|
||||
;
|
||||
|
||||
term: term INCOP
|
||||
{ $$ = buildtree( $2, $1, bcon(1) ); }
|
||||
| MUL term
|
||||
{ ubop:
|
||||
$$ = buildtree( UNARY $1, $2, NIL );
|
||||
}
|
||||
| AND term
|
||||
{ if( ISFTN($2->in.type) || ISARY($2->in.type) ){
|
||||
werror( "& before array or function: ignored" );
|
||||
$$ = $2;
|
||||
}
|
||||
else goto ubop;
|
||||
}
|
||||
| MINUS term
|
||||
{ goto ubop; }
|
||||
| UNOP term
|
||||
{
|
||||
$$ = buildtree( $1, $2, NIL );
|
||||
}
|
||||
| INCOP term
|
||||
{ $$ = buildtree( $1==INCR ? ASG PLUS : ASG MINUS,
|
||||
$2,
|
||||
bcon(1) );
|
||||
}
|
||||
| SIZEOF term
|
||||
{ $$ = doszof( $2 ); }
|
||||
| LP cast_type RP term %prec INCOP
|
||||
{ $$ = buildtree( CAST, $2, $4 );
|
||||
$$->in.left->in.op = FREE;
|
||||
$$->in.op = FREE;
|
||||
$$ = $$->in.right;
|
||||
}
|
||||
| SIZEOF LP cast_type RP %prec SIZEOF
|
||||
{ $$ = doszof( $3 ); }
|
||||
| term LB e RB
|
||||
{ $$ = buildtree( LB, $1, $3 ); }
|
||||
| term LB e COLON e RB
|
||||
{ $$ = xicolon( $1, $3, $5 ); }
|
||||
| funct_idn RP
|
||||
{ $$=buildtree(UNARY CALL,$1,NIL); }
|
||||
| funct_idn elist RP
|
||||
{ $$=buildtree(CALL,$1,$2); }
|
||||
| term STROP NAME
|
||||
{ if( $2 == DOT ){
|
||||
if( notlval( $1 ) )uerror(
|
||||
"structure reference must be addressable"
|
||||
);
|
||||
$1 = buildtree( UNARY AND, $1, NIL );
|
||||
}
|
||||
idname = $3;
|
||||
$$ = buildtree( STREF, $1,
|
||||
buildtree( NAME, NIL, NIL ) );
|
||||
}
|
||||
| NAME
|
||||
{ idname = $1;
|
||||
/* recognize identifiers in initializations */
|
||||
if( blevel==0 && stab[idname].stype == UNDEF ) {
|
||||
register NODE *q;
|
||||
werror( "undeclared initializer name %s",
|
||||
stab[idname].sname );
|
||||
q = block( FREE, NIL, NIL, INT, 0, INT );
|
||||
q->tn.rval = idname;
|
||||
defid( q, EXTERN );
|
||||
}
|
||||
$$=buildtree(NAME,NIL,NIL);
|
||||
stab[$1].suse = -lineno;
|
||||
}
|
||||
| ICON
|
||||
{ $$=bcon(0);
|
||||
$$->tn.lval = lastcon;
|
||||
$$->tn.rval = NONAME;
|
||||
if( $1 ) $$->fn.csiz = $$->in.type = ctype(LONG);
|
||||
}
|
||||
| FCON
|
||||
{ $$=buildtree(FCON,NIL,NIL);
|
||||
$$->fpn.dval = dcon;
|
||||
}
|
||||
| STRING
|
||||
{ $$ = getstr(); /* get string contents */ }
|
||||
| LP e RP
|
||||
{ $$=$2; }
|
||||
;
|
||||
|
||||
cast_type: type null_decl
|
||||
{
|
||||
$$ = tymerge( $1, $2 );
|
||||
$$->in.op = NAME;
|
||||
$1->in.op = FREE;
|
||||
}
|
||||
;
|
||||
|
||||
null_decl: /* EMPTY */
|
||||
{ $$ = bdty( NAME, NIL, -1 ); }
|
||||
| LP RP
|
||||
{ $$ = bdty( UNARY CALL, bdty(NAME,NIL,-1),0); }
|
||||
| LP null_decl RP LP RP
|
||||
{ $$ = bdty( UNARY CALL, $2, 0 ); }
|
||||
| MUL null_decl
|
||||
{ goto umul; }
|
||||
| null_decl LB RB
|
||||
{ goto uary; }
|
||||
| null_decl LB con_e RB
|
||||
{ goto bary; }
|
||||
| LP null_decl RP
|
||||
{ $$ = $2; }
|
||||
;
|
||||
|
||||
funct_idn: NAME LP
|
||||
{ if( stab[$1].stype == UNDEF ){
|
||||
register NODE *q;
|
||||
q = block( FREE, NIL, NIL, FTN|INT, 0, INT );
|
||||
q->tn.rval = $1;
|
||||
defid( q, EXTERN );
|
||||
}
|
||||
idname = $1;
|
||||
$$=buildtree(NAME,NIL,NIL);
|
||||
stab[idname].suse = -lineno;
|
||||
}
|
||||
| term LP
|
||||
;
|
||||
%%
|
||||
|
||||
NODE *
|
||||
mkty( t, d, s ) unsigned t; {
|
||||
return( block( TYPE, NIL, NIL, t, d, s ) );
|
||||
}
|
||||
|
||||
NODE *
|
||||
bdty( op, p, v ) NODE *p; {
|
||||
register NODE *q;
|
||||
|
||||
q = block( op, p, NIL, INT, 0, INT );
|
||||
|
||||
switch( op ){
|
||||
|
||||
case UNARY MUL:
|
||||
case UNARY CALL:
|
||||
break;
|
||||
|
||||
case LB:
|
||||
q->in.right = bcon(v);
|
||||
break;
|
||||
|
||||
case NAME:
|
||||
q->tn.rval = v;
|
||||
break;
|
||||
|
||||
default:
|
||||
cerror( "bad bdty" );
|
||||
}
|
||||
|
||||
return( q );
|
||||
}
|
||||
|
||||
dstash( n ){ /* put n into the dimension table */
|
||||
if( curdim >= DIMTABSZ-1 ){
|
||||
cerror( "dimension table overflow");
|
||||
}
|
||||
dimtab[ curdim++ ] = n;
|
||||
}
|
||||
|
||||
savebc() {
|
||||
if( psavbc > & asavbc[BCSZ-4 ] ){
|
||||
cerror( "whiles, fors, etc. too deeply nested");
|
||||
}
|
||||
*psavbc++ = brklab;
|
||||
*psavbc++ = contlab;
|
||||
*psavbc++ = flostat;
|
||||
*psavbc++ = swx;
|
||||
flostat = 0;
|
||||
}
|
||||
|
||||
resetbc(mask){
|
||||
|
||||
swx = *--psavbc;
|
||||
flostat = *--psavbc | (flostat&mask);
|
||||
contlab = *--psavbc;
|
||||
brklab = *--psavbc;
|
||||
|
||||
}
|
||||
|
||||
addcase(p) NODE *p; { /* add case to switch */
|
||||
|
||||
p = optim( p ); /* change enum to ints */
|
||||
if( p->in.op != ICON ){
|
||||
uerror( "non-constant case expression");
|
||||
return;
|
||||
}
|
||||
if( swp == swtab ){
|
||||
uerror( "case not in switch");
|
||||
return;
|
||||
}
|
||||
if( swp >= &swtab[SWITSZ] ){
|
||||
cerror( "switch table overflow");
|
||||
}
|
||||
swp->sval = p->tn.lval;
|
||||
deflab( swp->slab = getlab() );
|
||||
++swp;
|
||||
tfree(p);
|
||||
}
|
||||
|
||||
adddef(){ /* add default case to switch */
|
||||
if( swtab[swx].slab >= 0 ){
|
||||
uerror( "duplicate default in switch");
|
||||
return;
|
||||
}
|
||||
if( swp == swtab ){
|
||||
uerror( "default not inside switch");
|
||||
return;
|
||||
}
|
||||
deflab( swtab[swx].slab = getlab() );
|
||||
}
|
||||
|
||||
swstart(){
|
||||
/* begin a switch block */
|
||||
if( swp >= &swtab[SWITSZ] ){
|
||||
cerror( "switch table overflow");
|
||||
}
|
||||
swx = swp - swtab;
|
||||
swp->slab = -1;
|
||||
++swp;
|
||||
}
|
||||
|
||||
swend(){ /* end a switch block */
|
||||
|
||||
register struct sw *swbeg, *p, *q, *r, *r1;
|
||||
CONSZ temp;
|
||||
int tempi;
|
||||
|
||||
swbeg = &swtab[swx+1];
|
||||
|
||||
/* sort */
|
||||
|
||||
r1 = swbeg;
|
||||
r = swp-1;
|
||||
|
||||
while( swbeg < r ){
|
||||
/* bubble largest to end */
|
||||
for( q=swbeg; q<r; ++q ){
|
||||
if( q->sval > (q+1)->sval ){
|
||||
/* swap */
|
||||
r1 = q+1;
|
||||
temp = q->sval;
|
||||
q->sval = r1->sval;
|
||||
r1->sval = temp;
|
||||
tempi = q->slab;
|
||||
q->slab = r1->slab;
|
||||
r1->slab = tempi;
|
||||
}
|
||||
}
|
||||
r = r1;
|
||||
r1 = swbeg;
|
||||
}
|
||||
|
||||
/* it is now sorted */
|
||||
|
||||
for( p = swbeg+1; p<swp; ++p ){
|
||||
if( p->sval == (p-1)->sval ){
|
||||
uerror( "duplicate case in switch, %d",
|
||||
tempi=(int)p->sval );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
reached = 1;
|
||||
genswitch( swbeg-1, (int)(swp-swbeg) );
|
||||
swp = swbeg-1;
|
||||
}
|
||||
Loading…
Reference in New Issue