diff options
| author | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
|---|---|---|
| committer | Xavier ASUS <xavi92psx@gmail.com> | 2019-10-18 00:31:54 +0200 |
| commit | 268a53de823a6750d6256ee1fb1e7707b4b45740 (patch) | |
| tree | 42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCC.y | |
| download | sdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz | |
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCC.y')
| -rw-r--r-- | src/SDCC.y | 2465 |
1 files changed, 2465 insertions, 0 deletions
diff --git a/src/SDCC.y b/src/SDCC.y new file mode 100644 index 0000000..ff79f69 --- /dev/null +++ b/src/SDCC.y @@ -0,0 +1,2465 @@ +/*----------------------------------------------------------------------- + + 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); } + ; +%% |
