diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1995-10-18 08:53:40 +0000 |
commit | d6583bb2a13f329cf0332ef2570eb8bb8fc0e39c (patch) | |
tree | ece253b876159b39c620e62b6c9b1174642e070e /usr.bin/xlint/lint1/cgram.y |
initial import of NetBSD tree
Diffstat (limited to 'usr.bin/xlint/lint1/cgram.y')
-rw-r--r-- | usr.bin/xlint/lint1/cgram.y | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/usr.bin/xlint/lint1/cgram.y b/usr.bin/xlint/lint1/cgram.y new file mode 100644 index 00000000000..e65584ac998 --- /dev/null +++ b/usr.bin/xlint/lint1/cgram.y @@ -0,0 +1,1675 @@ +%{ +/* $NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $ */ + +/* + * Copyright (c) 1994, 1995 Jochen Pohl + * All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jochen Pohl for + * The NetBSD Project. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef lint +static char rcsid[] = "$NetBSD: cgram.y,v 1.8 1995/10/02 17:31:35 jpo Exp $"; +#endif + +#include <stdlib.h> +#include <limits.h> + +#include "lint1.h" + +/* + * Contains the level of current declaration. 0 is extern. + * Used for symbol table entries. + */ +int blklev; + +/* + * level for memory allocation. Normaly the same as blklev. + * An exeption is the declaration of arguments in prototypes. Memory + * for these can't be freed after the declaration, but symbols must + * be removed from the symbol table after the declaration. + */ +int mblklev; + +static int toicon __P((tnode_t *)); +static void idecl __P((sym_t *, int)); +static void ignuptorp __P((void)); + +%} + +%union { + int y_int; + val_t *y_val; + sbuf_t *y_sb; + sym_t *y_sym; + op_t y_op; + scl_t y_scl; + tspec_t y_tspec; + tqual_t y_tqual; + type_t *y_type; + tnode_t *y_tnode; + strg_t *y_strg; + pqinf_t *y_pqinf; +}; + +%token T_LBRACE T_RBRACE T_LBRACK T_RBRACK T_LPARN T_RPARN +%token <y_op> T_STROP +%token <y_op> T_UNOP +%token <y_op> T_INCDEC +%token T_SIZEOF +%token <y_op> T_MULT +%token <y_op> T_DIVOP +%token <y_op> T_ADDOP +%token <y_op> T_SHFTOP +%token <y_op> T_RELOP +%token <y_op> T_EQOP +%token <y_op> T_AND +%token <y_op> T_XOR +%token <y_op> T_OR +%token <y_op> T_LOGAND +%token <y_op> T_LOGOR +%token T_QUEST +%token T_COLON +%token <y_op> T_ASSIGN +%token <y_op> T_OPASS +%token T_COMMA +%token T_SEMI +%token T_ELLIPSE + +/* storage classes (extern, static, auto, register and typedef) */ +%token <y_scl> T_SCLASS + +/* types (char, int, short, long, unsigned, signed, float, double, void) */ +%token <y_tspec> T_TYPE + +/* qualifiers (const, volatile) */ +%token <y_tqual> T_QUAL + +/* struct or union */ +%token <y_tspec> T_SOU + +/* enum */ +%token T_ENUM + +/* remaining keywords */ +%token T_CASE +%token T_DEFAULT +%token T_IF +%token T_ELSE +%token T_SWITCH +%token T_DO +%token T_WHILE +%token T_FOR +%token T_GOTO +%token T_CONTINUE +%token T_BREAK +%token T_RETURN +%token T_ASM + +%left T_COMMA +%right T_ASSIGN T_OPASS +%right T_QUEST T_COLON +%left T_LOGOR +%left T_LOGAND +%left T_OR +%left T_XOR +%left T_AND +%left T_EQOP +%left T_RELOP +%left T_SHFTOP +%left T_ADDOP +%left T_MULT T_DIVOP +%right T_UNOP T_INCDEC T_SIZEOF +%left T_LPARN T_LBRACK T_STROP + +%token <y_sb> T_NAME +%token <y_sb> T_TYPENAME +%token <y_val> T_CON +%token <y_strg> T_STRING + +%type <y_sym> func_decl +%type <y_sym> notype_decl +%type <y_sym> type_decl +%type <y_type> typespec +%type <y_type> clrtyp_typespec +%type <y_type> notype_typespec +%type <y_type> struct_spec +%type <y_type> enum_spec +%type <y_sym> struct_tag +%type <y_sym> enum_tag +%type <y_tspec> struct +%type <y_sym> struct_declaration +%type <y_sb> identifier +%type <y_sym> member_declaration_list_with_rbrace +%type <y_sym> member_declaration_list +%type <y_sym> member_declaration +%type <y_sym> notype_member_decls +%type <y_sym> type_member_decls +%type <y_sym> notype_member_decl +%type <y_sym> type_member_decl +%type <y_tnode> constant +%type <y_sym> enum_declaration +%type <y_sym> enums_with_opt_comma +%type <y_sym> enums +%type <y_sym> enumerator +%type <y_sym> ename +%type <y_sym> notype_direct_decl +%type <y_sym> type_direct_decl +%type <y_pqinf> pointer +%type <y_pqinf> asterisk +%type <y_sym> param_decl +%type <y_sym> param_list +%type <y_sym> abs_decl_param_list +%type <y_sym> direct_param_decl +%type <y_sym> notype_param_decl +%type <y_sym> direct_notype_param_decl +%type <y_pqinf> type_qualifier_list +%type <y_pqinf> type_qualifier +%type <y_sym> identifier_list +%type <y_sym> abs_decl +%type <y_sym> direct_abs_decl +%type <y_sym> vararg_parameter_type_list +%type <y_sym> parameter_type_list +%type <y_sym> parameter_declaration +%type <y_tnode> expr +%type <y_tnode> term +%type <y_tnode> func_arg_list +%type <y_op> point_or_arrow +%type <y_type> type_name +%type <y_sym> abstract_declaration +%type <y_tnode> do_while_expr +%type <y_tnode> opt_expr +%type <y_strg> string +%type <y_strg> string2 + + +%% + +program: + /* empty */ { + if (sflag) { + /* empty translation unit */ + error(272); + } else if (!tflag) { + /* empty translation unit */ + warning(272); + } + } + | translation_unit + ; + +translation_unit: + ext_decl + | translation_unit ext_decl + ; + +ext_decl: + func_def { + glclup(0); + clrwflgs(); + } + | data_def { + glclup(0); + clrwflgs(); + } + ; + +data_def: + T_SEMI { + if (sflag) { + /* syntax error: empty declaration */ + error(0); + } else if (!tflag) { + /* syntax error: empty declaration */ + warning(0); + } + } + | clrtyp deftyp notype_init_decls T_SEMI { + if (sflag) { + /* old style declaration; add "int" */ + error(1); + } else if (!tflag) { + /* old style declaration; add "int" */ + warning(1); + } + } + | declmods deftyp T_SEMI { + if (dcs->d_scl == TYPEDEF) { + /* typedef declares no type name */ + warning(72); + } else { + /* empty declaration */ + warning(2); + } + } + | declmods deftyp notype_init_decls T_SEMI + | declspecs deftyp T_SEMI { + if (dcs->d_scl == TYPEDEF) { + /* typedef declares no type name */ + warning(72); + } else if (!dcs->d_nedecl) { + /* empty declaration */ + warning(2); + } + } + | declspecs deftyp type_init_decls T_SEMI + | error T_SEMI { + globclup(); + } + | error T_RBRACE { + globclup(); + } + ; + +func_def: + func_decl { + if ($1->s_type->t_tspec != FUNC) { + /* syntax error */ + error(249); + YYERROR; + } + if ($1->s_type->t_typedef) { + /* ()-less function definition */ + error(64); + YYERROR; + } + funcdef($1); + blklev++; + pushdecl(ARG); + } opt_arg_declaration_list { + popdecl(); + blklev--; + cluparg(); + pushctrl(0); + } comp_stmnt { + funcend(); + popctrl(0); + } + ; + +func_decl: + clrtyp deftyp notype_decl { + $$ = $3; + } + | declmods deftyp notype_decl { + $$ = $3; + } + | declspecs deftyp type_decl { + $$ = $3; + } + ; + +opt_arg_declaration_list: + /* empty */ + | arg_declaration_list + ; + +arg_declaration_list: + arg_declaration + | arg_declaration_list arg_declaration + /* XXX or better "arg_declaration error" ? */ + | error + ; + +/* + * "arg_declaration" is separated from "declaration" because it + * needs other error handling. + */ + +arg_declaration: + declmods deftyp T_SEMI { + /* empty declaration */ + warning(2); + } + | declmods deftyp notype_init_decls T_SEMI + | declspecs deftyp T_SEMI { + if (!dcs->d_nedecl) { + /* empty declaration */ + warning(2); + } else { + tspec_t ts = dcs->d_type->t_tspec; + /* %s declared in argument declaration list */ + warning(3, ts == STRUCT ? "struct" : + (ts == UNION ? "union" : "enum")); + } + } + | declspecs deftyp type_init_decls T_SEMI { + if (dcs->d_nedecl) { + tspec_t ts = dcs->d_type->t_tspec; + /* %s declared in argument declaration list */ + warning(3, ts == STRUCT ? "struct" : + (ts == UNION ? "union" : "enum")); + } + } + | declmods error + | declspecs error + ; + +declaration: + declmods deftyp T_SEMI { + if (dcs->d_scl == TYPEDEF) { + /* typedef declares no type name */ + warning(72); + } else { + /* empty declaration */ + warning(2); + } + } + | declmods deftyp notype_init_decls T_SEMI + | declspecs deftyp T_SEMI { + if (dcs->d_scl == TYPEDEF) { + /* typedef declares no type name */ + warning(72); + } else if (!dcs->d_nedecl) { + /* empty declaration */ + warning(2); + } + } + | declspecs deftyp type_init_decls T_SEMI + | error T_SEMI + ; + +clrtyp: + { + clrtyp(); + } + ; + +deftyp: + /* empty */ { + deftyp(); + } + ; + +declspecs: + clrtyp_typespec { + addtype($1); + } + | declmods typespec { + addtype($2); + } + | declspecs declmod + | declspecs notype_typespec { + addtype($2); + } + ; + +declmods: + clrtyp T_QUAL { + addqual($2); + } + | clrtyp T_SCLASS { + addscl($2); + } + | declmods declmod + ; + +declmod: + T_QUAL { + addqual($1); + } + | T_SCLASS { + addscl($1); + } + ; + +clrtyp_typespec: + clrtyp notype_typespec { + $$ = $2; + } + | T_TYPENAME clrtyp { + $$ = getsym($1)->s_type; + } + ; + +typespec: + notype_typespec { + $$ = $1; + } + | T_TYPENAME { + $$ = getsym($1)->s_type; + } + ; + +notype_typespec: + T_TYPE { + $$ = gettyp($1); + } + | struct_spec { + popdecl(); + $$ = $1; + } + | enum_spec { + popdecl(); + $$ = $1; + } + ; + +struct_spec: + struct struct_tag { + /* + * STDC requires that "struct a;" always introduces + * a new tag if "a" is not declared at current level + * + * yychar is valid because otherwise the parser would + * not been able to deceide if he must shift or reduce + */ + $$ = mktag($2, $1, 0, yychar == T_SEMI); + } + | struct struct_tag { + dcs->d_tagtyp = mktag($2, $1, 1, 0); + } struct_declaration { + $$ = compltag(dcs->d_tagtyp, $4); + } + | struct { + dcs->d_tagtyp = mktag(NULL, $1, 1, 0); + } struct_declaration { + $$ = compltag(dcs->d_tagtyp, $3); + } + | struct error { + symtyp = FVFT; + $$ = gettyp(INT); + } + ; + +struct: + T_SOU { + symtyp = FTAG; + pushdecl($1 == STRUCT ? MOS : MOU); + dcs->d_offset = 0; + dcs->d_stralign = CHAR_BIT; + $$ = $1; + } + ; + +struct_tag: + identifier { + $$ = getsym($1); + } + ; + +struct_declaration: + struct_decl_lbrace member_declaration_list_with_rbrace { + $$ = $2; + } + ; + +struct_decl_lbrace: + T_LBRACE { + symtyp = FVFT; + } + ; + +member_declaration_list_with_rbrace: + member_declaration_list T_SEMI T_RBRACE { + $$ = $1; + } + | member_declaration_list T_RBRACE { + if (sflag) { + /* syntax req. ";" after last struct/union member */ + error(66); + } else { + /* syntax req. ";" after last struct/union member */ + warning(66); + } + $$ = $1; + } + | T_RBRACE { + $$ = NULL; + } + ; + +member_declaration_list: + member_declaration { + $$ = $1; + } + | member_declaration_list T_SEMI member_declaration { + $$ = lnklst($1, $3); + } + ; + +member_declaration: + noclass_declmods deftyp { + /* too late, i know, but getsym() compensates it */ + symtyp = FMOS; + } notype_member_decls { + symtyp = FVFT; + $$ = $4; + } + | noclass_declspecs deftyp { + symtyp = FMOS; + } type_member_decls { + symtyp = FVFT; + $$ = $4; + } + | noclass_declmods deftyp { + /* struct or union member must be named */ + warning(49); + $$ = NULL; + } + | noclass_declspecs deftyp { + /* struct or union member must be named */ + warning(49); + $$ = NULL; + } + | error { + symtyp = FVFT; + $$ = NULL; + } + ; + +noclass_declspecs: + clrtyp_typespec { + addtype($1); + } + | noclass_declmods typespec { + addtype($2); + } + | noclass_declspecs T_QUAL { + addqual($2); + } + | noclass_declspecs notype_typespec { + addtype($2); + } + ; + +noclass_declmods: + clrtyp T_QUAL { + addqual($2); + } + | noclass_declmods T_QUAL { + addqual($2); + } + ; + +notype_member_decls: + notype_member_decl { + $$ = decl1str($1); + } + | notype_member_decls { + symtyp = FMOS; + } T_COMMA type_member_decl { + $$ = lnklst($1, decl1str($4)); + } + ; + +type_member_decls: + type_member_decl { + $$ = decl1str($1); + } + | type_member_decls { + symtyp = FMOS; + } T_COMMA type_member_decl { + $$ = lnklst($1, decl1str($4)); + } + ; + +notype_member_decl: + notype_decl { + $$ = $1; + } + | notype_decl T_COLON constant { + $$ = bitfield($1, toicon($3)); + } + | { + symtyp = FVFT; + } T_COLON constant { + $$ = bitfield(NULL, toicon($3)); + } + ; + +type_member_decl: + type_decl { + $$ = $1; + } + | type_decl T_COLON constant { + $$ = bitfield($1, toicon($3)); + } + | { + symtyp = FVFT; + } T_COLON constant { + $$ = bitfield(NULL, toicon($3)); + } + ; + +enum_spec: + enum enum_tag { + $$ = mktag($2, ENUM, 0, 0); + } + | enum enum_tag { + dcs->d_tagtyp = mktag($2, ENUM, 1, 0); + } enum_declaration { + $$ = compltag(dcs->d_tagtyp, $4); + } + | enum { + dcs->d_tagtyp = mktag(NULL, ENUM, 1, 0); + } enum_declaration { + $$ = compltag(dcs->d_tagtyp, $3); + } + | enum error { + symtyp = FVFT; + $$ = gettyp(INT); + } + ; + +enum: + T_ENUM { + symtyp = FTAG; + pushdecl(ENUMCON); + } + ; + +enum_tag: + identifier { + $$ = getsym($1); + } + ; + +enum_declaration: + enum_decl_lbrace enums_with_opt_comma T_RBRACE { + $$ = $2; + } + ; + +enum_decl_lbrace: + T_LBRACE { + symtyp = FVFT; + enumval = 0; + } + ; + +enums_with_opt_comma: + enums { + $$ = $1; + } + | enums T_COMMA { + if (sflag) { + /* trailing "," prohibited in enum declaration */ + error(54); + } else { + /* trailing "," prohibited in enum declaration */ + warning(54); + } + $$ = $1; + } + ; + +enums: + enumerator { + $$ = $1; + } + | enums T_COMMA enumerator { + $$ = lnklst($1, $3); + } + | error { + $$ = NULL; + } + ; + +enumerator: + ename { + $$ = ename($1, enumval, 1); + } + | ename T_ASSIGN constant { + $$ = ename($1, toicon($3), 0); + } + ; + +ename: + identifier { + $$ = getsym($1); + } + ; + + +notype_init_decls: + notype_init_decl + | notype_init_decls T_COMMA type_init_decl + ; + +type_init_decls: + type_init_decl + | type_init_decls T_COMMA type_init_decl + ; + +notype_init_decl: + notype_decl opt_asm_spec { + idecl($1, 0); + chksz($1); + } + | notype_decl opt_asm_spec { + idecl($1, 1); + } T_ASSIGN initializer { + chksz($1); + } + ; + +type_init_decl: + type_decl opt_asm_spec { + idecl($1, 0); + chksz($1); + } + | type_decl opt_asm_spec { + idecl($1, 1); + } T_ASSIGN initializer { + chksz($1); + } + ; + +notype_decl: + notype_direct_decl { + $$ = $1; + } + | pointer notype_direct_decl { + $$ = addptr($2, $1); + } + ; + +notype_direct_decl: + T_NAME { + $$ = dname(getsym($1)); + } + | T_LPARN type_decl T_RPARN { + $$ = $2; + } + | notype_direct_decl T_LBRACK T_RBRACK { + $$ = addarray($1, 0, 0); + } + | notype_direct_decl T_LBRACK constant T_RBRACK { + $$ = addarray($1, 1, toicon($3)); + } + | notype_direct_decl param_list { + $$ = addfunc($1, $2); + popdecl(); + blklev--; + } + ; + +type_decl: + type_direct_decl { + $$ = $1; + } + | pointer type_direct_decl { + $$ = addptr($2, $1); + } + ; + +type_direct_decl: + identifier { + $$ = dname(getsym($1)); + } + | T_LPARN type_decl T_RPARN { + $$ = $2; + } + | type_direct_decl T_LBRACK T_RBRACK { + $$ = addarray($1, 0, 0); + } + | type_direct_decl T_LBRACK constant T_RBRACK { + $$ = addarray($1, 1, toicon($3)); + } + | type_direct_decl param_list { + $$ = addfunc($1, $2); + popdecl(); + blklev--; + } + ; + +/* + * param_decl and notype_param_decl exist to avoid a conflict in + * argument lists. A typename enclosed in parens should always be + * treated as a typename, not an argument. + * "typedef int a; f(int (a));" is "typedef int a; f(int foo(a));" + * not "typedef int a; f(int a);" + */ +param_decl: + direct_param_decl { + $$ = $1; + } + | pointer direct_param_decl { + $$ = addptr($2, $1); + } + ; + +direct_param_decl: + identifier { + $$ = dname(getsym($1)); + } + | T_LPARN notype_param_decl T_RPARN { + $$ = $2; + } + | direct_param_decl T_LBRACK T_RBRACK { + $$ = addarray($1, 0, 0); + } + | direct_param_decl T_LBRACK constant T_RBRACK { + $$ = addarray($1, 1, toicon($3)); + } + | direct_param_decl param_list { + $$ = addfunc($1, $2); + popdecl(); + blklev--; + } + ; + +notype_param_decl: + direct_notype_param_decl { + $$ = $1; + } + | pointer direct_notype_param_decl { + $$ = addptr($2, $1); + } + ; + +direct_notype_param_decl: + T_NAME { + $$ = dname(getsym($1)); + } + | T_LPARN notype_param_decl T_RPARN { + $$ = $2; + } + | direct_notype_param_decl T_LBRACK T_RBRACK { + $$ = addarray($1, 0, 0); + } + | direct_notype_param_decl T_LBRACK constant T_RBRACK { + $$ = addarray($1, 1, toicon($3)); + } + | direct_notype_param_decl param_list { + $$ = addfunc($1, $2); + popdecl(); + blklev--; + } + ; + +pointer: + asterisk { + $$ = $1; + } + | asterisk type_qualifier_list { + $$ = mergepq($1, $2); + } + | asterisk pointer { + $$ = mergepq($1, $2); + } + | asterisk type_qualifier_list pointer { + $$ = mergepq(mergepq($1, $2), $3); + } + ; + +asterisk: + T_MULT { + $$ = xcalloc(1, sizeof (pqinf_t)); + $$->p_pcnt = 1; + } + ; + +type_qualifier_list: + type_qualifier { + $$ = $1; + } + | type_qualifier_list type_qualifier { + $$ = mergepq($1, $2); + } + ; + +type_qualifier: + T_QUAL { + $$ = xcalloc(1, sizeof (pqinf_t)); + if ($1 == CONST) { + $$->p_const = 1; + } else { + $$->p_volatile = 1; + } + } + ; + +param_list: + id_list_lparn identifier_list T_RPARN { + $$ = $2; + } + | abs_decl_param_list { + $$ = $1; + } + ; + +id_list_lparn: + T_LPARN { + blklev++; + pushdecl(PARG); + } + ; + +identifier_list: + T_NAME { + $$ = iname(getsym($1)); + } + | identifier_list T_COMMA T_NAME { + $$ = lnklst($1, iname(getsym($3))); + } + | identifier_list error { + $$ = $1; + } + ; + +abs_decl_param_list: + abs_decl_lparn T_RPARN { + $$ = NULL; + } + | abs_decl_lparn vararg_parameter_type_list T_RPARN { + dcs->d_proto = 1; + $$ = $2; + } + | abs_decl_lparn error T_RPARN { + $$ = NULL; + } + ; + +abs_decl_lparn: + T_LPARN { + blklev++; + pushdecl(PARG); + } + ; + +vararg_parameter_type_list: + parameter_type_list { + $$ = $1; + } + | parameter_type_list T_COMMA T_ELLIPSE { + dcs->d_vararg = 1; + $$ = $1; + } + | T_ELLIPSE { + if (sflag) { + /* ANSI C requires formal parameter before "..." */ + error(84); + } else if (!tflag) { + /* ANSI C requires formal parameter before "..." */ + warning(84); + } + dcs->d_vararg = 1; + $$ = NULL; + } + ; + +parameter_type_list: + parameter_declaration opt_asm_spec { + $$ = $1; + } + | parameter_type_list T_COMMA parameter_declaration opt_asm_spec { + $$ = lnklst($1, $3); + } + ; + +parameter_declaration: + declmods deftyp { + $$ = decl1arg(aname(), 0); + } + | declspecs deftyp { + $$ = decl1arg(aname(), 0); + } + | declmods deftyp notype_param_decl { + $$ = decl1arg($3, 0); + } + /* + * param_decl is needed because of following conflict: + * "typedef int a; f(int (a));" could be parsed as + * "function with argument a of type int", or + * "function with an abstract argument of type function". + * This grammar realizes the second case. + */ + | declspecs deftyp param_decl { + $$ = decl1arg($3, 0); + } + | declmods deftyp abs_decl { + $$ = decl1arg($3, 0); + } + | declspecs deftyp abs_decl { + $$ = decl1arg($3, 0); + } + ; + +opt_asm_spec: + /* empty */ + | T_ASM T_LPARN T_STRING T_RPARN { + freeyyv(&$3, T_STRING); + } + ; + +initializer: + init_expr + ; + +init_expr: + expr %prec T_COMMA { + mkinit($1); + } + | init_lbrace init_expr_list init_rbrace + | init_lbrace init_expr_list T_COMMA init_rbrace + | error + ; + +init_expr_list: + init_expr %prec T_COMMA + | init_expr_list T_COMMA init_expr + ; + +init_lbrace: + T_LBRACE { + initlbr(); + } + ; + +init_rbrace: + T_RBRACE { + initrbr(); + } + ; + +type_name: + { + pushdecl(ABSTRACT); + } abstract_declaration { + popdecl(); + $$ = $2->s_type; + } + ; + +abstract_declaration: + noclass_declmods deftyp { + $$ = decl1abs(aname()); + } + | noclass_declspecs deftyp { + $$ = decl1abs(aname()); + } + | noclass_declmods deftyp abs_decl { + $$ = decl1abs($3); + } + | noclass_declspecs deftyp abs_decl { + $$ = decl1abs($3); + } + ; + +abs_decl: + pointer { + $$ = addptr(aname(), $1); + } + | direct_abs_decl { + $$ = $1; + } + | pointer direct_abs_decl { + $$ = addptr($2, $1); + } + ; + +direct_abs_decl: + T_LPARN abs_decl T_RPARN { + $$ = $2; + } + | T_LBRACK T_RBRACK { + $$ = addarray(aname(), 0, 0); + } + | T_LBRACK constant T_RBRACK { + $$ = addarray(aname(), 1, toicon($2)); + } + | direct_abs_decl T_LBRACK T_RBRACK { + $$ = addarray($1, 0, 0); + } + | direct_abs_decl T_LBRACK constant T_RBRACK { + $$ = addarray($1, 1, toicon($3)); + } + | abs_decl_param_list { + $$ = addfunc(aname(), $1); + popdecl(); + blklev--; + } + | direct_abs_decl abs_decl_param_list { + $$ = addfunc($1, $2); + popdecl(); + blklev--; + } + ; + +stmnt: + labeled_stmnt + | expr_stmnt + | comp_stmnt + | selection_stmnt + | iteration_stmnt + | jump_stmnt { + ftflg = 0; + } + | asm_stmnt + ; + +labeled_stmnt: + label stmnt + ; + +label: + identifier T_COLON { + symtyp = FLAB; + label(T_NAME, getsym($1), NULL); + } + | T_CASE constant T_COLON { + label(T_CASE, NULL, $2); + ftflg = 1; + } + | T_DEFAULT T_COLON { + label(T_DEFAULT, NULL, NULL); + ftflg = 1; + } + ; + +comp_stmnt: + compstmnt_lbrace declaration_list opt_stmnt_list compstmnt_rbrace + | compstmnt_lbrace opt_stmnt_list compstmnt_rbrace + ; + +compstmnt_lbrace: + T_LBRACE { + blklev++; + mblklev++; + pushdecl(AUTO); + } + ; + +compstmnt_rbrace: + T_RBRACE { + popdecl(); + freeblk(); + mblklev--; + blklev--; + ftflg = 0; + } + ; + +opt_stmnt_list: + /* empty */ + | stmnt_list + ; + +stmnt_list: + stmnt { + clrwflgs(); + } + | stmnt_list stmnt { + clrwflgs(); + } + | stmnt_list error T_SEMI { + clrwflgs(); + } + ; + +expr_stmnt: + expr T_SEMI { + expr($1, 0, 0); + ftflg = 0; + } + | T_SEMI { + ftflg = 0; + } + ; + +selection_stmnt: + if_without_else { + if2(); + if3(0); + } + | if_without_else T_ELSE { + if2(); + } stmnt { + if3(1); + } + | if_without_else T_ELSE error { + if3(0); + } + | switch_expr stmnt { + switch2(); + } + | switch_expr error { + switch2(); + } + ; + +if_without_else: + if_expr stmnt + | if_expr error + ; + +if_expr: + T_IF T_LPARN expr T_RPARN { + if1($3); + clrwflgs(); + } + ; + +switch_expr: + T_SWITCH T_LPARN expr T_RPARN { + switch1($3); + clrwflgs(); + } + ; + +iteration_stmnt: + while_expr stmnt { + while2(); + } + | while_expr error { + while2(); + } + | do stmnt do_while_expr { + do2($3); + ftflg = 0; + } + | do error { + do2(NULL); + } + | for_exprs stmnt { + for2(); + } + | for_exprs error { + for2(); + } + ; + +while_expr: + T_WHILE T_LPARN expr T_RPARN { + while1($3); + clrwflgs(); + } + ; + +do: + T_DO { + do1(); + } + ; + +do_while_expr: + T_WHILE T_LPARN expr T_RPARN T_SEMI { + $$ = $3; + } + ; + +for_exprs: + T_FOR T_LPARN opt_expr T_SEMI opt_expr T_SEMI opt_expr T_RPARN { + for1($3, $5, $7); + clrwflgs(); + } + ; + +opt_expr: + /* empty */ { + $$ = NULL; + } + | expr { + $$ = $1; + } + ; + +jump_stmnt: + goto identifier T_SEMI { + dogoto(getsym($2)); + } + | goto error T_SEMI { + symtyp = FVFT; + } + | T_CONTINUE T_SEMI { + docont(); + } + | T_BREAK T_SEMI { + dobreak(); + } + | T_RETURN T_SEMI { + doreturn(NULL); + } + | T_RETURN expr T_SEMI { + doreturn($2); + } + ; + +goto: + T_GOTO { + symtyp = FLAB; + } + ; + +asm_stmnt: + T_ASM T_LPARN read_until_rparn T_SEMI { + setasm(); + } + | T_ASM T_QUAL T_LPARN read_until_rparn T_SEMI { + setasm(); + } + | T_ASM error + ; + +read_until_rparn: + /* empty */ { + ignuptorp(); + } + ; + +declaration_list: + declaration { + clrwflgs(); + } + | declaration_list declaration { + clrwflgs(); + } + ; + +constant: + expr %prec T_COMMA { + $$ = $1; + } + ; + +expr: + expr T_MULT expr { + $$ = build(MULT, $1, $3); + } + | expr T_DIVOP expr { + $$ = build($2, $1, $3); + } + | expr T_ADDOP expr { + $$ = build($2, $1, $3); + } + | expr T_SHFTOP expr { + $$ = build($2, $1, $3); + } + | expr T_RELOP expr { + $$ = build($2, $1, $3); + } + | expr T_EQOP expr { + $$ = build($2, $1, $3); + } + | expr T_AND expr { + $$ = build(AND, $1, $3); + } + | expr T_XOR expr { + $$ = build(XOR, $1, $3); + } + | expr T_OR expr { + $$ = build(OR, $1, $3); + } + | expr T_LOGAND expr { + $$ = build(LOGAND, $1, $3); + } + | expr T_LOGOR expr { + $$ = build(LOGOR, $1, $3); + } + | expr T_QUEST expr T_COLON expr { + $$ = build(QUEST, $1, build(COLON, $3, $5)); + } + | expr T_ASSIGN expr { + $$ = build(ASSIGN, $1, $3); + } + | expr T_OPASS expr { + $$ = build($2, $1, $3); + } + | expr T_COMMA expr { + $$ = build(COMMA, $1, $3); + } + | term { + $$ = $1; + } + ; + +term: + T_NAME { + /* XXX realy neccessary? */ + if (yychar < 0) + yychar = yylex(); + $$ = getnnode(getsym($1), yychar); + } + | string { + $$ = getsnode($1); + } + | T_CON { + $$ = getcnode(gettyp($1->v_tspec), $1); + } + | T_LPARN expr T_RPARN { + if ($2 != NULL) + $2->tn_parn = 1; + $$ = $2; + } + | term T_INCDEC { + $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL); + } + | T_INCDEC term { + $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL); + } + | T_MULT term { + $$ = build(STAR, $2, NULL); + } + | T_AND term { + $$ = build(AMPER, $2, NULL); + } + | T_UNOP term { + $$ = build($1, $2, NULL); + } + | T_ADDOP term { + if (tflag && $1 == PLUS) { + /* unary + is illegal in traditional C */ + warning(100); + } + $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL); + } + | term T_LBRACK expr T_RBRACK { + $$ = build(STAR, build(PLUS, $1, $3), NULL); + } + | term T_LPARN T_RPARN { + $$ = funccall($1, NULL); + } + | term T_LPARN func_arg_list T_RPARN { + $$ = funccall($1, $3); + } + | term point_or_arrow T_NAME { + if ($1 != NULL) { + sym_t *msym; + /* XXX strmemb should be integrated in build() */ + if ($2 == ARROW) { + /* must to this before strmemb is called */ + $1 = cconv($1); + } + msym = strmemb($1, $2, getsym($3)); + $$ = build($2, $1, getnnode(msym, 0)); + } else { + $$ = NULL; + } + } + | T_SIZEOF term %prec T_SIZEOF { + if (($$ = $2 == NULL ? NULL : bldszof($2->tn_type)) != NULL) + chkmisc($2, 0, 0, 0, 0, 0, 1); + } + | T_SIZEOF T_LPARN type_name T_RPARN %prec T_SIZEOF { + $$ = bldszof($3); + } + | T_LPARN type_name T_RPARN term %prec T_UNOP { + $$ = cast($4, $2); + } + ; + +string: + T_STRING { + $$ = $1; + } + | T_STRING string2 { + $$ = catstrg($1, $2); + } + ; + +string2: + T_STRING { + if (tflag) { + /* concatenated strings are illegal in traditional C */ + warning(219); + } + $$ = $1; + } + | string2 T_STRING { + $$ = catstrg($1, $2); + } + ; + +func_arg_list: + expr %prec T_COMMA { + $$ = funcarg(NULL, $1); + } + | func_arg_list T_COMMA expr { + $$ = funcarg($1, $3); + } + ; + +point_or_arrow: + T_STROP { + symtyp = FMOS; + $$ = $1; + } + ; + +identifier: + T_NAME { + $$ = $1; + } + | T_TYPENAME { + $$ = $1; + } + ; + +%% + +/* ARGSUSED */ +int +yyerror(msg) + char *msg; +{ + error(249); + if (++sytxerr >= 5) + norecover(); + return (0); +} + +/* + * Gets a node for a constant and returns the value of this constant + * as integer. + * Is the node not constant or too large for int or of type float, + * a warning will be printed. + * + * toicon() should be used only inside declarations. If it is used in + * expressions, it frees the memory used for the expression. + */ +static int +toicon(tn) + tnode_t *tn; +{ + int i; + tspec_t t; + val_t *v; + + v = constant(tn); + + /* + * Abstract declarations are used inside expression. To free + * the memory would be a fatal error. + */ + if (dcs->d_ctx != ABSTRACT) + tfreeblk(); + + if ((t = v->v_tspec) == FLOAT || t == DOUBLE || t == LDOUBLE) { + i = (int)v->v_ldbl; + /* integral constant expression expected */ + error(55); + } else { + i = (int)v->v_quad; + if (isutyp(t)) { + if ((u_quad_t)v->v_quad > INT_MAX) { + /* integral constant too large */ + warning(56); + } + } else { + if (v->v_quad > INT_MAX || v->v_quad < INT_MIN) { + /* integral constant too large */ + warning(56); + } + } + } + free(v); + return (i); +} + +static void +idecl(decl, initflg) + sym_t *decl; + int initflg; +{ + initerr = 0; + initsym = decl; + + switch (dcs->d_ctx) { + case EXTERN: + decl1ext(decl, initflg); + break; + case ARG: + (void)decl1arg(decl, initflg); + break; + case AUTO: + decl1loc(decl, initflg); + break; + default: + lerror("idecl()"); + } + + if (initflg && !initerr) + prepinit(); +} + +/* + * Discard all input tokens up to and including the next + * unmatched right paren + */ +void +ignuptorp() +{ + int level; + + if (yychar < 0) + yychar = yylex(); + freeyyv(&yylval, yychar); + + level = 1; + while (yychar != T_RPARN || --level > 0) { + if (yychar == T_LPARN) { + level++; + } else if (yychar <= 0) { + break; + } + freeyyv(&yylval, yychar = yylex()); + } + + yyclearin; +} |