gbdk-releases/sdcc/src/SDCC.y
2015-01-10 16:25:09 +01:00

1410 lines
42 KiB
Plaintext

/*-----------------------------------------------------------------------
SDCC.y - parser definition file for sdcc :
Written By : Sandeep Dutta . sandeep.dutta@usa.net (1997)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
In other words, you are welcome to use, share and improve this program.
You are forbidden to forbid anyone else to use, share and improve
what you give them. Help stamp out software-hoarding!
-------------------------------------------------------------------------*/
%{
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "SDCCglobl.h"
#include "SDCCsymt.h"
#include "SDCChasht.h"
#include "SDCCval.h"
#include "SDCCmem.h"
#include "SDCCast.h"
#include "port.h"
#include "newalloc.h"
#include "SDCCerr.h"
extern int yyerror (char *);
extern FILE *yyin;
int NestLevel = 0 ; /* current NestLevel */
int stackPtr = 1 ; /* stack pointer */
int xstackPtr = 0 ; /* xstack pointer */
int reentrant = 0 ;
int blockNo = 0 ; /* sequential block number */
int currBlockno=0 ;
extern int yylex();
int yyparse(void);
extern int noLineno ;
char lbuff[1024]; /* local buffer */
/* break & continue stacks */
STACK_DCL(continueStack ,symbol *,MAX_NEST_LEVEL)
STACK_DCL(breakStack ,symbol *,MAX_NEST_LEVEL)
STACK_DCL(forStack ,symbol *,MAX_NEST_LEVEL)
STACK_DCL(swStk ,ast *,MAX_NEST_LEVEL)
STACK_DCL(blockNum,int,MAX_NEST_LEVEL*3)
value *cenum = NULL ; /* current enumeration type chain*/
%}
%expect 6
%union {
symbol *sym ; /* symbol table pointer */
structdef *sdef; /* structure definition */
char yychar[SDCC_NAME_MAX+1];
sym_link *lnk ; /* declarator or specifier */
int yyint; /* integer value returned */
value *val ; /* for integer constant */
initList *ilist; /* initial list */
char *yyinline; /* inlined assembler code */
ast *asts; /* expression tree */
}
%token <yychar> IDENTIFIER TYPE_NAME
%token <val> CONSTANT STRING_LITERAL
%token SIZEOF
%token PTR_OP INC_OP DEC_OP LEFT_OP RIGHT_OP LE_OP GE_OP EQ_OP NE_OP
%token AND_OP OR_OP
%token <yyint> MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
%token <yyint> SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
%token <yyint> XOR_ASSIGN OR_ASSIGN
%token TYPEDEF EXTERN STATIC AUTO REGISTER CODE EEPROM INTERRUPT SFR AT SBIT
%token REENTRANT USING XDATA DATA IDATA PDATA VAR_ARGS CRITICAL NONBANKED BANKED
%token CHAR SHORT INT LONG SIGNED UNSIGNED FLOAT DOUBLE CONST VOLATILE VOID BIT
%token STRUCT UNION ENUM ELIPSIS RANGE FAR
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
%token NAKED
%token <yyinline> INLINEASM
%token IFX ADDRESS_OF GET_VALUE_AT_ADDRESS SPIL UNSPIL GETHBIT
%token BITWISEAND UNARYMINUS IPUSH IPOP PCALL ENDFUNCTION JUMPTABLE
%token RRC RLC
%token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND ARRAYINIT
%type <yyint> Interrupt_storage
%type <sym> identifier declarator declarator2 enumerator_list enumerator
%type <sym> struct_declarator
%type <sym> struct_declarator_list struct_declaration struct_declaration_list
%type <sym> declaration init_declarator_list init_declarator
%type <sym> declaration_list identifier_list parameter_identifier_list
%type <sym> declarator2_function_attributes while do for
%type <lnk> pointer type_specifier_list type_specifier type_name
%type <lnk> storage_class_specifier struct_or_union_specifier
%type <lnk> declaration_specifiers sfr_reg_bit type_specifier2
%type <lnk> function_attribute function_attributes enum_specifier
%type <lnk> abstract_declarator abstract_declarator2 unqualified_pointer
%type <val> parameter_type_list parameter_list parameter_declaration opt_assign_expr
%type <sdef> stag opt_stag
%type <asts> primary_expr
%type <asts> postfix_expr unary_expr cast_expr multiplicative_expr
%type <asts> additive_expr shift_expr relational_expr equality_expr
%type <asts> and_expr exclusive_or_expr inclusive_or_expr logical_or_expr
%type <asts> logical_and_expr conditional_expr assignment_expr constant_expr
%type <asts> expr argument_expr_list function_definition expr_opt
%type <asts> statement_list statement labeled_statement compound_statement
%type <asts> expression_statement selection_statement iteration_statement
%type <asts> jump_statement function_body else_statement string_literal
%type <ilist> initializer initializer_list
%type <yyint> unary_operator assignment_operator struct_or_union
%start file
%%
file
: external_definition
| file external_definition
;
external_definition
: function_definition {
blockNo=0;
}
| declaration {
if ($1 && $1->type
&& IS_FUNC($1->type))
{
/* The only legal storage classes for
* a function prototype (declaration)
* are extern and static. extern is the
* default. Thus, if this function isn't
* explicitly marked static, mark it
* extern.
*/
if ($1->etype
&& IS_SPEC($1->etype)
&& !SPEC_STAT($1->etype))
{
SPEC_EXTR($1->etype) = 1;
}
}
addSymChain ($1);
allocVariables ($1) ;
cleanUpLevel (SymbolTab,1);
}
;
function_definition
: declarator function_body { /* function type not specified */
/* assume it to be 'int' */
addDecl($1,0,newIntLink());
$$ = createFunction($1,$2);
}
| declaration_specifiers declarator function_body
{
pointerTypes($2->type,copyLinkChain($1));
addDecl($2,0,$1);
$$ = createFunction($2,$3);
}
;
function_attribute
: function_attributes
| function_attributes function_attribute { $$ = mergeSpec($1,$2,"function_attribute"); }
;
function_attributes
: USING CONSTANT {
$$ = newLink() ;
$$->class = SPECIFIER ;
FUNC_REGBANK($$) = (int) floatFromVal($2);
}
| REENTRANT { $$ = newLink ();
$$->class = SPECIFIER ;
FUNC_ISREENT($$)=1;
}
| CRITICAL { $$ = newLink ();
$$->class = SPECIFIER ;
FUNC_ISCRITICAL($$) = 1;
}
| NAKED { $$ = newLink ();
$$->class = SPECIFIER ;
FUNC_ISNAKED($$)=1;
}
| NONBANKED {$$ = newLink ();
$$->class = SPECIFIER ;
FUNC_NONBANKED($$) = 1;
if (FUNC_BANKED($$)) {
werror(W_BANKED_WITH_NONBANKED);
}
}
| BANKED {$$ = newLink ();
$$->class = SPECIFIER ;
FUNC_BANKED($$) = 1;
if (FUNC_NONBANKED($$)) {
werror(W_BANKED_WITH_NONBANKED);
}
if (SPEC_STAT($$)) {
werror(W_BANKED_WITH_STATIC);
}
}
| Interrupt_storage
{
$$ = newLink () ;
$$->class = SPECIFIER ;
FUNC_INTNO($$) = $1 ;
FUNC_ISISR($$) = 1;
}
;
function_body
: compound_statement
| declaration_list compound_statement
{
werror(E_OLD_STYLE,($1 ? $1->name: "")) ;
exit(1);
}
;
primary_expr
: identifier { $$ = newAst_VALUE(symbolVal($1)); }
| CONSTANT { $$ = newAst_VALUE($1); }
| string_literal
| '(' expr ')' { $$ = $2 ; }
;
string_literal
: STRING_LITERAL { $$ = newAst_VALUE($1); }
;
postfix_expr
: primary_expr
| postfix_expr '[' expr ']' { $$ = newNode ('[', $1, $3) ; }
| postfix_expr '(' ')' { $$ = newNode (CALL,$1,NULL);
$$->left->funcName = 1;}
| postfix_expr '(' argument_expr_list ')'
{
$$ = newNode (CALL,$1,$3) ; $$->left->funcName = 1;
}
| postfix_expr '.' identifier
{
$3 = newSymbol($3->name,NestLevel);
$3->implicit = 1;
$$ = newNode(PTR_OP,newNode('&',$1,NULL),newAst_VALUE(symbolVal($3)));
/* $$ = newNode('.',$1,newAst(EX_VALUE,symbolVal($3))) ; */
}
| postfix_expr PTR_OP identifier
{
$3 = newSymbol($3->name,NestLevel);
$3->implicit = 1;
$$ = newNode(PTR_OP,$1,newAst_VALUE(symbolVal($3)));
}
| postfix_expr INC_OP
{ $$ = newNode(INC_OP,$1,NULL);}
| postfix_expr DEC_OP
{ $$ = newNode(DEC_OP,$1,NULL); }
;
argument_expr_list
: assignment_expr
| assignment_expr ',' argument_expr_list { $$ = newNode(PARAM,$1,$3); }
;
unary_expr
: postfix_expr
| INC_OP unary_expr { $$ = newNode(INC_OP,NULL,$2); }
| DEC_OP unary_expr { $$ = newNode(DEC_OP,NULL,$2); }
| unary_operator cast_expr { $$ = newNode($1,$2,NULL) ; }
| SIZEOF unary_expr { $$ = newNode(SIZEOF,NULL,$2); }
| SIZEOF '(' type_name ')' { $$ = newAst_VALUE(sizeofOp($3)); }
;
unary_operator
: '&' { $$ = '&' ;}
| '*' { $$ = '*' ;}
| '+' { $$ = '+' ;}
| '-' { $$ = '-' ;}
| '~' { $$ = '~' ;}
| '!' { $$ = '!' ;}
;
cast_expr
: unary_expr
| '(' type_name ')' cast_expr { $$ = newNode(CAST,newAst_LINK($2),$4); }
;
multiplicative_expr
: cast_expr
| multiplicative_expr '*' cast_expr { $$ = newNode('*',$1,$3);}
| multiplicative_expr '/' cast_expr { $$ = newNode('/',$1,$3);}
| multiplicative_expr '%' cast_expr { $$ = newNode('%',$1,$3);}
;
additive_expr
: multiplicative_expr
| additive_expr '+' multiplicative_expr { $$=newNode('+',$1,$3);}
| additive_expr '-' multiplicative_expr { $$=newNode('-',$1,$3);}
;
shift_expr
: additive_expr
| shift_expr LEFT_OP additive_expr { $$ = newNode(LEFT_OP,$1,$3); }
| shift_expr RIGHT_OP additive_expr { $$ = newNode(RIGHT_OP,$1,$3); }
;
relational_expr
: shift_expr
| relational_expr '<' shift_expr {
$$ = (port->lt_nge ?
newNode('!',newNode(GE_OP,$1,$3),NULL) :
newNode('<', $1,$3));
}
| relational_expr '>' shift_expr {
$$ = (port->gt_nle ?
newNode('!',newNode(LE_OP,$1,$3),NULL) :
newNode('>',$1,$3));
}
| relational_expr LE_OP shift_expr {
$$ = (port->le_ngt ?
newNode('!', newNode('>', $1 , $3 ), NULL) :
newNode(LE_OP,$1,$3));
}
| relational_expr GE_OP shift_expr {
$$ = (port->ge_nlt ?
newNode('!', newNode('<', $1 , $3 ), NULL) :
newNode(GE_OP,$1,$3));
}
;
equality_expr
: relational_expr
| equality_expr EQ_OP relational_expr {
$$ = (port->eq_nne ?
newNode('!',newNode(NE_OP,$1,$3),NULL) :
newNode(EQ_OP,$1,$3));
}
| equality_expr NE_OP relational_expr {
$$ = (port->ne_neq ?
newNode('!', newNode(EQ_OP,$1,$3), NULL) :
newNode(NE_OP,$1,$3));
}
;
and_expr
: equality_expr
| and_expr '&' equality_expr { $$ = newNode('&',$1,$3);}
;
exclusive_or_expr
: and_expr
| exclusive_or_expr '^' and_expr { $$ = newNode('^',$1,$3);}
;
inclusive_or_expr
: exclusive_or_expr
| inclusive_or_expr '|' exclusive_or_expr { $$ = newNode('|',$1,$3);}
;
logical_and_expr
: inclusive_or_expr
| logical_and_expr AND_OP inclusive_or_expr
{ $$ = newNode(AND_OP,$1,$3);}
;
logical_or_expr
: logical_and_expr
| logical_or_expr OR_OP logical_and_expr
{ $$ = newNode(OR_OP,$1,$3); }
;
conditional_expr
: logical_or_expr
| logical_or_expr '?' logical_or_expr ':' conditional_expr
{
$$ = newNode(':',$3,$5) ;
$$ = newNode('?',$1,$$) ;
}
;
assignment_expr
: conditional_expr
| unary_expr assignment_operator assignment_expr
{
switch ($2) {
case '=':
$$ = newNode($2,$1,$3);
break;
case MUL_ASSIGN:
$$ = newNode('=',$1,newNode('*',copyAst($1),$3));
break;
case DIV_ASSIGN:
$$ = newNode('=',$1,newNode('/',copyAst($1),$3));
break;
case MOD_ASSIGN:
$$ = newNode('=',$1,newNode('%',copyAst($1),$3));
break;
case ADD_ASSIGN:
$$ = newNode('=',$1,newNode('+',copyAst($1),$3));
break;
case SUB_ASSIGN:
$$ = newNode('=',$1,newNode('-',copyAst($1),$3));
break;
case LEFT_ASSIGN:
$$ = newNode('=',$1,newNode(LEFT_OP,copyAst($1),$3));
break;
case RIGHT_ASSIGN:
$$ = newNode('=',$1,newNode(RIGHT_OP,copyAst($1),$3));
break;
case AND_ASSIGN:
$$ = newNode('=',$1,newNode('&',copyAst($1),$3));
break;
case XOR_ASSIGN:
$$ = newNode('=',$1,newNode('^',copyAst($1),$3));
break;
case OR_ASSIGN:
$$ = newNode('=',$1,newNode('|',copyAst($1),$3));
break;
default :
$$ = NULL;
}
}
;
assignment_operator
: '=' { $$ = '=' ;}
| MUL_ASSIGN
| DIV_ASSIGN
| MOD_ASSIGN
| ADD_ASSIGN
| SUB_ASSIGN
| LEFT_ASSIGN
| RIGHT_ASSIGN
| AND_ASSIGN
| XOR_ASSIGN
| OR_ASSIGN
;
expr
: assignment_expr
| expr ',' assignment_expr { $$ = newNode(',',$1,$3);}
;
constant_expr
: conditional_expr
;
declaration
: declaration_specifiers ';' { $$ = NULL ; }
| declaration_specifiers init_declarator_list ';'
{
/* add the specifier list to the id */
symbol *sym , *sym1;
for (sym1 = sym = reverseSyms($2);sym != NULL;sym = sym->next) {
sym_link *lnk = copyLinkChain($1);
/* do the pointer stuff */
pointerTypes(sym->type,lnk);
addDecl (sym,0,lnk) ;
}
$$ = sym1 ;
}
;
declaration_specifiers
: storage_class_specifier { $$ = $1; }
| storage_class_specifier declaration_specifiers {
/* if the decl $2 is not a specifier */
/* find the spec and replace it */
if ( !IS_SPEC($2)) {
sym_link *lnk = $2 ;
while (lnk && !IS_SPEC(lnk->next))
lnk = lnk->next;
lnk->next = mergeSpec($1,lnk->next, yytext);
$$ = $2 ;
}
else
$$ = mergeSpec($1,$2, yytext);
}
| type_specifier { $$ = $1; }
| type_specifier declaration_specifiers {
/* if the decl $2 is not a specifier */
/* find the spec and replace it */
if ( !IS_SPEC($2)) {
sym_link *lnk = $2 ;
while (lnk && !IS_SPEC(lnk->next))
lnk = lnk->next;
lnk->next = mergeSpec($1,lnk->next, yytext);
$$ = $2 ;
}
else
$$ = mergeSpec($1,$2, yytext);
}
;
init_declarator_list
: init_declarator
| init_declarator_list ',' init_declarator { $3->next = $1 ; $$ = $3;}
;
init_declarator
: declarator { $1->ival = NULL ; }
| declarator '=' initializer { $1->ival = $3 ; }
;
storage_class_specifier
: TYPEDEF {
$$ = newLink () ;
$$->class = SPECIFIER ;
SPEC_TYPEDEF($$) = 1 ;
}
| EXTERN {
$$ = newLink();
$$->class = SPECIFIER ;
SPEC_EXTR($$) = 1 ;
}
| STATIC {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_STAT($$) = 1 ;
}
| AUTO {
$$ = newLink () ;
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_AUTO ;
}
| REGISTER {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_REGISTER ;
}
;
Interrupt_storage
: INTERRUPT CONSTANT { $$ = (int) floatFromVal($2) ; }
;
type_specifier
: type_specifier2
| type_specifier2 AT constant_expr
{
/* add this to the storage class specifier */
SPEC_ABSA($1) = 1; /* set the absolute addr flag */
/* now get the abs addr from value */
SPEC_ADDR($1) = (int) floatFromVal(constExprValue($3,TRUE)) ;
}
;
type_specifier2
: CHAR {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_CHAR ;
}
| SHORT {
$$=newLink();
$$->class = SPECIFIER ;
$$->select.s._short = 1 ;
}
| INT {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_INT ;
}
| LONG {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_LONG($$) = 1 ;
}
| SIGNED {
$$=newLink();
$$->class = SPECIFIER ;
$$->select.s._signed = 1;
}
| UNSIGNED {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_USIGN($$) = 1 ;
}
| VOID {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_VOID ;
}
| CONST {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_CONST($$) = 1;
}
| VOLATILE {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_VOLATILE($$) = 1 ;
}
| FLOAT {
$$=newLink();
SPEC_NOUN($$) = V_FLOAT;
$$->class = SPECIFIER ;
}
| XDATA {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_XDATA ;
}
| CODE {
$$ = newLink () ;
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_CODE ;
}
| EEPROM {
$$ = newLink () ;
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_EEPROM ;
}
| DATA {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_DATA ;
}
| IDATA {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_IDATA ;
}
| PDATA {
$$ = newLink ();
$$->class = SPECIFIER ;
SPEC_SCLS($$) = S_PDATA ;
}
| BIT {
$$=newLink();
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_BIT ;
SPEC_SCLS($$) = S_BIT ;
SPEC_BLEN($$) = 1;
SPEC_BSTR($$) = 0;
}
| struct_or_union_specifier
| enum_specifier {
cenum = NULL ;
$$ = $1 ;
}
| TYPE_NAME
{
symbol *sym;
sym_link *p ;
sym = findSym(TypedefTab,NULL,$1) ;
$$ = p = copyLinkChain(sym->type);
SPEC_TYPEDEF(getSpec(p)) = 0;
}
| sfr_reg_bit
;
sfr_reg_bit
: SBIT {
$$ = newLink() ;
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_SBIT;
SPEC_SCLS($$) = S_SBIT;
}
| SFR {
$$ = newLink() ;
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_CHAR;
SPEC_SCLS($$) = S_SFR ;
SPEC_USIGN($$) = 1 ;
}
;
struct_or_union_specifier
: struct_or_union opt_stag '{' struct_declaration_list '}'
{
structdef *sdef ;
/* Create a structdef */
sdef = $2 ;
sdef->fields = reverseSyms($4) ; /* link the fields */
sdef->size = compStructSize($1,sdef); /* update size of */
/* Create the specifier */
$$ = newLink () ;
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_STRUCT;
SPEC_STRUCT($$)= sdef ;
}
| struct_or_union stag
{
$$ = newLink() ;
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_STRUCT;
SPEC_STRUCT($$) = $2 ;
}
;
struct_or_union
: STRUCT { $$ = STRUCT ; }
| UNION { $$ = UNION ; }
;
opt_stag
: stag
| { /* synthesize a name add to structtable */
$$ = newStruct(genSymName(NestLevel)) ;
$$->level = NestLevel ;
addSym (StructTab, $$, $$->tag,$$->level,currBlockno, 0);
};
stag
: identifier { /* add name to structure table */
$$ = findSymWithBlock (StructTab,$1,currBlockno);
if (! $$ ) {
$$ = newStruct($1->name) ;
$$->level = NestLevel ;
addSym (StructTab, $$, $$->tag,$$->level,currBlockno,0);
}
};
struct_declaration_list
: struct_declaration
| struct_declaration_list struct_declaration
{
symbol *sym = $2;
/* go to the end of the chain */
while (sym->next) sym = sym->next;
sym->next = $1 ;
$$ = $2;
}
;
struct_declaration
: type_specifier_list struct_declarator_list ';'
{
/* add this type to all the symbols */
symbol *sym ;
for ( sym = $2 ; sym != NULL ; sym = sym->next ) {
/* make the symbol one level up */
sym->level-- ;
pointerTypes(sym->type,copyLinkChain($1));
if (!sym->type) {
sym->type = copyLinkChain($1);
sym->etype = getSpec(sym->type);
}
else
addDecl (sym,0,cloneSpec($1));
/* make sure the type is complete and sane */
checkTypeSanity(sym->etype, sym->name);
}
$$ = $2;
}
;
struct_declarator_list
: struct_declarator
| struct_declarator_list ',' struct_declarator
{
$3->next = $1 ;
$$ = $3 ;
}
;
struct_declarator
: declarator
| ':' constant_expr {
$$ = newSymbol (genSymName(NestLevel),NestLevel) ;
$$->bitVar = (int) floatFromVal(constExprValue($2,TRUE));
}
| declarator ':' constant_expr
{
$1->bitVar = (int) floatFromVal(constExprValue($3,TRUE));
}
;
enum_specifier
: ENUM '{' enumerator_list '}' {
addSymChain ($3);
allocVariables(reverseSyms($3)) ;
$$ = copyLinkChain(cenum->type);
}
| ENUM identifier '{' enumerator_list '}' {
symbol *csym ;
$2->type = copyLinkChain(cenum->type);
$2->etype = getSpec($2->type);
/* add this to the enumerator table */
if (!(csym=findSym(enumTab,$2,$2->name)) &&
(csym && csym->level == $2->level))
werror(E_DUPLICATE_TYPEDEF,csym->name);
addSym ( enumTab,$2,$2->name,$2->level,$2->block, 0);
addSymChain ($4);
allocVariables (reverseSyms($4));
$$ = copyLinkChain(cenum->type);
SPEC_SCLS(getSpec($$)) = 0 ;
}
| ENUM identifier {
symbol *csym ;
/* check the enumerator table */
if ((csym = findSym(enumTab,$2,$2->name)))
$$ = copyLinkChain(csym->type);
else {
$$ = newLink() ;
$$->class = SPECIFIER ;
SPEC_NOUN($$) = V_INT ;
}
SPEC_SCLS(getSpec($$)) = 0 ;
}
;
enumerator_list
: enumerator
| enumerator_list ',' {
}
| enumerator_list ',' enumerator {
$3->next = $1 ;
$$ = $3 ;
}
;
enumerator
: identifier opt_assign_expr {
/* make the symbol one level up */
$1->level-- ;
$1->type = copyLinkChain($2->type);
$1->etype= getSpec($1->type);
SPEC_ENUM($1->etype) = 1;
$$ = $1 ;
}
;
opt_assign_expr
: '=' constant_expr {
value *val ;
val = constExprValue($2,TRUE);
$$ = cenum = val ;
}
| {
if (cenum) {
sprintf(lbuff,"%d",(int) floatFromVal(cenum)+1);
$$ = cenum = constVal(lbuff);
}
else {
sprintf(lbuff,"%d",0);
$$ = cenum = constVal(lbuff);
}
}
;
declarator
: declarator2_function_attributes { $$ = $1; }
| pointer declarator2_function_attributes
{
addDecl ($2,0,reverseLink($1));
$$ = $2 ;
}
;
declarator2_function_attributes
: declarator2 { $$ = $1 ; }
| declarator2 function_attribute {
// copy the functionAttributes (not the args and hasVargs !!)
sym_link *funcType=$1->etype;
struct value *args=FUNC_ARGS(funcType);
unsigned hasVargs=FUNC_HASVARARGS(funcType);
memcpy (&funcType->funcAttrs, &$2->funcAttrs,
sizeof($2->funcAttrs));
FUNC_ARGS(funcType)=args;
FUNC_HASVARARGS(funcType)=hasVargs;
// just to be sure
memset (&$2->funcAttrs, 0,
sizeof($2->funcAttrs));
addDecl ($1,0,$2);
}
;
declarator2
: identifier
| '(' declarator ')' { $$ = $2; }
| declarator2 '[' ']'
{
sym_link *p;
p = newLink ();
DCL_TYPE(p) = ARRAY ;
DCL_ELEM(p) = 0 ;
addDecl($1,0,p);
}
| declarator2 '[' constant_expr ']'
{
sym_link *p ;
value *tval;
p = (tval = constExprValue($3,TRUE))->etype;
/* if it is not a constant then Error */
if ( SPEC_SCLS(p) != S_LITERAL)
werror(E_CONST_EXPECTED) ;
else {
p = newLink ();
DCL_TYPE(p) = ARRAY ;
DCL_ELEM(p) = (int) floatFromVal(tval) ;
addDecl($1,0,p);
}
}
| declarator2 '(' ')' { addDecl ($1,FUNCTION,NULL) ; }
| declarator2 '(' { NestLevel++ ; currBlockno++; } parameter_type_list ')'
{
addDecl ($1,FUNCTION,NULL) ;
FUNC_HASVARARGS($1->type) = IS_VARG($4);
FUNC_ARGS($1->type) = reverseVal($4);
/* nest level was incremented to take care of the parms */
NestLevel-- ;
currBlockno--;
// if this was a pointer (to a function)
if (IS_PTR($1->type)) {
// move the args and hasVargs to the function
FUNC_ARGS($1->etype)=FUNC_ARGS($1->type);
FUNC_HASVARARGS($1->etype)=FUNC_HASVARARGS($1->type);
memset (&$1->type->funcAttrs, 0,
sizeof($1->type->funcAttrs));
// remove the symbol args (if any)
cleanUpLevel(SymbolTab,NestLevel+1);
}
$$ = $1;
}
| declarator2 '(' parameter_identifier_list ')'
{
werror(E_OLD_STYLE,$1->name) ;
/* assume it returns an int */
$1->type = $1->etype = newIntLink();
$$ = $1 ;
}
;
pointer
: unqualified_pointer { $$ = $1 ;}
| unqualified_pointer type_specifier_list
{
$$ = $1 ;
DCL_TSPEC($1) = $2;
}
| unqualified_pointer pointer
{
$$ = $1 ;
$$->next = $2 ;
DCL_TYPE($2)=GPOINTER;
}
| unqualified_pointer type_specifier_list pointer
{
$$ = $1 ;
if (IS_SPEC($2) && DCL_TYPE($3) == UPOINTER) {
DCL_PTR_CONST($1) = SPEC_CONST($2);
DCL_PTR_VOLATILE($1) = SPEC_VOLATILE($2);
switch (SPEC_SCLS($2)) {
case S_XDATA:
DCL_TYPE($3) = FPOINTER;
break;
case S_IDATA:
DCL_TYPE($3) = IPOINTER ;
break;
case S_PDATA:
DCL_TYPE($3) = PPOINTER ;
break;
case S_DATA:
DCL_TYPE($3) = POINTER ;
break;
case S_CODE:
DCL_PTR_CONST($3) = 1;
DCL_TYPE($3) = CPOINTER ;
break;
case S_EEPROM:
DCL_TYPE($3) = EEPPOINTER;
break;
default:
// this could be just "constant"
// werror(W_PTR_TYPE_INVALID);
}
}
else
werror (W_PTR_TYPE_INVALID);
$$->next = $3 ;
}
;
unqualified_pointer
: '*'
{
$$ = newLink();
DCL_TYPE($$)=UPOINTER;
}
;
type_specifier_list
: type_specifier
//| type_specifier_list type_specifier { $$ = mergeSpec ($1,$2, "type_specifier_list"); }
| type_specifier_list type_specifier {
/* if the decl $2 is not a specifier */
/* find the spec and replace it */
if ( !IS_SPEC($2)) {
sym_link *lnk = $2 ;
while (lnk && !IS_SPEC(lnk->next))
lnk = lnk->next;
lnk->next = mergeSpec($1,lnk->next, "type_specifier_list");
$$ = $2 ;
}
else
$$ = mergeSpec($1,$2, "type_specifier_list");
}
;
parameter_identifier_list
: identifier_list
| identifier_list ',' ELIPSIS
;
identifier_list
: identifier
| identifier_list ',' identifier
{
$3->next = $1;
$$ = $3 ;
}
;
parameter_type_list
: parameter_list
| parameter_list ',' VAR_ARGS { $1->vArgs = 1;}
;
parameter_list
: parameter_declaration
| parameter_list ',' parameter_declaration
{
$3->next = $1 ;
$$ = $3 ;
}
;
parameter_declaration
: type_specifier_list declarator
{
symbol *loop ;
pointerTypes($2->type,$1);
addDecl ($2,0,$1);
for (loop=$2;loop;loop->_isparm=1,loop=loop->next);
addSymChain ($2);
$$ = symbolVal($2);
}
| type_name {
$$ = newValue() ;
$$->type = $1;
$$->etype = getSpec($$->type);
}
;
type_name
: type_specifier_list { $$ = $1 ;}
| type_specifier_list abstract_declarator
{
/* go to the end of the list */
sym_link *p;
pointerTypes($2,$1);
for ( p = $2 ; p->next ; p=p->next);
p->next = $1 ;
$$ = $2 ;
}
;
abstract_declarator
: pointer { $$ = reverseLink($1); }
| abstract_declarator2
| pointer abstract_declarator2 { $1 = reverseLink($1); $1->next = $2 ; $$ = $1;}
;
abstract_declarator2
: '(' abstract_declarator ')' { $$ = $2 ; }
| '[' ']' {
$$ = newLink ();
DCL_TYPE($$) = ARRAY ;
DCL_ELEM($$) = 0 ;
}
| '[' constant_expr ']' {
value *val ;
$$ = newLink ();
DCL_TYPE($$) = ARRAY ;
DCL_ELEM($$) = (int) floatFromVal(val = constExprValue($2,TRUE));
}
| abstract_declarator2 '[' ']' {
$$ = newLink ();
DCL_TYPE($$) = ARRAY ;
DCL_ELEM($$) = 0 ;
$$->next = $1 ;
}
| abstract_declarator2 '[' constant_expr ']'
{
value *val ;
$$ = newLink ();
DCL_TYPE($$) = ARRAY ;
DCL_ELEM($$) = (int) floatFromVal(val = constExprValue($3,TRUE));
$$->next = $1 ;
}
| '(' ')' { $$ = NULL;}
| '(' parameter_type_list ')' { $$ = NULL;}
| abstract_declarator2 '(' ')' {
// $1 must be a pointer to a function
sym_link *p=newLink();
DCL_TYPE(p) = FUNCTION;
$1->next=p;
}
| abstract_declarator2 '(' parameter_type_list ')' {
if (!IS_VOID($3->type)) {
// this is nonsense, so let's just burp something
werror(E_TOO_FEW_PARMS);
} else {
// $1 must be a pointer to a function
sym_link *p=newLink();
DCL_TYPE(p) = FUNCTION;
$1->next=p;
}
}
initializer
: assignment_expr { $$ = newiList(INIT_NODE,$1); }
| '{' initializer_list '}' { $$ = newiList(INIT_DEEP,revinit($2)); }
| '{' initializer_list ',' '}' { $$ = newiList(INIT_DEEP,revinit($2)); }
;
initializer_list
: initializer
| initializer_list ',' initializer { $3->next = $1; $$ = $3; }
;
statement
: labeled_statement
| compound_statement
| expression_statement
| selection_statement
| iteration_statement
| jump_statement
| INLINEASM ';' {
ast *ex = newNode(INLINEASM,NULL,NULL);
ex->values.inlineasm = malloc(strlen($1)+1);
strcpy(ex->values.inlineasm,$1);
$$ = ex;
}
;
labeled_statement
// : identifier ':' statement { $$ = createLabel($1,$3); }
: identifier ':' { $$ = createLabel($1,NULL); }
| CASE constant_expr ':' statement { $$ = createCase(STACK_PEEK(swStk),$2,$4); }
| DEFAULT ':' statement { $$ = createDefault(STACK_PEEK(swStk),$3); }
;
start_block : '{' { STACK_PUSH(blockNum,currBlockno); currBlockno = ++blockNo ; }
;
end_block : '}' { currBlockno = STACK_POP(blockNum); }
;
compound_statement
: start_block end_block { $$ = createBlock(NULL,NULL); }
| start_block statement_list end_block { $$ = createBlock(NULL,$2) ; }
| start_block
declaration_list { addSymChain($2); }
end_block { $$ = createBlock($2,NULL) ; }
| start_block
declaration_list { addSymChain ($2); }
statement_list
end_block {$$ = createBlock($2,$4) ; }
| error ';' { $$ = NULL ; }
;
declaration_list
: declaration
{
/* if this is typedef declare it immediately */
if ( $1 && IS_TYPEDEF($1->etype)) {
allocVariables ($1);
$$ = NULL ;
}
else
$$ = $1 ;
}
| declaration_list declaration
{
symbol *sym;
/* if this is a typedef */
if ($2 && IS_TYPEDEF($2->etype)) {
allocVariables ($2);
$$ = $1 ;
}
else {
/* get to the end of the previous decl */
if ( $1 ) {
$$ = sym = $1 ;
while (sym->next)
sym = sym->next ;
sym->next = $2;
}
else
$$ = $2 ;
}
}
;
statement_list
: statement
| statement_list statement { $$ = newNode(NULLOP,$1,$2) ;}
;
expression_statement
: ';' { $$ = NULL;}
| expr ';'
;
else_statement
: ELSE statement { $$ = $2 ; }
| { $$ = NULL;}
;
selection_statement
: IF '(' expr ')' statement else_statement { noLineno++ ; $$ = createIf ($3, $5, $6 ); noLineno--;}
| SWITCH '(' expr ')' {
ast *ex ;
static int swLabel = 0 ;
/* create a node for expression */
ex = newNode(SWITCH,$3,NULL);
STACK_PUSH(swStk,ex); /* save it in the stack */
ex->values.switchVals.swNum = swLabel ;
/* now create the label */
sprintf(lbuff,"_swBrk_%d",swLabel++);
$<sym>$ = newSymbol(lbuff,NestLevel);
/* put label in the break stack */
STACK_PUSH(breakStack,$<sym>$);
}
statement {
/* get back the switch form the stack */
$$ = STACK_POP(swStk) ;
$$->right = newNode (NULLOP,$6,createLabel($<sym>5,NULL));
STACK_POP(breakStack);
}
;
while : WHILE { /* create and push the continue , break & body labels */
static int Lblnum = 0 ;
/* continue */
sprintf (lbuff,"_whilecontinue_%d",Lblnum);
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
/* break */
sprintf (lbuff,"_whilebreak_%d",Lblnum);
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
/* body */
sprintf (lbuff,"_whilebody_%d",Lblnum++);
$$ = newSymbol(lbuff,NestLevel);
}
do : DO { /* create and push the continue , break & body Labels */
static int Lblnum = 0 ;
/* continue */
sprintf(lbuff,"_docontinue_%d",Lblnum);
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
/* break */
sprintf (lbuff,"_dobreak_%d",Lblnum);
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
/* do body */
sprintf (lbuff,"_dobody_%d",Lblnum++);
$$ = newSymbol (lbuff,NestLevel);
}
for : FOR { /* create & push continue, break & body labels */
static int Lblnum = 0 ;
/* continue */
sprintf (lbuff,"_forcontinue_%d",Lblnum);
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
/* break */
sprintf (lbuff,"_forbreak_%d",Lblnum);
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
/* body */
sprintf (lbuff,"_forbody_%d",Lblnum);
$$ = newSymbol(lbuff,NestLevel);
/* condition */
sprintf (lbuff,"_forcond_%d",Lblnum++);
STACK_PUSH(forStack,newSymbol(lbuff,NestLevel));
}
iteration_statement
: while '(' expr ')' statement
{
noLineno++ ;
$$ = createWhile ( $1, STACK_POP(continueStack),
STACK_POP(breakStack), $3, $5 );
$$->lineno = $1->lineDef ;
noLineno-- ;
}
| do statement WHILE '(' expr ')' ';'
{
noLineno++ ;
$$ = createDo ( $1 , STACK_POP(continueStack),
STACK_POP(breakStack), $5, $2);
$$->lineno = $1->lineDef ;
noLineno-- ;
}
| for '(' expr_opt ';' expr_opt ';' expr_opt ')' statement
{
noLineno++ ;
/* if break or continue statement present
then create a general case loop */
if (STACK_PEEK(continueStack)->isref ||
STACK_PEEK(breakStack)->isref) {
$$ = createFor ($1, STACK_POP(continueStack),
STACK_POP(breakStack) ,
STACK_POP(forStack) ,
$3 , $5 , $7, $9 );
} else {
$$ = newNode(FOR,$9,NULL);
AST_FOR($$,trueLabel) = $1;
AST_FOR($$,continueLabel) = STACK_POP(continueStack);
AST_FOR($$,falseLabel) = STACK_POP(breakStack);
AST_FOR($$,condLabel) = STACK_POP(forStack) ;
AST_FOR($$,initExpr) = $3;
AST_FOR($$,condExpr) = $5;
AST_FOR($$,loopExpr) = $7;
}
noLineno-- ;
}
;
expr_opt
: { $$ = NULL ; }
| expr
;
jump_statement
: GOTO identifier ';' {
$2->islbl = 1;
$$ = newAst_VALUE(symbolVal($2));
$$ = newNode(GOTO,$$,NULL);
}
| CONTINUE ';' {
/* make sure continue is in context */
if (STACK_PEEK(continueStack) == NULL) {
werror(E_BREAK_CONTEXT);
$$ = NULL;
}
else {
$$ = newAst_VALUE(symbolVal(STACK_PEEK(continueStack)));
$$ = newNode(GOTO,$$,NULL);
/* mark the continue label as referenced */
STACK_PEEK(continueStack)->isref = 1;
}
}
| BREAK ';' {
if (STACK_PEEK(breakStack) == NULL) {
werror(E_BREAK_CONTEXT);
$$ = NULL;
} else {
$$ = newAst_VALUE(symbolVal(STACK_PEEK(breakStack)));
$$ = newNode(GOTO,$$,NULL);
STACK_PEEK(breakStack)->isref = 1;
}
}
| RETURN ';' { $$ = newNode(RETURN,NULL,NULL) ; }
| RETURN expr ';' { $$ = newNode(RETURN,NULL,$2) ; }
;
identifier
: IDENTIFIER { $$ = newSymbol ($1,NestLevel) ; }
;
%%