2466 lines
80 KiB
Plaintext
2466 lines
80 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"
|
|
#include "SDCCutil.h"
|
|
#include "SDCCbtree.h"
|
|
#include "SDCCopt.h"
|
|
|
|
extern int yyerror (char *);
|
|
extern FILE *yyin;
|
|
long 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;
|
|
int inCriticalFunction = 0;
|
|
int inCriticalBlock = 0;
|
|
int seqPointNo= 1; /* sequence point number */
|
|
int ignoreTypedefType=0;
|
|
extern int yylex();
|
|
int yyparse(void);
|
|
extern int noLineno;
|
|
char lbuff[1024]; /* local buffer */
|
|
char function_name[256] = {0};
|
|
|
|
/* 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*/
|
|
bool uselessDecl = TRUE;
|
|
|
|
#define YYDEBUG 1
|
|
|
|
%}
|
|
%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 */
|
|
designation*dsgn; /* designator */
|
|
const char *yystr; /* pointer to dynamicaly allocated string */
|
|
ast *asts; /* expression tree */
|
|
}
|
|
|
|
%token <yychar> IDENTIFIER TYPE_NAME ADDRSPACE_NAME
|
|
%token <val> CONSTANT
|
|
%token SIZEOF ALIGNOF TYPEOF OFFSETOF
|
|
%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 SFR16 SFR32 ADDRESSMOD STATIC_ASSERT
|
|
%token AT SBIT REENTRANT USING XDATA DATA IDATA PDATA VAR_ARGS CRITICAL
|
|
%token NONBANKED BANKED SHADOWREGS SD_WPARAM
|
|
%token SD_BOOL SD_CHAR SD_SHORT SD_INT SD_LONG SIGNED UNSIGNED SD_FLOAT DOUBLE FIXED16X16 SD_CONST VOLATILE SD_VOID BIT
|
|
%token STRUCT UNION ENUM RANGE SD_FAR
|
|
%token CASE DEFAULT IF ELSE SWITCH WHILE DO FOR GOTO CONTINUE BREAK RETURN
|
|
%token NAKED JAVANATIVE OVERLAY TRAP
|
|
%token <yystr> STRING_LITERAL INLINEASM
|
|
%token IFX ADDRESS_OF GET_VALUE_AT_ADDRESS SET_VALUE_AT_ADDRESS SPIL UNSPIL GETHBIT GETABIT GETBYTE GETWORD
|
|
%token BITWISEAND UNARYMINUS IPUSH IPOP PCALL ENDFUNCTION JUMPTABLE
|
|
%token RRC RLC
|
|
%token CAST CALL PARAM NULLOP BLOCK LABEL RECEIVE SEND ARRAYINIT
|
|
%token DUMMY_READ_VOLATILE ENDCRITICAL SWAP INLINE NORETURN RESTRICT SMALLC PRESERVES_REGS Z88DK_FASTCALL Z88DK_CALLEE ALIGNAS Z88DK_SHORTCALL Z88DK_PARAMS_OFFSET
|
|
%token GENERIC GENERIC_ASSOC_LIST GENERIC_ASSOCIATION
|
|
%token ASM
|
|
|
|
%type <yyint> Interrupt_storage
|
|
%type <sym> identifier declarator declarator2 declarator3 enumerator_list enumerator
|
|
%type <sym> struct_declarator function_declarator function_declarator2
|
|
%type <sym> struct_declarator_list struct_declaration struct_declaration_list
|
|
%type <sym> declaration init_declarator_list init_declarator
|
|
%type <sym> declaration_list identifier_list
|
|
%type <sym> declaration_after_statement
|
|
%type <sym> declarator2_function_attributes while do for critical
|
|
%type <sym> addressmod
|
|
%type <lnk> pointer type_specifier_list type_specifier_list_ type_specifier type_qualifier_list type_qualifier type_name
|
|
%type <lnk> storage_class_specifier struct_or_union_specifier function_specifier alignment_specifier
|
|
%type <lnk> declaration_specifiers declaration_specifiers_ sfr_reg_bit sfr_attributes
|
|
%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 offsetof_member_designator 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_val
|
|
%type <asts> critical_statement asm_statement label
|
|
%type <asts> generic_selection generic_assoc_list generic_association
|
|
%type <asts> implicit_block statements_and_implicit block_item_list
|
|
%type <dsgn> designator designator_list designation designation_opt
|
|
%type <ilist> initializer initializer_list
|
|
%type <yyint> unary_operator assignment_operator struct_or_union
|
|
%type <yystr> asm_string_literal
|
|
|
|
%start file
|
|
|
|
%%
|
|
|
|
file
|
|
: /* empty */
|
|
{
|
|
werror(W_EMPTY_SOURCE_FILE);
|
|
}
|
|
| program
|
|
;
|
|
|
|
program
|
|
: external_definition
|
|
| program external_definition
|
|
;
|
|
|
|
external_definition
|
|
: function_definition
|
|
{
|
|
// blockNo = 0;
|
|
}
|
|
| declaration
|
|
{
|
|
ignoreTypedefType = 0;
|
|
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);
|
|
}
|
|
| addressmod
|
|
{
|
|
/* These empty braces here are apparently required by some version of GNU bison on MS Windows. See bug #2858. */
|
|
}
|
|
;
|
|
|
|
function_definition
|
|
: function_declarator
|
|
{ /* function type not specified */
|
|
/* assume it to be 'int' */
|
|
addDecl($1,0,newIntLink());
|
|
$1 = createFunctionDecl($1);
|
|
if ($1 && FUNC_ISCRITICAL ($1->type))
|
|
inCriticalFunction = 1;
|
|
}
|
|
function_body
|
|
{
|
|
$$ = createFunction($1,$3);
|
|
if ($1 && FUNC_ISCRITICAL ($1->type))
|
|
inCriticalFunction = 0;
|
|
}
|
|
| declaration_specifiers function_declarator
|
|
{
|
|
sym_link *p = copyLinkChain($1);
|
|
pointerTypes($2->type,p);
|
|
addDecl($2,0,p);
|
|
$2 = createFunctionDecl($2);
|
|
if ($2 && FUNC_ISCRITICAL ($2->type))
|
|
inCriticalFunction = 1;
|
|
/* warn for loss of calling convention for inlined functions. */
|
|
if ($2 && FUNC_ISINLINE ($2->type) &&
|
|
( FUNC_ISZ88DK_CALLEE ($2->type) || FUNC_ISZ88DK_FASTCALL ($2->type) ||
|
|
FUNC_BANKED ($2->type) || FUNC_REGBANK ($2->type) ||
|
|
FUNC_ISOVERLAY ($2->type) || FUNC_ISISR ($2->type) ))
|
|
{
|
|
werror (W_INLINE_FUNCATTR, $2->name);
|
|
}
|
|
}
|
|
function_body
|
|
{
|
|
$$ = createFunction($2,$4);
|
|
if ($2 && FUNC_ISCRITICAL ($2->type))
|
|
inCriticalFunction = 0;
|
|
}
|
|
;
|
|
|
|
function_attribute
|
|
: function_attributes
|
|
| function_attributes function_attribute { $$ = mergeSpec($1,$2,"function_attribute"); }
|
|
;
|
|
|
|
function_attributes
|
|
: USING constant_expr {
|
|
$$ = newLink(SPECIFIER);
|
|
FUNC_REGBANK($$) = (int) ulFromVal(constExprValue($2,TRUE));
|
|
}
|
|
| REENTRANT { $$ = newLink (SPECIFIER);
|
|
FUNC_ISREENT($$)=1;
|
|
}
|
|
| CRITICAL { $$ = newLink (SPECIFIER);
|
|
FUNC_ISCRITICAL($$) = 1;
|
|
}
|
|
| NAKED { $$ = newLink (SPECIFIER);
|
|
FUNC_ISNAKED($$)=1;
|
|
}
|
|
| JAVANATIVE { $$ = newLink (SPECIFIER);
|
|
FUNC_ISJAVANATIVE($$)=1;
|
|
}
|
|
| OVERLAY { $$ = newLink (SPECIFIER);
|
|
FUNC_ISOVERLAY($$)=1;
|
|
}
|
|
| NONBANKED {$$ = newLink (SPECIFIER);
|
|
FUNC_NONBANKED($$) = 1;
|
|
if (FUNC_BANKED($$)) {
|
|
werror(W_BANKED_WITH_NONBANKED);
|
|
}
|
|
}
|
|
| SHADOWREGS {$$ = newLink (SPECIFIER);
|
|
FUNC_ISSHADOWREGS($$) = 1;
|
|
}
|
|
| SD_WPARAM {$$ = newLink (SPECIFIER);
|
|
FUNC_ISWPARAM($$) = 1;
|
|
}
|
|
| BANKED {$$ = newLink (SPECIFIER);
|
|
FUNC_BANKED($$) = 1;
|
|
if (FUNC_NONBANKED($$)) {
|
|
werror(W_BANKED_WITH_NONBANKED);
|
|
}
|
|
}
|
|
| Interrupt_storage
|
|
{
|
|
$$ = newLink (SPECIFIER);
|
|
FUNC_INTNO($$) = $1;
|
|
FUNC_ISISR($$) = 1;
|
|
}
|
|
| TRAP
|
|
{
|
|
$$ = newLink (SPECIFIER);
|
|
FUNC_INTNO($$) = INTNO_TRAP;
|
|
FUNC_ISISR($$) = 1;
|
|
}
|
|
| SMALLC { $$ = newLink (SPECIFIER);
|
|
FUNC_ISSMALLC($$) = 1;
|
|
}
|
|
| Z88DK_FASTCALL { $$ = newLink (SPECIFIER);
|
|
FUNC_ISZ88DK_FASTCALL($$) = 1;
|
|
}
|
|
| Z88DK_CALLEE { $$ = newLink (SPECIFIER);
|
|
FUNC_ISZ88DK_CALLEE($$) = 1;
|
|
}
|
|
| Z88DK_PARAMS_OFFSET '(' constant_expr ')'
|
|
{
|
|
value *offset_v = constExprValue ($3, TRUE);
|
|
int offset = 0;
|
|
$$ = newLink(SPECIFIER);
|
|
if ( offset_v )
|
|
offset = ulFromVal(offset_v);
|
|
$$->funcAttrs.z88dk_params_offset = offset;
|
|
}
|
|
| Z88DK_SHORTCALL '(' constant_expr ',' constant_expr ')'
|
|
{
|
|
value *rst_v = constExprValue ($3, TRUE);
|
|
value *value_v = constExprValue ($5, TRUE);
|
|
int rst = -1, value = -1;
|
|
$$ = newLink(SPECIFIER);
|
|
|
|
if ( rst_v )
|
|
rst = ulFromVal(rst_v);
|
|
if ( value_v )
|
|
value = ulFromVal(value_v);
|
|
|
|
if ( rst < 0 || rst > 56 || ( rst % 8 ) )
|
|
{
|
|
werror(E_SHORTCALL_INVALID_VALUE, "rst", rst);
|
|
}
|
|
if ( value < 0 || value > 0xfff )
|
|
{
|
|
werror(E_SHORTCALL_INVALID_VALUE, "value", value);
|
|
}
|
|
$$->funcAttrs.z88dk_shortcall_rst = rst;
|
|
$$->funcAttrs.z88dk_shortcall_val = value;
|
|
FUNC_ISZ88DK_SHORTCALL($$) = 1;
|
|
}
|
|
| PRESERVES_REGS '(' identifier_list ')'
|
|
{
|
|
const struct symbol *regsym;
|
|
$$ = newLink (SPECIFIER);
|
|
|
|
for(regsym = $3; regsym; regsym = regsym->next)
|
|
{
|
|
int regnum;
|
|
|
|
if (!port->getRegByName || ((regnum = port->getRegByName(regsym->name)) < 0))
|
|
werror (W_UNKNOWN_REG, regsym->name);
|
|
else
|
|
$$->funcAttrs.preserved_regs[regnum] = TRUE;
|
|
}
|
|
}
|
|
;
|
|
|
|
function_body
|
|
: compound_statement
|
|
| declaration_list compound_statement
|
|
{
|
|
werror (E_OLD_STYLE, ($1 ? $1->name: ""));
|
|
exit (1);
|
|
}
|
|
;
|
|
|
|
offsetof_member_designator
|
|
: identifier { $$ = newAst_VALUE (symbolVal ($1)); }
|
|
| offsetof_member_designator '.' { ignoreTypedefType = 1; } identifier
|
|
{
|
|
ignoreTypedefType = 0;
|
|
$4 = newSymbol ($4->name, NestLevel);
|
|
$4->implicit = 1;
|
|
$$ = newNode ('.', $1, newAst_VALUE (symbolVal ($4)));
|
|
}
|
|
| offsetof_member_designator '[' expr ']'
|
|
{
|
|
$$ = newNode ('[', $1, $3);
|
|
}
|
|
;
|
|
|
|
primary_expr
|
|
: identifier { $$ = newAst_VALUE (symbolVal ($1)); }
|
|
| CONSTANT { $$ = newAst_VALUE ($1); }
|
|
| string_literal_val
|
|
| '(' expr ')' { $$ = $2; }
|
|
| generic_selection
|
|
;
|
|
|
|
generic_selection
|
|
: GENERIC '(' assignment_expr ',' generic_assoc_list ')' { $$ = newNode (GENERIC, $3, $5); }
|
|
;
|
|
|
|
generic_assoc_list
|
|
: generic_association { $$ = newNode (GENERIC_ASSOC_LIST, NULL, $1); }
|
|
| generic_assoc_list ',' generic_association { $$ = newNode (GENERIC_ASSOC_LIST, $1, $3); }
|
|
;
|
|
|
|
generic_association
|
|
: type_name ':' assignment_expr { $$ = newNode (GENERIC_ASSOCIATION, newAst_LINK($1), $3); }
|
|
| DEFAULT ':' assignment_expr { $$ = newNode (GENERIC_ASSOCIATION,NULL,$3); }
|
|
;
|
|
|
|
string_literal_val
|
|
: STRING_LITERAL {
|
|
int cnt = 1;
|
|
int max = 253, min = 1;
|
|
char fb[256];
|
|
/* refer to support/cpp/libcpp/macro.c for details */
|
|
while ((((int) ($1[cnt] & 0xff)) & 0xff) == 0xff)
|
|
cnt++;
|
|
|
|
if (cnt <= max)
|
|
{
|
|
$$ = newAst_VALUE (strVal ($1));
|
|
}
|
|
else
|
|
{
|
|
memset (fb, 0x00, sizeof (fb));
|
|
fb[0] = '"';
|
|
strncpy (fb + 1, function_name, max - min + 1);
|
|
fb[max + 1] = '"';
|
|
fb[max + 2] = 0;
|
|
fb[strlen (fb)] = '"';
|
|
fb[strlen (fb) + 1] = 0;
|
|
$$ = newAst_VALUE (strVal (fb));
|
|
}
|
|
}
|
|
;
|
|
|
|
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 '.' { ignoreTypedefType = 1; } identifier
|
|
{
|
|
ignoreTypedefType = 0;
|
|
$4 = newSymbol($4->name,NestLevel);
|
|
$4->implicit = 1;
|
|
$$ = newNode(PTR_OP,newNode('&',$1,NULL),newAst_VALUE(symbolVal($4)));
|
|
}
|
|
| postfix_expr PTR_OP { ignoreTypedefType = 1; } identifier
|
|
{
|
|
ignoreTypedefType = 0;
|
|
$4 = newSymbol($4->name,NestLevel);
|
|
$4->implicit = 1;
|
|
$$ = newNode(PTR_OP,$1,newAst_VALUE(symbolVal($4)));
|
|
}
|
|
| 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
|
|
{
|
|
if ($1 == '&' && IS_AST_OP ($2) && $2->opval.op == '*' && $2->right == NULL)
|
|
$$ = $2->left;
|
|
else if ($1 == '*' && IS_AST_OP ($2) && $2->opval.op == '&' && $2->right == NULL)
|
|
$$ = $2->left;
|
|
else
|
|
$$ = newNode ($1, $2, NULL);
|
|
}
|
|
| SIZEOF unary_expr { $$ = newNode (SIZEOF, NULL, $2); }
|
|
| SIZEOF '(' type_name ')' { $$ = newAst_VALUE (sizeofOp ($3)); }
|
|
| ALIGNOF '(' type_name ')'{ $$ = newAst_VALUE (alignofOp ($3)); }
|
|
| TYPEOF unary_expr { $$ = newNode (TYPEOF, NULL, $2); }
|
|
| OFFSETOF '(' type_name ',' offsetof_member_designator ')' { $$ = offsetofOp($3, $5); }
|
|
;
|
|
|
|
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 { $$ = newNode('<', $1,$3);}
|
|
| relational_expr '>' shift_expr { $$ = newNode('>', $1,$3);}
|
|
| relational_expr LE_OP shift_expr { $$ = newNode(LE_OP,$1,$3);}
|
|
| relational_expr GE_OP shift_expr { $$ = newNode(GE_OP,$1,$3);}
|
|
;
|
|
|
|
equality_expr
|
|
: relational_expr
|
|
| equality_expr EQ_OP relational_expr { $$ = newNode(EQ_OP,$1,$3);}
|
|
| equality_expr NE_OP relational_expr { $$ = 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 { seqPointNo++;} inclusive_or_expr
|
|
{ $$ = newNode(AND_OP,$1,$4);}
|
|
;
|
|
|
|
logical_or_expr
|
|
: logical_and_expr
|
|
| logical_or_expr OR_OP { seqPointNo++;} logical_and_expr
|
|
{ $$ = newNode(OR_OP,$1,$4); }
|
|
;
|
|
|
|
conditional_expr
|
|
: logical_or_expr
|
|
| logical_or_expr '?' { seqPointNo++;} expr ':' conditional_expr
|
|
{
|
|
$$ = newNode(':',$4,$6);
|
|
$$ = newNode('?',$1,$$);
|
|
}
|
|
;
|
|
|
|
assignment_expr
|
|
: conditional_expr
|
|
| cast_expr assignment_operator assignment_expr
|
|
{
|
|
|
|
switch ($2) {
|
|
case '=':
|
|
$$ = newNode($2,$1,$3);
|
|
break;
|
|
case MUL_ASSIGN:
|
|
$$ = createRMW($1, '*', $3);
|
|
break;
|
|
case DIV_ASSIGN:
|
|
$$ = createRMW($1, '/', $3);
|
|
break;
|
|
case MOD_ASSIGN:
|
|
$$ = createRMW($1, '%', $3);
|
|
break;
|
|
case ADD_ASSIGN:
|
|
$$ = createRMW($1, '+', $3);
|
|
break;
|
|
case SUB_ASSIGN:
|
|
$$ = createRMW($1, '-', $3);
|
|
break;
|
|
case LEFT_ASSIGN:
|
|
$$ = createRMW($1, LEFT_OP, $3);
|
|
break;
|
|
case RIGHT_ASSIGN:
|
|
$$ = createRMW($1, RIGHT_OP, $3);
|
|
break;
|
|
case AND_ASSIGN:
|
|
$$ = createRMW($1, '&', $3);
|
|
break;
|
|
case XOR_ASSIGN:
|
|
$$ = createRMW($1, '^', $3);
|
|
break;
|
|
case OR_ASSIGN:
|
|
$$ = createRMW($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 ',' { seqPointNo++;} assignment_expr { $$ = newNode(',',$1,$4);}
|
|
;
|
|
|
|
constant_expr
|
|
: conditional_expr
|
|
;
|
|
|
|
declaration
|
|
: declaration_specifiers ';'
|
|
{
|
|
/* Special case: if incomplete struct/union declared without name, */
|
|
/* make sure an incomplete type for it exists in the current scope */
|
|
if (IS_STRUCT($1))
|
|
{
|
|
structdef *sdef = SPEC_STRUCT($1);
|
|
structdef *osdef;
|
|
osdef = findSymWithBlock (StructTab, sdef->tagsym, currBlockno, NestLevel);
|
|
if (osdef && osdef->block != currBlockno)
|
|
{
|
|
sdef = newStruct(osdef->tagsym->name);
|
|
sdef->level = NestLevel;
|
|
sdef->block = currBlockno;
|
|
sdef->tagsym = newSymbol (osdef->tagsym->name, NestLevel);
|
|
addSym (StructTab, sdef, sdef->tag, sdef->level, currBlockno, 0);
|
|
uselessDecl = FALSE;
|
|
}
|
|
}
|
|
if (uselessDecl)
|
|
werror(W_USELESS_DECL);
|
|
uselessDecl = TRUE;
|
|
$$ = 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);
|
|
sym_link *l0 = NULL, *l1 = NULL, *l2 = NULL;
|
|
/* check illegal declaration */
|
|
for (l0 = sym->type; l0 != NULL; l0 = l0->next)
|
|
if (IS_PTR (l0))
|
|
break;
|
|
/* check if creating intances of structs with flexible arrays */
|
|
for (l1 = lnk; l1 != NULL; l1 = l1->next)
|
|
if (IS_STRUCT (l1) && SPEC_STRUCT (l1)->b_flexArrayMember)
|
|
break;
|
|
if (!options.std_c99 && l0 == NULL && l1 != NULL && SPEC_EXTR($1) != 1)
|
|
werror (W_FLEXARRAY_INSTRUCT, sym->name);
|
|
/* check if creating intances of function type */
|
|
for (l1 = lnk; l1 != NULL; l1 = l1->next)
|
|
if (IS_FUNC (l1))
|
|
break;
|
|
for (l2 = lnk; l2 != NULL; l2 = l2->next)
|
|
if (IS_PTR (l2))
|
|
break;
|
|
if (l0 == NULL && l2 == NULL && l1 != NULL)
|
|
werrorfl(sym->fileDef, sym->lineDef, E_TYPE_IS_FUNCTION, sym->name);
|
|
/* do the pointer stuff */
|
|
pointerTypes(sym->type,lnk);
|
|
addDecl (sym,0,lnk);
|
|
}
|
|
|
|
uselessDecl = TRUE;
|
|
$$ = sym1;
|
|
}
|
|
| static_assert_declaration ';'
|
|
{
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
declaration_specifiers : declaration_specifiers_ { $$ = finalizeSpec($1); };
|
|
|
|
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 */
|
|
$$ = mergeDeclSpec($1, $2, "storage_class_specifier declaration_specifiers - skipped");
|
|
}
|
|
| type_specifier { $$ = $1; }
|
|
| type_specifier declaration_specifiers_ {
|
|
/* if the decl $2 is not a specifier */
|
|
/* find the spec and replace it */
|
|
$$ = mergeDeclSpec($1, $2, "type_specifier declaration_specifiers - skipped");
|
|
}
|
|
| function_specifier { $$ = $1; }
|
|
| function_specifier declaration_specifiers_ {
|
|
/* if the decl $2 is not a specifier */
|
|
/* find the spec and replace it */
|
|
$$ = mergeDeclSpec($1, $2, "function_specifier declaration_specifiers - skipped");
|
|
}
|
|
| alignment_specifier { $$ = $1; }
|
|
| alignment_specifier declaration_specifiers_ {
|
|
/* if the decl $2 is not a specifier */
|
|
/* find the spec and replace it */
|
|
$$ = mergeDeclSpec($1, $2, "alignment_specifier declaration_specifiers - skipped");
|
|
}
|
|
;
|
|
|
|
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; seqPointNo++; }
|
|
;
|
|
|
|
designation_opt
|
|
: { $$ = NULL; }
|
|
| designation
|
|
;
|
|
|
|
designation
|
|
: designator_list '=' { $$ = revDesignation($1); }
|
|
;
|
|
|
|
designator_list
|
|
: designator
|
|
| designator_list designator { $2->next = $1; $$ = $2; }
|
|
;
|
|
|
|
designator
|
|
: '[' constant_expr ']'
|
|
{
|
|
value *tval;
|
|
int elemno;
|
|
|
|
tval = constExprValue($2, TRUE);
|
|
/* if it is not a constant then Error */
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror (E_CONST_EXPECTED);
|
|
elemno = 0; /* arbitrary fixup */
|
|
}
|
|
else
|
|
{
|
|
if ((elemno = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror (E_BAD_DESIGNATOR);
|
|
elemno = 0; /* arbitrary fixup */
|
|
}
|
|
}
|
|
$$ = newDesignation(DESIGNATOR_ARRAY, &elemno);
|
|
}
|
|
| '.' identifier { $$ = newDesignation(DESIGNATOR_STRUCT,$2); }
|
|
;
|
|
|
|
storage_class_specifier
|
|
: TYPEDEF {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_TYPEDEF($$) = 1;
|
|
}
|
|
| EXTERN {
|
|
$$ = newLink(SPECIFIER);
|
|
SPEC_EXTR($$) = 1;
|
|
}
|
|
| STATIC {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_STAT($$) = 1;
|
|
}
|
|
| AUTO {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_AUTO;
|
|
}
|
|
| REGISTER {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_REGISTER;
|
|
}
|
|
;
|
|
|
|
function_specifier
|
|
: INLINE {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_INLINE($$) = 1;
|
|
}
|
|
| NORETURN {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_NORETURN($$) = 1;
|
|
}
|
|
;
|
|
|
|
alignment_specifier
|
|
: ALIGNAS '(' type_name ')'
|
|
{
|
|
checkTypeSanity ($3, "(_Alignas)");
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_ALIGNAS($$) = 1;
|
|
}
|
|
| ALIGNAS '(' constant_expr ')'
|
|
{
|
|
value *val = constExprValue ($3, TRUE);
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_ALIGNAS($$) = 0;
|
|
if (!val)
|
|
werror (E_CONST_EXPECTED);
|
|
else if (ulFromVal (val) == 0 || isPowerOf2 (ulFromVal (val)) && ulFromVal (val) <= port->mem.maxextalign)
|
|
SPEC_ALIGNAS($$) = ulFromVal(val);
|
|
else
|
|
werror (E_ALIGNAS, ulFromVal(val));
|
|
}
|
|
;
|
|
|
|
Interrupt_storage
|
|
: INTERRUPT { $$ = INTNO_UNSPEC; }
|
|
| INTERRUPT constant_expr
|
|
{
|
|
value *val = constExprValue($2,TRUE);
|
|
int intno = (int) ulFromVal(val);
|
|
if (val && (intno >= 0) && (intno <= INTNO_MAX))
|
|
$$ = intno;
|
|
else
|
|
{
|
|
werror(E_INT_BAD_INTNO, intno);
|
|
$$ = INTNO_UNSPEC;
|
|
}
|
|
}
|
|
;
|
|
|
|
type_qualifier
|
|
: SD_CONST {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_CONST($$) = 1;
|
|
}
|
|
| RESTRICT {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_RESTRICT($$) = 1;
|
|
}
|
|
| VOLATILE {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_VOLATILE($$) = 1;
|
|
}
|
|
| ADDRSPACE_NAME {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_ADDRSPACE($$) = findSym (AddrspaceTab, 0, $1);
|
|
}
|
|
| XDATA {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_XDATA;
|
|
}
|
|
| CODE {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_CODE;
|
|
}
|
|
| EEPROM {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_EEPROM;
|
|
}
|
|
| DATA {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_DATA;
|
|
}
|
|
| IDATA {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_IDATA;
|
|
}
|
|
| PDATA {
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_SCLS($$) = S_PDATA;
|
|
}
|
|
;
|
|
|
|
type_qualifier_list
|
|
: type_qualifier
|
|
| type_qualifier_list type_qualifier
|
|
{
|
|
$$ = mergeDeclSpec($1, $2, "type_qualifier_list type_qualifier skipped");
|
|
}
|
|
;
|
|
|
|
type_specifier
|
|
: type_qualifier { $$ = $1; }
|
|
| SD_BOOL {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_BOOL;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_CHAR {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_CHAR;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_SHORT {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_SHORT($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_INT {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_INT;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_LONG {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_LONG($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SIGNED {
|
|
$$=newLink(SPECIFIER);
|
|
$$->select.s.b_signed = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| UNSIGNED {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_USIGN($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_VOID {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_VOID;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SD_FLOAT {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_FLOAT;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| FIXED16X16 {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_FIXED16X16;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| BIT {
|
|
$$=newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_BIT;
|
|
SPEC_SCLS($$) = S_BIT;
|
|
SPEC_BLEN($$) = 1;
|
|
SPEC_BSTR($$) = 0;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| AT constant_expr {
|
|
$$=newLink(SPECIFIER);
|
|
/* add this to the storage class specifier */
|
|
SPEC_ABSA($$) = 1; /* set the absolute addr flag */
|
|
/* now get the abs addr from value */
|
|
SPEC_ADDR($$) = (unsigned int) ulFromVal(constExprValue($2,TRUE));
|
|
}
|
|
| struct_or_union_specifier {
|
|
uselessDecl = FALSE;
|
|
$$ = $1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| enum_specifier {
|
|
cenum = NULL;
|
|
uselessDecl = FALSE;
|
|
ignoreTypedefType = 1;
|
|
$$ = $1;
|
|
}
|
|
| TYPE_NAME
|
|
{
|
|
symbol *sym;
|
|
sym_link *p;
|
|
sym = findSym(TypedefTab,NULL,$1);
|
|
$$ = p = copyLinkChain(sym ? sym->type : NULL);
|
|
SPEC_TYPEDEF(getSpec(p)) = 0;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| sfr_reg_bit
|
|
;
|
|
|
|
sfr_reg_bit
|
|
: SBIT {
|
|
$$ = newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_SBIT;
|
|
SPEC_SCLS($$) = S_SBIT;
|
|
SPEC_BLEN($$) = 1;
|
|
SPEC_BSTR($$) = 0;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| sfr_attributes
|
|
;
|
|
|
|
sfr_attributes
|
|
: SFR {
|
|
$$ = newLink(SPECIFIER);
|
|
FUNC_REGBANK($$) = 0;
|
|
SPEC_NOUN($$) = V_CHAR;
|
|
SPEC_SCLS($$) = S_SFR;
|
|
SPEC_USIGN($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
| SFR BANKED {
|
|
$$ = newLink(SPECIFIER);
|
|
FUNC_REGBANK($$) = 1;
|
|
SPEC_NOUN($$) = V_CHAR;
|
|
SPEC_SCLS($$) = S_SFR;
|
|
SPEC_USIGN($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
;
|
|
|
|
sfr_attributes
|
|
: SFR16 {
|
|
$$ = newLink(SPECIFIER);
|
|
FUNC_REGBANK($$) = 0;
|
|
SPEC_NOUN($$) = V_INT;
|
|
SPEC_SCLS($$) = S_SFR;
|
|
SPEC_USIGN($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
;
|
|
|
|
sfr_attributes
|
|
: SFR32 {
|
|
$$ = newLink(SPECIFIER);
|
|
FUNC_REGBANK($$) = 0;
|
|
SPEC_NOUN($$) = V_INT;
|
|
SPEC_SCLS($$) = S_SFR;
|
|
SPEC_LONG($$) = 1;
|
|
SPEC_USIGN($$) = 1;
|
|
ignoreTypedefType = 1;
|
|
}
|
|
;
|
|
|
|
struct_or_union_specifier
|
|
: struct_or_union opt_stag
|
|
{
|
|
structdef *sdef;
|
|
|
|
if (! $2->tagsym)
|
|
{
|
|
/* no tag given, so new struct def for current scope */
|
|
addSym (StructTab, $2, $2->tag, $2->level, currBlockno, 0);
|
|
}
|
|
else
|
|
{
|
|
sdef = findSymWithBlock (StructTab, $2->tagsym, currBlockno, NestLevel);
|
|
if (sdef)
|
|
{
|
|
/* Error if a complete type already defined in this scope */
|
|
if (sdef->block == currBlockno)
|
|
{
|
|
if (sdef->fields)
|
|
{
|
|
werror(E_STRUCT_REDEF, $2->tag);
|
|
werrorfl(sdef->tagsym->fileDef, sdef->tagsym->lineDef, E_PREVIOUS_DEF);
|
|
}
|
|
else
|
|
{
|
|
$2 = sdef; /* We are completing an incomplete type */
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* There is an existing struct def in an outer scope. */
|
|
/* Create new struct def for current scope */
|
|
addSym (StructTab, $2, $2->tag, $2->level, currBlockno, 0);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* There is no existing struct def at all. */
|
|
/* Create new struct def for current scope */
|
|
addSym (StructTab, $2, $2->tag, $2->level, currBlockno, 0);
|
|
}
|
|
}
|
|
|
|
if (!$2->type)
|
|
{
|
|
$2->type = $1;
|
|
}
|
|
else
|
|
{
|
|
if ($2->type != $1)
|
|
werror(E_BAD_TAG, $2->tag, $1==STRUCT ? "struct" : "union");
|
|
}
|
|
}
|
|
'{' struct_declaration_list '}'
|
|
{
|
|
structdef *sdef;
|
|
symbol *sym, *dsym;
|
|
|
|
// check for errors in structure members
|
|
for (sym=$5; sym; sym=sym->next)
|
|
{
|
|
if (IS_ABSOLUTE(sym->etype))
|
|
{
|
|
werrorfl(sym->fileDef, sym->lineDef, E_NOT_ALLOWED, "'at'");
|
|
SPEC_ABSA(sym->etype) = 0;
|
|
}
|
|
if (IS_SPEC(sym->etype) && SPEC_SCLS(sym->etype))
|
|
{
|
|
werrorfl(sym->fileDef, sym->lineDef, E_NOT_ALLOWED, "storage class");
|
|
printTypeChainRaw (sym->type, NULL);
|
|
SPEC_SCLS(sym->etype) = 0;
|
|
}
|
|
for (dsym=sym->next; dsym; dsym=dsym->next)
|
|
{
|
|
if (*dsym->name && strcmp(sym->name, dsym->name)==0)
|
|
{
|
|
werrorfl(sym->fileDef, sym->lineDef, E_DUPLICATE_MEMBER,
|
|
$1==STRUCT ? "struct" : "union", sym->name);
|
|
werrorfl(dsym->fileDef, dsym->lineDef, E_PREVIOUS_DEF);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Create a structdef */
|
|
sdef = $2;
|
|
sdef->fields = reverseSyms($5); /* link the fields */
|
|
sdef->size = compStructSize($1, sdef); /* update size of */
|
|
promoteAnonStructs ($1, sdef);
|
|
|
|
/* Create the specifier */
|
|
$$ = newLink (SPECIFIER);
|
|
SPEC_NOUN($$) = V_STRUCT;
|
|
SPEC_STRUCT($$)= sdef;
|
|
}
|
|
| struct_or_union stag
|
|
{
|
|
structdef *sdef;
|
|
|
|
sdef = findSymWithBlock (StructTab, $2->tagsym, currBlockno, NestLevel);
|
|
|
|
if (sdef)
|
|
$2 = sdef;
|
|
else
|
|
{
|
|
/* new struct def for current scope */
|
|
addSym (StructTab, $2, $2->tag, $2->level, currBlockno, 0);
|
|
}
|
|
$$ = newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_STRUCT;
|
|
SPEC_STRUCT($$) = $2;
|
|
|
|
if (!$2->type)
|
|
{
|
|
$2->type = $1;
|
|
}
|
|
else
|
|
{
|
|
if ($2->type != $1)
|
|
werror(E_BAD_TAG, $2->tag, $1==STRUCT ? "struct" : "union");
|
|
}
|
|
}
|
|
;
|
|
|
|
struct_or_union
|
|
: STRUCT { $$ = STRUCT; ignoreTypedefType = 1; }
|
|
| UNION { $$ = UNION; ignoreTypedefType = 1; }
|
|
;
|
|
|
|
opt_stag
|
|
: stag
|
|
| { /* synthesize a name add to structtable */
|
|
ignoreTypedefType = 0;
|
|
$$ = newStruct(genSymName(NestLevel));
|
|
$$->level = NestLevel;
|
|
$$->block = currBlockno;
|
|
$$->tagsym = NULL;
|
|
//addSym (StructTab, $$, $$->tag, $$->level, currBlockno, 0);
|
|
}
|
|
;
|
|
|
|
stag
|
|
: identifier
|
|
{ /* add name to structure table */
|
|
ignoreTypedefType = 0;
|
|
$$ = newStruct($1->name);
|
|
$$->level = NestLevel;
|
|
$$->block = currBlockno;
|
|
$$->tagsym = $1;
|
|
//$$ = findSymWithBlock (StructTab, $1, currBlockno);
|
|
//if (! $$ )
|
|
// {
|
|
// $$ = newStruct($1->name);
|
|
// $$->level = NestLevel;
|
|
// $$->tagsym = $1;
|
|
// //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 )
|
|
{
|
|
sym_link *btype = copyLinkChain($1);
|
|
|
|
pointerTypes(sym->type, btype);
|
|
if (!sym->type)
|
|
{
|
|
sym->type = btype;
|
|
sym->etype = getSpec(sym->type);
|
|
}
|
|
else
|
|
addDecl (sym, 0, btype);
|
|
/* make sure the type is complete and sane */
|
|
checkTypeSanity(sym->etype, sym->name);
|
|
}
|
|
ignoreTypedefType = 0;
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
struct_declarator_list
|
|
: struct_declarator
|
|
| struct_declarator_list ',' struct_declarator
|
|
{
|
|
$3->next = $1;
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
struct_declarator
|
|
: declarator
|
|
| ':' constant_expr
|
|
{
|
|
unsigned int bitsize;
|
|
$$ = newSymbol (genSymName(NestLevel), NestLevel);
|
|
bitsize = (unsigned int) ulFromVal(constExprValue($2, TRUE));
|
|
if (!bitsize)
|
|
bitsize = BITVAR_PAD;
|
|
$$->bitVar = bitsize;
|
|
$$->bitUnnamed = 1;
|
|
}
|
|
| declarator ':' constant_expr
|
|
{
|
|
unsigned int bitsize;
|
|
bitsize = (unsigned int) ulFromVal(constExprValue($3, TRUE));
|
|
|
|
if (!bitsize)
|
|
{
|
|
$$ = newSymbol (genSymName(NestLevel), NestLevel);
|
|
$$->bitVar = BITVAR_PAD;
|
|
werror(W_BITFLD_NAMED);
|
|
}
|
|
else
|
|
$1->bitVar = bitsize;
|
|
}
|
|
| { $$ = newSymbol ("", NestLevel); }
|
|
;
|
|
|
|
enum_specifier
|
|
: ENUM '{' enumerator_list '}'
|
|
{
|
|
$$ = newEnumType ($3);
|
|
SPEC_SCLS(getSpec($$)) = 0;
|
|
}
|
|
| ENUM identifier '{' enumerator_list '}'
|
|
{
|
|
symbol *csym;
|
|
sym_link *enumtype;
|
|
|
|
csym = findSymWithLevel(enumTab, $2);
|
|
if ((csym && csym->level == $2->level))
|
|
{
|
|
werrorfl($2->fileDef, $2->lineDef, E_DUPLICATE_TYPEDEF, csym->name);
|
|
werrorfl(csym->fileDef, csym->lineDef, E_PREVIOUS_DEF);
|
|
}
|
|
|
|
enumtype = newEnumType ($4);
|
|
SPEC_SCLS(getSpec(enumtype)) = 0;
|
|
$2->type = enumtype;
|
|
|
|
/* add this to the enumerator table */
|
|
if (!csym)
|
|
addSym (enumTab, $2, $2->name, $2->level, $2->block, 0);
|
|
$$ = copyLinkChain(enumtype);
|
|
}
|
|
| ENUM identifier
|
|
{
|
|
symbol *csym;
|
|
|
|
/* check the enumerator table */
|
|
if ((csym = findSymWithLevel(enumTab, $2)))
|
|
$$ = copyLinkChain(csym->type);
|
|
else
|
|
{
|
|
$$ = newLink(SPECIFIER);
|
|
SPEC_NOUN($$) = V_INT;
|
|
}
|
|
}
|
|
;
|
|
|
|
enumerator_list
|
|
: enumerator
|
|
| enumerator_list ','
|
|
| enumerator_list ',' enumerator
|
|
{
|
|
$3->next = $1;
|
|
$$ = $3;
|
|
}
|
|
;
|
|
|
|
enumerator
|
|
: identifier opt_assign_expr
|
|
{
|
|
symbol *sym;
|
|
|
|
// check if the symbol at the same level already exists
|
|
if ((sym = findSymWithLevel (SymbolTab, $1)) && sym->level == $1->level)
|
|
{
|
|
werrorfl ($1->fileDef, $1->lineDef, E_DUPLICATE_MEMBER, "enum", $1->name);
|
|
werrorfl (sym->fileDef, sym->lineDef, E_PREVIOUS_DEF);
|
|
}
|
|
$1->type = copyLinkChain ($2->type);
|
|
$1->etype = getSpec ($1->type);
|
|
SPEC_ENUM ($1->etype) = 1;
|
|
$$ = $1;
|
|
// do this now, so we can use it for the next enums in the list
|
|
addSymChain (&$1);
|
|
}
|
|
;
|
|
|
|
opt_assign_expr
|
|
: '=' constant_expr
|
|
{
|
|
value *val;
|
|
|
|
val = constExprValue($2, TRUE);
|
|
if (!IS_INT(val->type) && !IS_CHAR(val->type) && !IS_BOOL(val->type))
|
|
{
|
|
werror(E_ENUM_NON_INTEGER);
|
|
SNPRINTF(lbuff, sizeof(lbuff), "%d", (int) ulFromVal(val));
|
|
val = constVal(lbuff);
|
|
}
|
|
$$ = cenum = val;
|
|
}
|
|
| {
|
|
if (cenum)
|
|
{
|
|
SNPRINTF(lbuff, sizeof(lbuff), "%d", (int) ulFromVal(cenum)+1);
|
|
$$ = cenum = constVal(lbuff);
|
|
}
|
|
else
|
|
{
|
|
$$ = cenum = constCharVal(0);
|
|
}
|
|
}
|
|
;
|
|
|
|
declarator
|
|
: declarator3 { $$ = $1; }
|
|
| pointer declarator3
|
|
{
|
|
addDecl ($2,0,reverseLink($1));
|
|
$$ = $2;
|
|
}
|
|
;
|
|
|
|
declarator3
|
|
: declarator2_function_attributes { $$ = $1; }
|
|
| declarator2 { $$ = $1; }
|
|
;
|
|
|
|
function_declarator
|
|
: declarator2_function_attributes
|
|
{
|
|
$$ = $1;
|
|
strncpy (function_name, $$->name, sizeof (function_name) - 4);
|
|
memset (function_name + sizeof (function_name) - 4, 0x00, 4);
|
|
}
|
|
| pointer declarator2_function_attributes
|
|
{
|
|
addDecl ($2,0,reverseLink($1));
|
|
$$ = $2;
|
|
strncpy (function_name, $$->name, sizeof (function_name) - 4);
|
|
memset (function_name + sizeof (function_name) - 4, 0x00, 4);
|
|
}
|
|
;
|
|
|
|
declarator2_function_attributes
|
|
: function_declarator2 { $$ = $1; }
|
|
| function_declarator2 function_attribute {
|
|
// copy the functionAttributes (not the args and hasVargs !!)
|
|
struct value *args;
|
|
unsigned hasVargs;
|
|
sym_link *funcType=$1->type;
|
|
|
|
while (funcType && !IS_FUNC(funcType))
|
|
funcType = funcType->next;
|
|
|
|
if (!funcType)
|
|
werror (E_FUNC_ATTR);
|
|
else
|
|
{
|
|
args=FUNC_ARGS(funcType);
|
|
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; }
|
|
| declarator3 '[' ']'
|
|
{
|
|
sym_link *p;
|
|
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
DCL_ELEM(p) = 0;
|
|
addDecl($1,0,p);
|
|
}
|
|
| declarator3 '[' type_qualifier_list ']'
|
|
{
|
|
sym_link *p, *n;
|
|
|
|
if (!options.std_c99)
|
|
werror (E_QUALIFIED_ARRAY_PARAM_C99);
|
|
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
DCL_ELEM(p) = 0;
|
|
DCL_PTR_CONST(p) = SPEC_CONST ($3);
|
|
DCL_PTR_RESTRICT(p) = SPEC_RESTRICT ($3);
|
|
DCL_PTR_VOLATILE(p) = SPEC_VOLATILE ($3);
|
|
DCL_PTR_ADDRSPACE(p) = SPEC_ADDRSPACE ($3);
|
|
addDecl($1,0,p);
|
|
n = newLink (SPECIFIER);
|
|
SPEC_NEEDSPAR(n) = 1;
|
|
addDecl($1,0,n);
|
|
}
|
|
| declarator3 '[' constant_expr ']'
|
|
{
|
|
sym_link *p;
|
|
value *tval;
|
|
int size;
|
|
|
|
tval = constExprValue($3, TRUE);
|
|
/* if it is not a constant then Error */
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror(E_CONST_EXPECTED);
|
|
/* Assume a single item array to limit the cascade */
|
|
/* of additional errors. */
|
|
size = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((size = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror(E_NEGATIVE_ARRAY_SIZE, $1->name);
|
|
size = 1;
|
|
}
|
|
}
|
|
DCL_ELEM(p) = size;
|
|
addDecl($1, 0, p);
|
|
}
|
|
| declarator3 '[' STATIC constant_expr ']'
|
|
{
|
|
sym_link *p, *n;
|
|
value *tval;
|
|
int size;
|
|
|
|
if (!options.std_c99)
|
|
werror (E_STATIC_ARRAY_PARAM_C99);
|
|
|
|
tval = constExprValue($4, TRUE);
|
|
/* if it is not a constant then Error */
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror(E_CONST_EXPECTED);
|
|
/* Assume a single item array to limit the cascade */
|
|
/* of additional errors. */
|
|
size = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((size = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror(E_NEGATIVE_ARRAY_SIZE, $1->name);
|
|
size = 1;
|
|
}
|
|
}
|
|
DCL_ELEM(p) = size;
|
|
addDecl($1, 0, p);
|
|
n = newLink (SPECIFIER);
|
|
SPEC_NEEDSPAR(n) = 1;
|
|
addDecl($1,0,n);
|
|
}
|
|
| declarator3 '[' type_qualifier_list constant_expr ']'
|
|
{
|
|
sym_link *p, *n;
|
|
value *tval;
|
|
int size;
|
|
|
|
if (!options.std_c99)
|
|
werror (E_QUALIFIED_ARRAY_PARAM_C99);
|
|
|
|
tval = constExprValue($4, TRUE);
|
|
/* if it is not a constant then Error */
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror(E_CONST_EXPECTED);
|
|
/* Assume a single item array to limit the cascade */
|
|
/* of additional errors. */
|
|
size = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((size = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror(E_NEGATIVE_ARRAY_SIZE, $1->name);
|
|
size = 1;
|
|
}
|
|
}
|
|
DCL_ELEM(p) = size;
|
|
DCL_PTR_CONST(p) = SPEC_CONST ($3);
|
|
DCL_PTR_RESTRICT(p) = SPEC_RESTRICT ($3);
|
|
DCL_PTR_VOLATILE(p) = SPEC_VOLATILE ($3);
|
|
DCL_PTR_ADDRSPACE(p) = SPEC_ADDRSPACE ($3);
|
|
addDecl($1, 0, p);
|
|
n = newLink (SPECIFIER);
|
|
SPEC_NEEDSPAR(n) = 1;
|
|
addDecl($1,0,n);
|
|
}
|
|
| declarator3 '[' STATIC type_qualifier_list constant_expr ']'
|
|
{
|
|
sym_link *p, *n;
|
|
value *tval;
|
|
int size;
|
|
|
|
if (!options.std_c99)
|
|
{
|
|
werror (E_STATIC_ARRAY_PARAM_C99);
|
|
werror (E_QUALIFIED_ARRAY_PARAM_C99);
|
|
}
|
|
|
|
tval = constExprValue($5, TRUE);
|
|
/* if it is not a constant then Error */
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror(E_CONST_EXPECTED);
|
|
/* Assume a single item array to limit the cascade */
|
|
/* of additional errors. */
|
|
size = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((size = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror(E_NEGATIVE_ARRAY_SIZE, $1->name);
|
|
size = 1;
|
|
}
|
|
}
|
|
DCL_ELEM(p) = size;
|
|
DCL_PTR_CONST(p) = SPEC_CONST ($4);
|
|
DCL_PTR_RESTRICT(p) = SPEC_RESTRICT ($4);
|
|
DCL_PTR_VOLATILE(p) = SPEC_VOLATILE ($4);
|
|
DCL_PTR_ADDRSPACE(p) = SPEC_ADDRSPACE ($4);
|
|
addDecl($1, 0, p);
|
|
n = newLink (SPECIFIER);
|
|
SPEC_NEEDSPAR(n) = 1;
|
|
addDecl($1,0,n);
|
|
}
|
|
| declarator3 '[' type_qualifier_list STATIC constant_expr ']'
|
|
{
|
|
sym_link *p, *n;
|
|
value *tval;
|
|
int size;
|
|
|
|
if (!options.std_c99)
|
|
{
|
|
werror (E_QUALIFIED_ARRAY_PARAM_C99);
|
|
werror (E_STATIC_ARRAY_PARAM_C99);
|
|
}
|
|
|
|
tval = constExprValue($5, TRUE);
|
|
/* if it is not a constant then Error */
|
|
p = newLink (DECLARATOR);
|
|
DCL_TYPE(p) = ARRAY;
|
|
|
|
if (!tval || (SPEC_SCLS(tval->etype) != S_LITERAL))
|
|
{
|
|
werror(E_CONST_EXPECTED);
|
|
/* Assume a single item array to limit the cascade */
|
|
/* of additional errors. */
|
|
size = 1;
|
|
}
|
|
else
|
|
{
|
|
if ((size = (int) ulFromVal(tval)) < 0)
|
|
{
|
|
werror(E_NEGATIVE_ARRAY_SIZE, $1->name);
|
|
size = 1;
|
|
}
|
|
}
|
|
DCL_ELEM(p) = size;
|
|
DCL_PTR_CONST(p) = SPEC_CONST ($3);
|
|
DCL_PTR_RESTRICT(p) = SPEC_RESTRICT ($3);
|
|
DCL_PTR_VOLATILE(p) = SPEC_VOLATILE ($3);
|
|
DCL_PTR_ADDRSPACE(p) = SPEC_ADDRSPACE ($3);
|
|
addDecl($1, 0, p);
|
|
n = newLink (SPECIFIER);
|
|
SPEC_NEEDSPAR(n) = 1;
|
|
addDecl($1,0,n);
|
|
}
|
|
;
|
|
|
|
function_declarator2
|
|
: declarator2 '(' ')'
|
|
{
|
|
addDecl ($1, FUNCTION, NULL);
|
|
}
|
|
| declarator2 '('
|
|
{
|
|
NestLevel += LEVEL_UNIT;
|
|
STACK_PUSH(blockNum, currBlockno);
|
|
btree_add_child(currBlockno, ++blockNo);
|
|
currBlockno = blockNo;
|
|
seqPointNo++; /* not a true sequence point, but helps resolve scope */
|
|
}
|
|
parameter_type_list ')'
|
|
{
|
|
sym_link *funcType;
|
|
|
|
addDecl ($1, FUNCTION, NULL);
|
|
|
|
funcType = $1->type;
|
|
while (funcType && !IS_FUNC(funcType))
|
|
funcType = funcType->next;
|
|
|
|
assert (funcType);
|
|
|
|
FUNC_HASVARARGS(funcType) = IS_VARG($4);
|
|
FUNC_ARGS(funcType) = reverseVal($4);
|
|
|
|
/* nest level was incremented to take care of the parms */
|
|
NestLevel -= LEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
seqPointNo++; /* not a true sequence point, but helps resolve scope */
|
|
|
|
// if this was a pointer (to a function)
|
|
if (!IS_FUNC($1->type))
|
|
cleanUpLevel(SymbolTab, NestLevel + LEVEL_UNIT);
|
|
|
|
$$ = $1;
|
|
}
|
|
| declarator2 '(' 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;
|
|
if (IS_SPEC($2)) {
|
|
DCL_TSPEC($1) = $2;
|
|
DCL_PTR_CONST($1) = SPEC_CONST($2);
|
|
DCL_PTR_VOLATILE($1) = SPEC_VOLATILE($2);
|
|
DCL_PTR_RESTRICT($1) = SPEC_RESTRICT($2);
|
|
DCL_PTR_ADDRSPACE($1) = SPEC_ADDRSPACE($2);
|
|
}
|
|
else
|
|
werror (W_PTR_TYPE_INVALID);
|
|
}
|
|
| unqualified_pointer pointer
|
|
{
|
|
$$ = $1;
|
|
$$->next = $2;
|
|
DCL_TYPE($2)=port->unqualified_pointer;
|
|
}
|
|
| 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);
|
|
DCL_PTR_RESTRICT($1) = SPEC_RESTRICT($2);
|
|
DCL_PTR_ADDRSPACE($1) = SPEC_ADDRSPACE($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_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(DECLARATOR);
|
|
DCL_TYPE($$)=UPOINTER;
|
|
}
|
|
;
|
|
|
|
type_specifier_list : type_specifier_list_ { $$ = finalizeSpec($1); };
|
|
|
|
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 */
|
|
$$ = mergeDeclSpec($1, $2, "type_specifier_list type_specifier skipped");
|
|
}
|
|
;
|
|
|
|
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
|
|
: declaration_specifiers declarator
|
|
{
|
|
symbol *loop;
|
|
|
|
if (IS_SPEC ($1) && !IS_VALID_PARAMETER_STORAGE_CLASS_SPEC ($1))
|
|
{
|
|
werror (E_STORAGE_CLASS_FOR_PARAMETER, $2->name);
|
|
}
|
|
pointerTypes ($2->type, $1);
|
|
if (IS_SPEC ($2->etype))
|
|
SPEC_NEEDSPAR($2->etype) = 0;
|
|
addDecl ($2, 0, $1);
|
|
for (loop = $2; loop; loop->_isparm = 1, loop = loop->next)
|
|
;
|
|
$$ = symbolVal ($2);
|
|
ignoreTypedefType = 0;
|
|
}
|
|
| type_name
|
|
{
|
|
$$ = newValue ();
|
|
$$->type = $1;
|
|
$$->etype = getSpec ($$->type);
|
|
ignoreTypedefType = 0;
|
|
}
|
|
;
|
|
|
|
type_name
|
|
: declaration_specifiers
|
|
{
|
|
if (IS_SPEC ($1) && !IS_VALID_PARAMETER_STORAGE_CLASS_SPEC ($1))
|
|
{
|
|
werror (E_STORAGE_CLASS_FOR_PARAMETER, "type name");
|
|
}
|
|
$$ = $1; ignoreTypedefType = 0;
|
|
}
|
|
| declaration_specifiers abstract_declarator
|
|
{
|
|
/* go to the end of the list */
|
|
sym_link *p;
|
|
|
|
if (IS_SPEC ($1) && !IS_VALID_PARAMETER_STORAGE_CLASS_SPEC ($1))
|
|
{
|
|
werror (E_STORAGE_CLASS_FOR_PARAMETER, "type name");
|
|
}
|
|
pointerTypes ($2,$1);
|
|
for (p = $2; p && p->next; p = p->next)
|
|
;
|
|
if (!p)
|
|
{
|
|
werror(E_SYNTAX_ERROR, yytext);
|
|
}
|
|
else
|
|
{
|
|
p->next = $1;
|
|
}
|
|
$$ = $2;
|
|
ignoreTypedefType = 0;
|
|
}
|
|
;
|
|
|
|
abstract_declarator
|
|
: pointer { $$ = reverseLink($1); }
|
|
| abstract_declarator2
|
|
| pointer abstract_declarator2 { $1 = reverseLink($1); $2->next = $1; $$ = $2;
|
|
if (IS_PTR($1) && IS_FUNC($2))
|
|
DCL_TYPE($1) = CPOINTER;
|
|
}
|
|
;
|
|
|
|
abstract_declarator2
|
|
: '(' abstract_declarator ')' { $$ = $2; }
|
|
| '[' ']' {
|
|
$$ = newLink (DECLARATOR);
|
|
DCL_TYPE($$) = ARRAY;
|
|
DCL_ELEM($$) = 0;
|
|
}
|
|
| '[' constant_expr ']' {
|
|
value *val;
|
|
$$ = newLink (DECLARATOR);
|
|
DCL_TYPE($$) = ARRAY;
|
|
DCL_ELEM($$) = (int) ulFromVal(val = constExprValue($2,TRUE));
|
|
}
|
|
| abstract_declarator2 '[' ']' {
|
|
$$ = newLink (DECLARATOR);
|
|
DCL_TYPE($$) = ARRAY;
|
|
DCL_ELEM($$) = 0;
|
|
$$->next = $1;
|
|
}
|
|
| abstract_declarator2 '[' constant_expr ']'
|
|
{
|
|
value *val;
|
|
$$ = newLink (DECLARATOR);
|
|
DCL_TYPE($$) = ARRAY;
|
|
DCL_ELEM($$) = (int) ulFromVal(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(DECLARATOR);
|
|
DCL_TYPE(p) = FUNCTION;
|
|
if (!$1) {
|
|
// ((void (code *) ()) 0) ()
|
|
$1=newLink(DECLARATOR);
|
|
DCL_TYPE($1)=CPOINTER;
|
|
$$ = $1;
|
|
}
|
|
$1->next=p;
|
|
}
|
|
| abstract_declarator2 '('
|
|
{
|
|
NestLevel += LEVEL_UNIT;
|
|
STACK_PUSH(blockNum, currBlockno);
|
|
btree_add_child(currBlockno, ++blockNo);
|
|
currBlockno = blockNo;
|
|
}
|
|
parameter_type_list ')'
|
|
{
|
|
sym_link *p = newLink(DECLARATOR), *q;
|
|
DCL_TYPE(p) = FUNCTION;
|
|
|
|
FUNC_HASVARARGS(p) = IS_VARG($4);
|
|
FUNC_ARGS(p) = reverseVal($4);
|
|
|
|
/* nest level was incremented to take care of the parms */
|
|
NestLevel -= LEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
if (!$1)
|
|
{
|
|
/* ((void (code *) (void)) 0) () */
|
|
$1 = newLink(DECLARATOR);
|
|
DCL_TYPE($1) = CPOINTER;
|
|
$$ = $1;
|
|
}
|
|
for (q = $1; q && q->next; q = q->next);
|
|
q->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
|
|
: designation_opt initializer { $2->designation = $1; $$ = $2; }
|
|
| initializer_list ',' designation_opt initializer
|
|
{
|
|
$4->designation = $3;
|
|
$4->next = $1;
|
|
$$ = $4;
|
|
}
|
|
;
|
|
|
|
static_assert_declaration
|
|
: STATIC_ASSERT '(' constant_expr ',' STRING_LITERAL ')'
|
|
{
|
|
value *val = constExprValue ($3, TRUE);
|
|
if (!val)
|
|
werror (E_CONST_EXPECTED);
|
|
else if (!ulFromVal(val))
|
|
werror (W_STATIC_ASSERTION, $5);
|
|
}
|
|
| STATIC_ASSERT '(' constant_expr ')'
|
|
{
|
|
value *val = constExprValue ($3, TRUE);
|
|
if (!options.std_c2x)
|
|
werror (E_STATIC_ASSERTION_C2X);
|
|
if (!val)
|
|
werror (E_CONST_EXPECTED);
|
|
else if (!ulFromVal(val))
|
|
werror (W_STATIC_ASSERTION_2);
|
|
}
|
|
;
|
|
|
|
statement
|
|
: labeled_statement
|
|
| compound_statement
|
|
| expression_statement
|
|
| selection_statement
|
|
| iteration_statement
|
|
| jump_statement
|
|
| critical_statement
|
|
| asm_statement
|
|
;
|
|
|
|
critical
|
|
: CRITICAL {
|
|
if (inCriticalFunction || inCriticalBlock)
|
|
werror(E_INVALID_CRITICAL);
|
|
inCriticalBlock = 1;
|
|
STACK_PUSH(continueStack,NULL);
|
|
STACK_PUSH(breakStack,NULL);
|
|
$$ = NULL;
|
|
}
|
|
;
|
|
|
|
critical_statement
|
|
: critical statement {
|
|
STACK_POP(breakStack);
|
|
STACK_POP(continueStack);
|
|
$$ = newNode(CRITICAL,$2,NULL);
|
|
inCriticalBlock = 0;
|
|
}
|
|
;
|
|
|
|
labeled_statement
|
|
: label statement { if ($1) {$$ = $1; $1->right = $2;} else $$ = newNode (BLOCK, NULL, NULL); }
|
|
| label '}'
|
|
{ /* Support a label without a statement at the end of a */
|
|
/* compound statement as a SDCC extension. Include the */
|
|
/* closing brace as part of the rule to avoid an */
|
|
/* unacceptably large number of shift/reduce conflicts */
|
|
/* and then reinsert it to be parsed a second time. */
|
|
werror(W_LABEL_WITHOUT_STATEMENT);
|
|
$$ = $1;
|
|
yychar = '}';
|
|
}
|
|
;
|
|
|
|
label
|
|
: identifier ':' { $$ = createLabel($1,NULL);
|
|
$1->isitmp = 0; }
|
|
| CASE constant_expr ':'
|
|
{
|
|
if (STACK_EMPTY(swStk))
|
|
$$ = createCase(NULL,$2,NULL);
|
|
else
|
|
$$ = createCase(STACK_PEEK(swStk),$2,NULL);
|
|
}
|
|
| DEFAULT { $<asts>$ = newNode(DEFAULT,NULL,NULL); } ':'
|
|
{
|
|
if (STACK_EMPTY(swStk))
|
|
$$ = createDefault(NULL,$<asts>2,NULL);
|
|
else
|
|
$$ = createDefault(STACK_PEEK(swStk),$<asts>2,NULL);
|
|
}
|
|
;
|
|
|
|
start_block
|
|
: '{'
|
|
{
|
|
NestLevel += LEVEL_UNIT;
|
|
STACK_PUSH(blockNum, currBlockno);
|
|
btree_add_child(currBlockno, ++blockNo);
|
|
currBlockno = blockNo;
|
|
ignoreTypedefType = 0;
|
|
}
|
|
;
|
|
|
|
end_block
|
|
: '}'
|
|
{
|
|
NestLevel -= LEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
}
|
|
;
|
|
|
|
compound_statement
|
|
: start_block end_block { $$ = createBlock(NULL, NULL); }
|
|
| start_block block_item_list end_block
|
|
{
|
|
$$ = $2;
|
|
cleanUpLevel(StructTab, NestLevel + LEVEL_UNIT);
|
|
}
|
|
| error ';' { $$ = NULL; }
|
|
;
|
|
|
|
block_item_list
|
|
: statements_and_implicit { $$ = createBlock(NULL, $1); }
|
|
| declaration_list { $$ = createBlock($1, NULL); }
|
|
| declaration_list statements_and_implicit { $$ = createBlock($1, $2); }
|
|
;
|
|
|
|
statements_and_implicit
|
|
: statement_list
|
|
| statement_list implicit_block
|
|
{
|
|
$$ = newNode(NULLOP, $1, $2);
|
|
if (!options.std_c99)
|
|
werror(E_DECL_AFTER_STATEMENT_C99);
|
|
}
|
|
;
|
|
|
|
declaration_after_statement
|
|
: {
|
|
NestLevel += SUBLEVEL_UNIT;
|
|
STACK_PUSH(blockNum, currBlockno);
|
|
btree_add_child(currBlockno, ++blockNo);
|
|
currBlockno = blockNo;
|
|
ignoreTypedefType = 0;
|
|
}
|
|
declaration_list { $$ = $2; }
|
|
;
|
|
|
|
implicit_block
|
|
: declaration_after_statement statements_and_implicit
|
|
{
|
|
NestLevel -= SUBLEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
$$ = createBlock($1, $2);
|
|
cleanUpLevel(StructTab, NestLevel + SUBLEVEL_UNIT);
|
|
}
|
|
| declaration_after_statement
|
|
{
|
|
NestLevel -= SUBLEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
$$ = createBlock($1, NULL);
|
|
cleanUpLevel(StructTab, NestLevel + SUBLEVEL_UNIT);
|
|
}
|
|
;
|
|
|
|
declaration_list
|
|
: declaration
|
|
{
|
|
/* if this is typedef declare it immediately */
|
|
if ( $1 && IS_TYPEDEF($1->etype)) {
|
|
allocVariables ($1);
|
|
$$ = NULL;
|
|
}
|
|
else
|
|
$$ = $1;
|
|
ignoreTypedefType = 0;
|
|
addSymChain(&$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;
|
|
}
|
|
ignoreTypedefType = 0;
|
|
addSymChain(&$2);
|
|
}
|
|
;
|
|
|
|
statement_list
|
|
: statement
|
|
| statement_list statement { $$ = newNode(NULLOP,$1,$2);}
|
|
;
|
|
|
|
expression_statement
|
|
: ';' { $$ = NULL;}
|
|
| expr ';' { $$ = $1; seqPointNo++;}
|
|
;
|
|
|
|
else_statement
|
|
: ELSE statement { $$ = $2; }
|
|
| { $$ = NULL; }
|
|
;
|
|
|
|
|
|
selection_statement
|
|
: IF '(' expr ')' { seqPointNo++;} statement else_statement
|
|
{
|
|
noLineno++;
|
|
$$ = createIf ($3, $6, $7 );
|
|
$$->lineno = $3->lineno;
|
|
$$->filename = $3->filename;
|
|
noLineno--;
|
|
}
|
|
| SWITCH '(' expr ')' {
|
|
ast *ex;
|
|
static int swLabel = 0;
|
|
|
|
seqPointNo++;
|
|
/* 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 */
|
|
SNPRINTF(lbuff, sizeof(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 */
|
|
SNPRINTF (lbuff, sizeof(lbuff), "_whilecontinue_%d",Lblnum);
|
|
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
|
|
/* break */
|
|
SNPRINTF (lbuff, sizeof(lbuff), "_whilebreak_%d",Lblnum);
|
|
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
|
|
/* body */
|
|
SNPRINTF (lbuff, sizeof(lbuff), "_whilebody_%d",Lblnum++);
|
|
$$ = newSymbol(lbuff,NestLevel);
|
|
}
|
|
;
|
|
|
|
do : DO { /* create and push the continue , break & body Labels */
|
|
static int Lblnum = 0;
|
|
|
|
/* continue */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_docontinue_%d",Lblnum);
|
|
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
|
|
/* break */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_dobreak_%d",Lblnum);
|
|
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
|
|
/* do body */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_dobody_%d",Lblnum++);
|
|
$$ = newSymbol (lbuff,NestLevel);
|
|
}
|
|
;
|
|
|
|
for : FOR { /* create & push continue, break & body labels */
|
|
static int Lblnum = 0;
|
|
|
|
NestLevel += LEVEL_UNIT;
|
|
STACK_PUSH(blockNum, currBlockno);
|
|
btree_add_child(currBlockno, ++blockNo);
|
|
currBlockno = blockNo;
|
|
ignoreTypedefType = 0;
|
|
|
|
/* continue */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_forcontinue_%d",Lblnum);
|
|
STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
|
|
/* break */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_forbreak_%d",Lblnum);
|
|
STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
|
|
/* body */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_forbody_%d",Lblnum);
|
|
$$ = newSymbol(lbuff,NestLevel);
|
|
/* condition */
|
|
SNPRINTF(lbuff, sizeof(lbuff), "_forcond_%d",Lblnum++);
|
|
STACK_PUSH(forStack,newSymbol(lbuff,NestLevel));
|
|
}
|
|
;
|
|
|
|
iteration_statement
|
|
: while '(' expr ')' { seqPointNo++;} statement
|
|
{
|
|
noLineno++;
|
|
$$ = createWhile ( $1, STACK_POP(continueStack),
|
|
STACK_POP(breakStack), $3, $6 );
|
|
$$->lineno = $1->lineDef;
|
|
$$->filename = $1->fileDef;
|
|
noLineno--;
|
|
}
|
|
| do statement WHILE '(' expr ')' ';'
|
|
{
|
|
seqPointNo++;
|
|
noLineno++;
|
|
$$ = createDo ( $1 , STACK_POP(continueStack),
|
|
STACK_POP(breakStack), $5, $2);
|
|
$$->lineno = $1->lineDef;
|
|
$$->filename = $1->fileDef;
|
|
noLineno--;
|
|
}
|
|
| for '(' expr_opt ';' expr_opt ';' expr_opt ')' statement
|
|
{
|
|
noLineno++;
|
|
|
|
$$ = 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;
|
|
|
|
/* This continue label is not at the correct location, */
|
|
/* but we need to create it now for proper binding. The */
|
|
/* code that handles the FOR node will move it to the */
|
|
/* proper location inside the for loop. */
|
|
if (AST_FOR($$,continueLabel)->isref)
|
|
$$->right = createLabel(AST_FOR($$,continueLabel),NULL);
|
|
$$ = newNode(NULLOP,$$,createLabel(AST_FOR($$,falseLabel),NULL));
|
|
noLineno--;
|
|
|
|
NestLevel -= LEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
}
|
|
| for '(' declaration expr_opt ';' expr_opt ')'
|
|
{
|
|
if (!options.std_c99)
|
|
werror (E_FOR_INITAL_DECLARATION_C99);
|
|
|
|
if ( $3 && IS_TYPEDEF($3->etype))
|
|
allocVariables ($3);
|
|
ignoreTypedefType = 0;
|
|
addSymChain(&$3);
|
|
}
|
|
statement
|
|
{
|
|
|
|
noLineno++;
|
|
|
|
$$ = 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) = 0;
|
|
AST_FOR($$,condExpr) = $4;
|
|
AST_FOR($$,loopExpr) = $6;
|
|
|
|
/* This continue label is not at the correct location, */
|
|
/* but we need to create it now for proper binding. The */
|
|
/* code that handles the FOR node will move it to the */
|
|
/* proper location inside the for loop. */
|
|
if (AST_FOR($$,continueLabel)->isref)
|
|
$$->right = createLabel(AST_FOR($$,continueLabel),NULL);
|
|
$$ = createBlock($3, newNode(NULLOP,$$,createLabel(AST_FOR($$,falseLabel),NULL)));
|
|
cleanUpLevel(StructTab, NestLevel + LEVEL_UNIT);
|
|
noLineno--;
|
|
|
|
NestLevel -= LEVEL_UNIT;
|
|
currBlockno = STACK_POP(blockNum);
|
|
}
|
|
;
|
|
|
|
expr_opt
|
|
: { $$ = NULL; seqPointNo++; }
|
|
| expr { $$ = $1; seqPointNo++; }
|
|
;
|
|
|
|
jump_statement
|
|
: GOTO identifier ';' {
|
|
if (inCriticalBlock) {
|
|
werror(E_INVALID_CRITICAL);
|
|
$$ = NULL;
|
|
} else {
|
|
$2->islbl = 1;
|
|
$$ = newAst_VALUE(symbolVal($2));
|
|
$$ = newNode(GOTO,$$,NULL);
|
|
}
|
|
}
|
|
| CONTINUE ';' {
|
|
/* make sure continue is in context */
|
|
if (STACK_EMPTY(continueStack) || 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_EMPTY(breakStack) || 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 ';' {
|
|
seqPointNo++;
|
|
if (inCriticalBlock) {
|
|
werror(E_INVALID_CRITICAL);
|
|
$$ = NULL;
|
|
} else {
|
|
$$ = newNode(RETURN,NULL,NULL);
|
|
}
|
|
}
|
|
| RETURN expr ';' {
|
|
seqPointNo++;
|
|
if (inCriticalBlock) {
|
|
werror(E_INVALID_CRITICAL);
|
|
$$ = NULL;
|
|
} else {
|
|
$$ = newNode(RETURN,NULL,$2);
|
|
}
|
|
}
|
|
;
|
|
|
|
asm_string_literal
|
|
: STRING_LITERAL
|
|
;
|
|
|
|
asm_statement
|
|
: ASM '(' asm_string_literal ')' ';'
|
|
{
|
|
ast *ex;
|
|
|
|
seqPointNo++;
|
|
ex = newNode(INLINEASM, NULL, NULL);
|
|
ex->values.inlineasm = strdup(copyStr ($3, NULL));
|
|
seqPointNo++;
|
|
$$ = ex;
|
|
}
|
|
| INLINEASM ';'
|
|
{
|
|
ast *ex;
|
|
|
|
seqPointNo++;
|
|
ex = newNode(INLINEASM, NULL, NULL);
|
|
ex->values.inlineasm = strdup($1);
|
|
seqPointNo++;
|
|
$$ = ex;
|
|
}
|
|
;
|
|
|
|
addressmod
|
|
: ADDRESSMOD identifier identifier ';' {
|
|
symbol *sym;
|
|
if ((sym = findSymWithLevel (AddrspaceTab, $3)) && sym->level == $3->level)
|
|
werrorfl (sym->fileDef, sym->lineDef, E_PREVIOUS_DEF);
|
|
if (!findSymWithLevel (SymbolTab, $2))
|
|
werror (E_ID_UNDEF, $2->name);
|
|
addSym (AddrspaceTab, $3, $3->name, $3->level, $3->block, 0);
|
|
sym = findSymWithLevel (AddrspaceTab, $3);
|
|
sym->addressmod[0] = findSymWithLevel (SymbolTab, $2);
|
|
sym->addressmod[1] = 0;
|
|
}
|
|
| ADDRESSMOD identifier SD_CONST identifier ';' {
|
|
symbol *sym;
|
|
sym_link *type;
|
|
if ((sym = findSymWithLevel (AddrspaceTab, $4)) && sym->level == $4->level)
|
|
werrorfl (sym->fileDef, sym->lineDef, E_PREVIOUS_DEF);
|
|
if (!findSymWithLevel (SymbolTab, $2))
|
|
werror (E_ID_UNDEF, $2->name);
|
|
addSym (AddrspaceTab, $4, $4->name, $4->level, $4->block, 0);
|
|
sym = findSymWithLevel (AddrspaceTab, $4);
|
|
sym->addressmod[0] = findSymWithLevel (SymbolTab, $2);
|
|
sym->addressmod[1] = 0;
|
|
type = newLink (SPECIFIER);
|
|
SPEC_CONST(type) = 1;
|
|
sym->type = sym->etype = type;
|
|
}
|
|
;
|
|
|
|
identifier
|
|
: IDENTIFIER { $$ = newSymbol ($1, NestLevel); }
|
|
;
|
|
%%
|