@@ -1,5 +1,5 @@
%{
-/* $NetBSD: cgram.y,v 1.318 2021/07/11 21:07:44 rillig Exp $ */
+/* $NetBSD: cgram.y,v 1.319 2021/07/12 21:43:44 rillig Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
@@ -35,7 +35,7 @@
#include <sys/cdefs.h>
#if defined(__RCSID) && !defined(lint)
-__RCSID("$NetBSD: cgram.y,v 1.318 2021/07/11 21:07:44 rillig Exp $");
+__RCSID("$NetBSD: cgram.y,v 1.319 2021/07/12 21:43:44 rillig Exp $");
#endif
#include <limits.h>
@@ -363,161 +363,375 @@
| translation_unit
;
-translation_unit: /* C99 6.9 */
- external_declaration
- | translation_unit external_declaration
+identifier_sym: /* helper for struct/union/enum */
+ identifier {
+ $$ = getsym($1);
+ }
;
-external_declaration: /* C99 6.9 */
- asm_statement
- | function_definition {
- global_clean_up_decl(false);
- clear_warning_flags();
+/* K&R ???, C90 ???, C99 6.4.2.1, C11 ???, C18 ??? */
+identifier:
+ T_NAME {
+ $$ = $1;
+ cgram_debug("name '%s'", $$->sb_name);
}
- | top_level_declaration {
- global_clean_up_decl(false);
- clear_warning_flags();
+ | T_TYPENAME {
+ $$ = $1;
+ cgram_debug("typename '%s'", $$->sb_name);
}
;
-/*
- * On the top level, lint allows several forms of declarations that it doesn't
- * allow in functions. For example, a single ';' is an empty declaration and
- * is supported by some compilers, but in a function it would be an empty
- * statement, not a declaration. This makes a difference in C90 mode, where
- * a statement must not be followed by a declaration.
- *
- * See 'declaration' for all other declarations.
- */
-top_level_declaration: /* C99 6.9 calls this 'declaration' */
- T_SEMI {
- if (sflag) {
- /* empty declaration */
- error(0);
- } else if (!tflag) {
- /* empty declaration */
- warning(0);
- }
+/* see C99 6.4.5, string literals are joined by 5.1.1.2 */
+string:
+ T_STRING
+ | T_STRING string2 {
+ $$ = cat_strings($1, $2);
}
- | begin_type end_type notype_init_decls T_SEMI {
- if (sflag) {
- /* old style declaration; add 'int' */
- error(1);
- } else if (!tflag) {
- /* old style declaration; add 'int' */
- warning(1);
+ ;
+
+/* see C99 6.4.5, string literals are joined by 5.1.1.2 */
+string2:
+ T_STRING {
+ if (tflag) {
+ /* concatenated strings are illegal in traditional C */
+ warning(219);
}
+ $$ = $1;
}
- | begin_type_declmods end_type T_SEMI {
- if (dcs->d_scl == TYPEDEF) {
- /* typedef declares no type name */
- warning(72);
- } else {
- /* empty declaration */
- warning(2);
- }
+ | string2 T_STRING {
+ $$ = cat_strings($1, $2);
}
- | begin_type_declmods end_type notype_init_decls T_SEMI
- | begin_type_declaration_specifiers end_type T_SEMI {
- if (dcs->d_scl == TYPEDEF) {
- /* typedef declares no type name */
- warning(72);
- } else if (!dcs->d_nonempty_decl) {
- /* empty declaration */
- warning(2);
- }
+ ;
+
+/* K&R 7.1, C90 ???, C99 6.5.1, C11 6.5.1, C18 6.5.1 */
+primary_expression:
+ T_NAME {
+ /* XXX really necessary? */
+ if (yychar < 0)
+ yychar = yylex();
+ $$ = new_name_node(getsym($1), yychar);
}
- | begin_type_declaration_specifiers end_type type_init_decls T_SEMI
- | error T_SEMI {
- global_clean_up();
+ | T_CON {
+ $$ = expr_new_constant(gettyp($1->v_tspec), $1);
}
- | error T_RBRACE {
- global_clean_up();
+ | string {
+ $$ = new_string_node($1);
}
+ | T_LPAREN expr T_RPAREN {
+ if ($2 != NULL)
+ $2->tn_parenthesized = true;
+ $$ = $2;
+ }
+ | generic_selection
+ /* GCC primary-expression, see c_parser_postfix_expression */
+ | T_BUILTIN_OFFSETOF T_LPAREN type_name T_COMMA identifier T_RPAREN {
+ symtyp = FMEMBER;
+ $$ = build_offsetof($3, getsym($5));
+ }
;
-function_definition: /* C99 6.9.1 */
- func_decl {
- if ($1->s_type->t_tspec != FUNC) {
- /* syntax error '%s' */
- error(249, yytext);
- YYERROR;
- }
- if ($1->s_type->t_typedef) {
- /* ()-less function definition */
- error(64);
- YYERROR;
- }
- funcdef($1);
- block_level++;
- begin_declaration_level(ARG);
- if (lwarn == LWARN_NONE)
- $1->s_used = true;
- } arg_declaration_list_opt {
- end_declaration_level();
- block_level--;
- check_func_lint_directives();
- check_func_old_style_arguments();
- begin_control_statement(CS_FUNCTION_BODY);
- } compound_statement {
- funcend();
- end_control_statement(CS_FUNCTION_BODY);
+/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
+generic_selection:
+ T_GENERIC T_LPAREN assignment_expression T_COMMA
+ generic_assoc_list T_RPAREN {
+ /* generic selection requires C11 or later */
+ c11ism(345);
+ $$ = build_generic_selection($3, $5);
}
;
-func_decl:
- begin_type end_type notype_decl {
+/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
+generic_assoc_list:
+ generic_association
+ | generic_assoc_list T_COMMA generic_association {
+ $3->ga_prev = $1;
$$ = $3;
}
- | begin_type_declmods end_type notype_decl {
- $$ = $3;
+ ;
+
+/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
+generic_association:
+ type_name T_COLON assignment_expression {
+ $$ = getblk(sizeof(*$$));
+ $$->ga_arg = $1;
+ $$->ga_result = $3;
}
- | begin_type_declaration_specifiers end_type type_decl {
- $$ = $3;
+ | T_DEFAULT T_COLON assignment_expression {
+ $$ = getblk(sizeof(*$$));
+ $$->ga_arg = NULL;
+ $$->ga_result = $3;
}
;
-arg_declaration_list_opt: /* C99 6.9.1p13 example 1 */
- /* empty */
- | arg_declaration_list
+/* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2, C18 6.5.2 */
+postfix_expression:
+ primary_expression
+ | postfix_expression T_LBRACK expr T_RBRACK {
+ $$ = build(INDIR, build(PLUS, $1, $3), NULL);
+ }
+ | postfix_expression T_LPAREN T_RPAREN {
+ $$ = new_function_call_node($1, NULL);
+ }
+ | postfix_expression T_LPAREN argument_expression_list T_RPAREN {
+ $$ = new_function_call_node($1, $3);
+ }
+ | postfix_expression point_or_arrow T_NAME {
+ if ($1 != NULL) {
+ sym_t *msym;
+ /*
+ * XXX struct_or_union_member should be integrated
+ * in build()
+ */
+ if ($2 == ARROW) {
+ /*
+ * must do this before struct_or_union_member
+ * is called
+ */
+ $1 = cconv($1);
+ }
+ msym = struct_or_union_member($1, $2, getsym($3));
+ $$ = build($2, $1, new_name_node(msym, 0));
+ } else {
+ $$ = NULL;
+ }
+ }
+ | postfix_expression T_INCDEC {
+ $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL);
+ }
+ | T_LPAREN type_name T_RPAREN { /* C99 6.5.2.5 "Compound literals" */
+ sym_t *tmp = mktempsym($2);
+ begin_initialization(tmp);
+ cgram_declare(tmp, true, NULL);
+ } init_lbrace initializer_list comma_opt init_rbrace {
+ if (!Sflag)
+ /* compound literals are a C9X/GCC extension */
+ gnuism(319);
+ $$ = new_name_node(*current_initsym(), 0);
+ end_initialization();
+ }
+ | T_LPAREN compound_statement_lbrace gcc_statement_expr_list {
+ block_level--;
+ mem_block_level--;
+ begin_initialization(mktempsym(dup_type($3->tn_type)));
+ mem_block_level++;
+ block_level++;
+ /* ({ }) is a GCC extension */
+ gnuism(320);
+ } compound_statement_rbrace T_RPAREN {
+ $$ = new_name_node(*current_initsym(), 0);
+ end_initialization();
+ }
;
-arg_declaration_list: /* C99 6.9.1p13 example 1 */
- arg_declaration
- | arg_declaration_list arg_declaration
- /* XXX or better "arg_declaration error" ? */
- | error
+comma_opt: /* helper for 'postfix_expression' */
+ /* empty */
+ | T_COMMA
;
/*
- * "arg_declaration" is separated from "declaration" because it
- * needs other error handling.
+ * The inner part of a GCC statement-expression of the form ({ ... }).
+ *
+ * https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
*/
-arg_declaration:
- begin_type_declmods end_type T_SEMI {
- /* empty declaration */
- warning(2);
+gcc_statement_expr_list:
+ gcc_statement_expr_item
+ | gcc_statement_expr_list gcc_statement_expr_item {
+ $$ = $2;
}
- | begin_type_declmods end_type notype_init_decls T_SEMI
- | begin_type_declaration_specifiers end_type T_SEMI {
- if (!dcs->d_nonempty_decl) {
- /* empty declaration */
- warning(2);
+ ;
+
+gcc_statement_expr_item:
+ declaration {
+ clear_warning_flags();
+ $$ = NULL;
+ }
+ | non_expr_statement {
+ $$ = expr_zalloc_tnode();
+ $$->tn_type = gettyp(VOID);
+ }
+ | expr T_SEMI {
+ if ($1 == NULL) { /* in case of syntax errors */
+ $$ = expr_zalloc_tnode();
+ $$->tn_type = gettyp(VOID);
} else {
- /* '%s' declared in argument declaration list */
- warning(3, type_name(dcs->d_type));
+ /* XXX: do that only on the last name */
+ if ($1->tn_op == NAME)
+ $1->tn_sym->s_used = true;
+ $$ = $1;
+ expr($1, false, false, false, false);
+ seen_fallthrough = false;
}
}
- | begin_type_declaration_specifiers end_type type_init_decls T_SEMI {
- if (dcs->d_nonempty_decl) {
- /* '%s' declared in argument declaration list */
- warning(3, type_name(dcs->d_type));
+ ;
+
+point_or_arrow: /* helper for 'postfix_expression' */
+ T_POINT {
+ symtyp = FMEMBER;
+ $$ = POINT;
+ }
+ | T_ARROW {
+ symtyp = FMEMBER;
+ $$ = ARROW;
+ }
+ ;
+
+/* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2, C18 6.5.2 */
+argument_expression_list:
+ expr %prec T_COMMA {
+ $$ = new_function_argument_node(NULL, $1);
+ }
+ | argument_expression_list T_COMMA expr {
+ $$ = new_function_argument_node($1, $3);
+ }
+ ;
+
+/* K&R 7.2, C90 ???, C99 6.5.3, C11 6.5.3, C18 6.5.3 */
+unary_expression:
+ postfix_expression
+ | T_INCDEC unary_expression {
+ $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL);
+ }
+ | T_AMPER cast_expression {
+ $$ = build(ADDR, $2, NULL);
+ }
+ | T_ASTERISK cast_expression {
+ $$ = build(INDIR, $2, NULL);
+ }
+ | T_ADDITIVE cast_expression {
+ if (tflag && $1 == PLUS) {
+ /* unary + is illegal in traditional C */
+ warning(100);
}
+ $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL);
}
- | begin_type_declmods error
- | begin_type_declaration_specifiers error
+ | T_COMPLEMENT cast_expression {
+ $$ = build(COMPL, $2, NULL);
+ }
+ | T_LOGNOT cast_expression {
+ $$ = build(NOT, $2, NULL);
+ }
+ | T_REAL cast_expression { /* GCC c_parser_unary_expression */
+ $$ = build(REAL, $2, NULL);
+ }
+ | T_IMAG cast_expression { /* GCC c_parser_unary_expression */
+ $$ = build(IMAG, $2, NULL);
+ }
+ | T_EXTENSION cast_expression { /* GCC c_parser_unary_expression */
+ $$ = $2;
+ }
+ | T_SIZEOF unary_expression {
+ $$ = $2 == NULL ? NULL : build_sizeof($2->tn_type);
+ if ($$ != NULL)
+ check_expr_misc($2, false, false, false, false, false, true);
+ }
+ | T_SIZEOF T_LPAREN type_name T_RPAREN {
+ $$ = build_sizeof($3);
+ }
+ /* K&R ---, C90 ---, C99 ---, C11 6.5.3, C18 6.5.3 */
+ | T_ALIGNOF T_LPAREN type_name T_RPAREN {
+ $$ = build_alignof($3);
+ }
;
+/* The rule 'unary_operator' is inlined into unary_expression. */
+
+/* K&R 7.2, C90 ???, C99 6.5.4, C11 6.5.4, C18 6.5.4 */
+cast_expression:
+ unary_expression
+ | T_LPAREN type_name T_RPAREN cast_expression {
+ $$ = cast($4, $2);
+ }
+ ;
+
+expr_opt:
+ /* empty */ {
+ $$ = NULL;
+ }
+ | expr
+ ;
+
+/* 'expression' also implements 'multiplicative_expression'. */
+/* 'expression' also implements 'additive_expression'. */
+/* 'expression' also implements 'shift_expression'. */
+/* 'expression' also implements 'relational_expression'. */
+/* 'expression' also implements 'equality_expression'. */
+/* 'expression' also implements 'AND_expression'. */
+/* 'expression' also implements 'exclusive_OR_expression'. */
+/* 'expression' also implements 'inclusive_OR_expression'. */
+/* 'expression' also implements 'logical_AND_expression'. */
+/* 'expression' also implements 'logical_OR_expression'. */
+/* 'expression' also implements 'conditional_expression'. */
+/* 'expression' also implements 'assignment_expression'. */
+/* TODO: rename to 'expression' */
+/* K&R ???, C90 ???, C99 6.5.5 to 6.5.17, C11 ???, C18 ??? */
+expr:
+ expr T_ASTERISK expr {
+ $$ = build(MULT, $1, $3);
+ }
+ | expr T_MULTIPLICATIVE expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_ADDITIVE expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_SHIFT expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_RELATIONAL expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_EQUALITY expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_AMPER expr {
+ $$ = build(BITAND, $1, $3);
+ }
+ | expr T_BITXOR expr {
+ $$ = build(BITXOR, $1, $3);
+ }
+ | expr T_BITOR expr {
+ $$ = build(BITOR, $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_OPASSIGN expr {
+ $$ = build($2, $1, $3);
+ }
+ | expr T_COMMA expr {
+ $$ = build(COMMA, $1, $3);
+ }
+ | cast_expression
+ ;
+
+/* K&R ???, C90 ???, C99 6.5.16, C11 ???, C18 ??? */
+assignment_expression:
+ expr %prec T_ASSIGN
+ ;
+
+constant_expr_list_opt: /* helper for gcc_attribute */
+ /* empty */
+ | constant_expr_list
+ ;
+
+constant_expr_list: /* helper for gcc_attribute */
+ constant_expr
+ | constant_expr_list T_COMMA constant_expr
+ ;
+
+constant_expr: /* C99 6.6 */
+ expr %prec T_ASSIGN
+ ;
+
declaration: /* C99 6.7 */
begin_type_declmods end_type T_SEMI {
if (dcs->d_scl == TYPEDEF) {
@@ -542,18 +756,6 @@
| error T_SEMI
;
-begin_type:
- /* empty */ {
- begin_type();
- }
- ;
-
-end_type:
- /* empty */ {
- end_type();
- }
- ;
-
begin_type_declaration_specifiers: /* see C99 6.7 */
begin_type_typespec {
add_type($1);
@@ -568,7 +770,7 @@
}
;
-begin_type_declmods:
+begin_type_declmods: /* see C99 6.7 */
begin_type T_QUAL {
add_qualifier($2);
}
@@ -578,14 +780,21 @@
| begin_type_declmods declmod
;
-declmod:
- T_QUAL {
- add_qualifier($1);
+begin_type_noclass_declspecs:
+ begin_type_typespec {
+ add_type($1);
}
- | T_SCLASS {
- add_storage_class($1);
+ | type_attribute begin_type_noclass_declspecs
+ | begin_type_noclass_declmods type_specifier {
+ add_type($2);
}
- | type_attribute_list
+ | begin_type_noclass_declspecs T_QUAL {
+ add_qualifier($2);
+ }
+ | begin_type_noclass_declspecs notype_type_specifier {
+ add_type($2);
+ }
+ | begin_type_noclass_declspecs type_attribute
;
begin_type_typespec:
@@ -597,6 +806,25 @@
}
;
+begin_type_noclass_declmods:
+ begin_type T_QUAL {
+ add_qualifier($2);
+ }
+ | begin_type_noclass_declmods T_QUAL {
+ add_qualifier($2);
+ }
+ ;
+
+declmod:
+ T_QUAL {
+ add_qualifier($1);
+ }
+ | T_SCLASS {
+ add_storage_class($1);
+ }
+ | type_attribute_list
+ ;
+
type_attribute_list:
type_attribute
| type_attribute_list type_attribute
@@ -620,6 +848,23 @@
| T_NORETURN
;
+align_as: /* See alignment-specifier in C11 6.7.5 */
+ type_specifier
+ | constant_expr
+ ;
+
+begin_type:
+ /* empty */ {
+ begin_type();
+ }
+ ;
+
+end_type:
+ /* empty */ {
+ end_type();
+ }
+ ;
+
type_specifier: /* C99 6.7.2 */
notype_type_specifier
| T_TYPENAME {
@@ -627,7 +872,7 @@
}
;
-notype_type_specifier:
+notype_type_specifier: /* see C99 6.7.2 */
T_TYPE {
$$ = gettyp($1);
}
@@ -682,19 +927,19 @@
}
;
-braced_struct_declaration_list:
+braced_struct_declaration_list: /* see C99 6.7.2.1 */
struct_declaration_lbrace struct_declaration_list_with_rbrace {
$$ = $2;
}
;
-struct_declaration_lbrace:
+struct_declaration_lbrace: /* see C99 6.7.2.1 */
T_LBRACE {
symtyp = FVFT;
}
;
-struct_declaration_list_with_rbrace:
+struct_declaration_list_with_rbrace: /* see C99 6.7.2.1 */
struct_declaration_list T_SEMI T_RBRACE
| struct_declaration_list T_RBRACE {
if (sflag) {
@@ -711,14 +956,14 @@
}
;
-struct_declaration_list:
+struct_declaration_list: /* C99 6.7.2.1 */
struct_declaration
| struct_declaration_list T_SEMI struct_declaration {
$$ = lnklst($1, $3);
}
;
-struct_declaration:
+struct_declaration: /* C99 6.7.2.1 */
begin_type_noclass_declmods end_type {
/* too late, i know, but getsym() compensates it */
symtyp = FMEMBER;
@@ -758,32 +1003,7 @@
}
;
-begin_type_noclass_declspecs:
- begin_type_typespec {
- add_type($1);
- }
- | type_attribute begin_type_noclass_declspecs
- | begin_type_noclass_declmods type_specifier {
- add_type($2);
- }
- | begin_type_noclass_declspecs T_QUAL {
- add_qualifier($2);
- }
- | begin_type_noclass_declspecs notype_type_specifier {
- add_type($2);
- }
- | begin_type_noclass_declspecs type_attribute
- ;
-
-begin_type_noclass_declmods:
- begin_type T_QUAL {
- add_qualifier($2);
- }
- | begin_type_noclass_declmods T_QUAL {
- add_qualifier($2);
- }
- ;
-
+/* TODO: rename 'decls' to 'declarators', everywhere. */
notype_member_decls:
notype_member_decl {
$$ = declarator_1_struct_union($1);
@@ -830,7 +1050,7 @@
}
;
-enum_specifier: /* C99 6.7.2.2 */
+enum_specifier: /* C99 6.7.2.2 */
enum identifier_sym {
$$ = mktag($2, ENUM, false, false);
}
@@ -850,27 +1070,27 @@
}
;
-enum:
+enum: /* helper for C99 6.7.2.2 */
T_ENUM {
symtyp = FTAG;
begin_declaration_level(CTCONST);
}
;
-enum_declaration:
+enum_declaration: /* helper for C99 6.7.2.2 */
enum_decl_lbrace enums_with_opt_comma T_RBRACE {
$$ = $2;
}
;
-enum_decl_lbrace:
+enum_decl_lbrace: /* helper for C99 6.7.2.2 */
T_LBRACE {
symtyp = FVFT;
enumval = 0;
}
;
-enums_with_opt_comma:
+enums_with_opt_comma: /* helper for C99 6.7.2.2 */
enumerator_list
| enumerator_list T_COMMA {
if (sflag) {
@@ -884,7 +1104,7 @@
}
;
-enumerator_list:
+enumerator_list: /* C99 6.7.2.2 */
enumerator
| enumerator_list T_COMMA enumerator {
$$ = lnklst($1, $3);
@@ -903,7 +1123,50 @@
}
;
+type_qualifier: /* C99 6.7.3 */
+ T_QUAL {
+ $$ = xcalloc(1, sizeof(*$$));
+ if ($1 == CONST) {
+ $$->p_const = true;
+ } else if ($1 == VOLATILE) {
+ $$->p_volatile = true;
+ } else {
+ lint_assert($1 == RESTRICT || $1 == THREAD);
+ }
+ }
+ ;
+pointer: /* C99 6.7.5 */
+ asterisk type_qualifier_list_opt {
+ $$ = merge_qualified_pointer($1, $2);
+ }
+ | asterisk type_qualifier_list_opt pointer {
+ $$ = merge_qualified_pointer($1, $2);
+ $$ = merge_qualified_pointer($$, $3);
+ }
+ ;
+
+asterisk: /* helper for 'pointer' */
+ T_ASTERISK {
+ $$ = xcalloc(1, sizeof(*$$));
+ $$->p_pointer = true;
+ }
+ ;
+
+type_qualifier_list_opt: /* see C99 6.7.5 */
+ /* empty */ {
+ $$ = NULL;
+ }
+ | type_qualifier_list
+ ;
+
+type_qualifier_list: /* C99 6.7.5 */
+ type_qualifier
+ | type_qualifier_list type_qualifier {
+ $$ = merge_qualified_pointer($1, $2);
+ }
+ ;
+
/*
* For an explanation of 'notype' in the following rules, see the Bison
* manual, section 7.1 "Semantic Info in Token Kinds".
@@ -1023,16 +1286,11 @@
}
;
-array_size:
- type_qualifier_list_opt T_SCLASS constant_expr {
- /* C11 6.7.6.3p7 */
- if ($2 != STATIC)
- yyerror("Bad attribute");
- /* static array size is a C11 extension */
- c11ism(343);
- $$ = $3;
+notype_param_decl:
+ direct_notype_param_decl
+ | pointer direct_notype_param_decl {
+ $$ = add_pointer($2, $1);
}
- | constant_expr
;
direct_param_decl:
@@ -1058,13 +1316,6 @@
}
;
-notype_param_decl:
- direct_notype_param_decl
- | pointer direct_notype_param_decl {
- $$ = add_pointer($2, $1);
- }
- ;
-
direct_notype_param_decl:
identifier {
$$ = declarator_name(getsym($1));
@@ -1085,77 +1336,113 @@
}
;
-pointer: /* C99 6.7.5 */
- asterisk type_qualifier_list_opt {
- $$ = merge_qualified_pointer($1, $2);
+param_list:
+ id_list_lparen identifier_list T_RPAREN {
+ $$ = $2;
}
- | asterisk type_qualifier_list_opt pointer {
- $$ = merge_qualified_pointer($1, $2);
- $$ = merge_qualified_pointer($$, $3);
- }
+ | abstract_decl_param_list
;
-asterisk:
- T_ASTERISK {
- $$ = xcalloc(1, sizeof(*$$));
- $$->p_pointer = true;
+id_list_lparen:
+ T_LPAREN {
+ block_level++;
+ begin_declaration_level(PROTO_ARG);
}
;
-type_qualifier_list_opt:
- /* empty */ {
- $$ = NULL;
+array_size:
+ type_qualifier_list_opt T_SCLASS constant_expr {
+ /* C11 6.7.6.3p7 */
+ if ($2 != STATIC)
+ yyerror("Bad attribute");
+ /* static array size is a C11 extension */
+ c11ism(343);
+ $$ = $3;
}
- | type_qualifier_list
+ | constant_expr
;
-type_qualifier_list: /* C99 6.7.5 */
- type_qualifier
- | type_qualifier_list type_qualifier {
- $$ = merge_qualified_pointer($1, $2);
+identifier_list: /* C99 6.7.5 */
+ T_NAME {
+ $$ = old_style_function_name(getsym($1));
}
+ | identifier_list T_COMMA T_NAME {
+ $$ = lnklst($1, old_style_function_name(getsym($3)));
+ }
+ | identifier_list error
;
-type_qualifier:
- T_QUAL {
- $$ = xcalloc(1, sizeof(*$$));
- if ($1 == CONST) {
- $$->p_const = true;
- } else if ($1 == VOLATILE) {
- $$->p_volatile = true;
- } else {
- lint_assert($1 == RESTRICT || $1 == THREAD);
- }
+/* XXX: C99 requires an additional specifier-qualifier-list. */
+type_name: /* C99 6.7.6 */
+ {
+ begin_declaration_level(ABSTRACT);
+ } abstract_declaration {
+ end_declaration_level();
+ $$ = $2->s_type;
}
;
-align_as: /* See alignment-specifier in C11 6.7.5 */
- type_specifier
- | constant_expr
- ;
-
-param_list:
- id_list_lparen identifier_list T_RPAREN {
- $$ = $2;
+abstract_declaration:
+ begin_type_noclass_declmods end_type {
+ $$ = declare_1_abstract(abstract_name());
}
- | abstract_decl_param_list
+ | begin_type_noclass_declspecs end_type {
+ $$ = declare_1_abstract(abstract_name());
+ }
+ | begin_type_noclass_declmods end_type abstract_declarator {
+ $$ = declare_1_abstract($3);
+ }
+ | begin_type_noclass_declspecs end_type abstract_declarator {
+ $$ = declare_1_abstract($3);
+ }
;
-id_list_lparen:
- T_LPAREN {
- block_level++;
- begin_declaration_level(PROTO_ARG);
+abstract_declarator: /* C99 6.7.6 */
+ pointer {
+ $$ = add_pointer(abstract_name(), $1);
}
+ | direct_abstract_declarator
+ | pointer direct_abstract_declarator {
+ $$ = add_pointer($2, $1);
+ }
+ | T_TYPEOF cast_expression { /* GCC extension */
+ $$ = mktempsym($2->tn_type);
+ }
;
-identifier_list:
- T_NAME {
- $$ = old_style_function_name(getsym($1));
+direct_abstract_declarator: /* C99 6.7.6 */
+ T_LPAREN abstract_declarator T_RPAREN {
+ $$ = $2;
}
- | identifier_list T_COMMA T_NAME {
- $$ = lnklst($1, old_style_function_name(getsym($3)));
+ | T_LBRACK T_RBRACK {
+ $$ = add_array(abstract_name(), false, 0);
}
- | identifier_list error
+ | T_LBRACK array_size T_RBRACK {
+ $$ = add_array(abstract_name(), true, to_int_constant($2, false));
+ }
+ | type_attribute direct_abstract_declarator {
+ $$ = $2;
+ }
+ | direct_abstract_declarator T_LBRACK T_RBRACK {
+ $$ = add_array($1, false, 0);
+ }
+ | direct_abstract_declarator T_LBRACK T_ASTERISK T_RBRACK { /* C99 */
+ $$ = add_array($1, false, 0);
+ }
+ | direct_abstract_declarator T_LBRACK array_size T_RBRACK {
+ $$ = add_array($1, true, to_int_constant($3, false));
+ }
+ | abstract_decl_param_list asm_or_symbolrename_opt {
+ $$ = add_function(symbolrename(abstract_name(), $2), $1);
+ end_declaration_level();
+ block_level--;
+ }
+ | direct_abstract_declarator abstract_decl_param_list asm_or_symbolrename_opt {
+ $$ = add_function(symbolrename($1, $3), $2);
+ end_declaration_level();
+ block_level--;
+ }
+ | direct_abstract_declarator type_attribute_list
;
abstract_decl_param_list:
@@ -1197,6 +1484,7 @@
}
;
+/* XXX: C99 6.7.5 defines the same name, but it looks different. */
parameter_type_list:
parameter_declaration
| parameter_type_list T_COMMA parameter_declaration {
@@ -1233,19 +1521,6 @@
}
;
-asm_or_symbolrename_opt: /* expect only one */
- /* empty */ {
- $$ = NULL;
- }
- | T_ASM T_LPAREN T_STRING T_RPAREN {
- freeyyv(&$3, T_STRING);
- $$ = NULL;
- }
- | T_SYMBOLRENAME T_LPAREN T_NAME T_RPAREN {
- $$ = $3;
- }
- ;
-
initializer: /* C99 6.7.8 "Initialization" */
expr %prec T_COMMA {
init_expr($1);
@@ -1262,7 +1537,7 @@
| initializer_list T_COMMA initializer_list_item
;
-initializer_list_item:
+initializer_list_item: /* helper */
designation initializer
| initializer
;
@@ -1309,91 +1584,37 @@
}
;
-init_lbrace:
+init_lbrace: /* helper */
T_LBRACE {
init_lbrace();
}
;
-init_rbrace:
+init_rbrace: /* helper */
T_RBRACE {
init_rbrace();
}
;
-type_name: /* C99 6.7.6 */
- {
- begin_declaration_level(ABSTRACT);
- } abstract_declaration {
- end_declaration_level();
- $$ = $2->s_type;
+asm_or_symbolrename_opt: /* GCC extensions */
+ /* empty */ {
+ $$ = NULL;
}
- ;
-
-abstract_declaration:
- begin_type_noclass_declmods end_type {
- $$ = declare_1_abstract(abstract_name());
+ | T_ASM T_LPAREN T_STRING T_RPAREN {
+ freeyyv(&$3, T_STRING);
+ $$ = NULL;
}
- | begin_type_noclass_declspecs end_type {
- $$ = declare_1_abstract(abstract_name());
+ | T_SYMBOLRENAME T_LPAREN T_NAME T_RPAREN {
+ $$ = $3;
}
- | begin_type_noclass_declmods end_type abstract_declarator {
- $$ = declare_1_abstract($3);
- }
- | begin_type_noclass_declspecs end_type abstract_declarator {
- $$ = declare_1_abstract($3);
- }
;
-abstract_declarator: /* C99 6.7.6 */
- pointer {
- $$ = add_pointer(abstract_name(), $1);
- }
- | direct_abstract_declarator
- | pointer direct_abstract_declarator {
- $$ = add_pointer($2, $1);
- }
- | T_TYPEOF cast_expression { /* GCC extension */
- $$ = mktempsym($2->tn_type);
- }
+statement: /* C99 6.8 */
+ expression_statement
+ | non_expr_statement
;
-direct_abstract_declarator: /* C99 6.7.6 */
- T_LPAREN abstract_declarator T_RPAREN {
- $$ = $2;
- }
- | T_LBRACK T_RBRACK {
- $$ = add_array(abstract_name(), false, 0);
- }
- | T_LBRACK array_size T_RBRACK {
- $$ = add_array(abstract_name(), true, to_int_constant($2, false));
- }
- | type_attribute direct_abstract_declarator {
- $$ = $2;
- }
- | direct_abstract_declarator T_LBRACK T_RBRACK {
- $$ = add_array($1, false, 0);
- }
- | direct_abstract_declarator T_LBRACK T_ASTERISK T_RBRACK { /* C99 */
- $$ = add_array($1, false, 0);
- }
- | direct_abstract_declarator T_LBRACK array_size T_RBRACK {
- $$ = add_array($1, true, to_int_constant($3, false));
- }
- | abstract_decl_param_list asm_or_symbolrename_opt {
- $$ = add_function(symbolrename(abstract_name(), $2), $1);
- end_declaration_level();
- block_level--;
- }
- | direct_abstract_declarator abstract_decl_param_list asm_or_symbolrename_opt {
- $$ = add_function(symbolrename($1, $3), $2);
- end_declaration_level();
- block_level--;
- }
- | direct_abstract_declarator type_attribute_list
- ;
-
-non_expr_statement:
+non_expr_statement: /* helper for C99 6.8 */
type_attribute T_SEMI
| labeled_statement
| compound_statement
@@ -1405,11 +1626,6 @@
| asm_statement
;
-statement: /* C99 6.8 */
- expression_statement
- | non_expr_statement
- ;
-
labeled_statement: /* C99 6.8.1 */
label type_attribute_opt statement
;
@@ -1534,12 +1750,6 @@
}
;
-do_statement: /* C99 6.8.5 */
- do statement {
- clear_warning_flags();
- }
- ;
-
iteration_statement: /* C99 6.8.5 */
while_expr statement {
clear_warning_flags();
@@ -1571,20 +1781,26 @@
}
;
-while_expr:
+while_expr: /* see C99 6.8.5 */
T_WHILE T_LPAREN expr T_RPAREN {
while1($3);
clear_warning_flags();
}
;
+do_statement: /* see C99 6.8.5 */
+ do statement {
+ clear_warning_flags();
+ }
+ ;
+
do: /* see C99 6.8.5 */
T_DO {
do1();
}
;
-do_while_expr:
+do_while_expr: /* see C99 6.8.5 */
T_WHILE T_LPAREN expr T_RPAREN T_SEMI {
$$ = $3;
}
@@ -1632,13 +1848,13 @@
}
;
-goto:
+goto: /* see C99 6.8.6 */
T_GOTO {
symtyp = FLABEL;
}
;
-asm_statement:
+asm_statement: /* GCC extension */
T_ASM T_LPAREN read_until_rparen T_SEMI {
setasm();
}
@@ -1648,359 +1864,165 @@
| T_ASM error
;
-read_until_rparen:
+read_until_rparen: /* helper for 'asm_statement' */
/* empty */ {
ignore_up_to_rparen();
}
;
-constant_expr_list_opt:
- /* empty */
- | constant_expr_list
+translation_unit: /* C99 6.9 */
+ external_declaration
+ | translation_unit external_declaration
;
-constant_expr_list:
- constant_expr
- | constant_expr_list T_COMMA constant_expr
- ;
-
-constant_expr: /* C99 6.6 */
- expr %prec T_ASSIGN
- ;
-
-expr_opt:
- /* empty */ {
- $$ = NULL;
+external_declaration: /* C99 6.9 */
+ asm_statement
+ | function_definition {
+ global_clean_up_decl(false);
+ clear_warning_flags();
}
- | expr
- ;
-
-expr: /* C99 6.5 */
- expr T_ASTERISK expr {
- $$ = build(MULT, $1, $3);
+ | top_level_declaration {
+ global_clean_up_decl(false);
+ clear_warning_flags();
}
- | expr T_MULTIPLICATIVE expr {
- $$ = build($2, $1, $3);
- }
- | expr T_ADDITIVE expr {
- $$ = build($2, $1, $3);
- }
- | expr T_SHIFT expr {
- $$ = build($2, $1, $3);
- }
- | expr T_RELATIONAL expr {
- $$ = build($2, $1, $3);
- }
- | expr T_EQUALITY expr {
- $$ = build($2, $1, $3);
- }
- | expr T_AMPER expr {
- $$ = build(BITAND, $1, $3);
- }
- | expr T_BITXOR expr {
- $$ = build(BITXOR, $1, $3);
- }
- | expr T_BITOR expr {
- $$ = build(BITOR, $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_OPASSIGN expr {
- $$ = build($2, $1, $3);
- }
- | expr T_COMMA expr {
- $$ = build(COMMA, $1, $3);
- }
- | cast_expression
;
-assignment_expression: /* C99 6.5.16 */
- expr %prec T_ASSIGN
- ;
-
-/* K&R 7.1, C90 ???, C99 6.5.1, C11 6.5.1, C18 6.5.1 */
-primary_expression:
- T_NAME {
- /* XXX really necessary? */
- if (yychar < 0)
- yychar = yylex();
- $$ = new_name_node(getsym($1), yychar);
+/*
+ * On the top level, lint allows several forms of declarations that it doesn't
+ * allow in functions. For example, a single ';' is an empty declaration and
+ * is supported by some compilers, but in a function it would be an empty
+ * statement, not a declaration. This makes a difference in C90 mode, where
+ * a statement must not be followed by a declaration.
+ *
+ * See 'declaration' for all other declarations.
+ */
+top_level_declaration: /* C99 6.9 calls this 'declaration' */
+ T_SEMI {
+ if (sflag) {
+ /* empty declaration */
+ error(0);
+ } else if (!tflag) {
+ /* empty declaration */
+ warning(0);
+ }
}
- | T_CON {
- $$ = expr_new_constant(gettyp($1->v_tspec), $1);
+ | begin_type end_type notype_init_decls T_SEMI {
+ if (sflag) {
+ /* old style declaration; add 'int' */
+ error(1);
+ } else if (!tflag) {
+ /* old style declaration; add 'int' */
+ warning(1);
+ }
}
- | string {
- $$ = new_string_node($1);
+ | begin_type_declmods end_type T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else {
+ /* empty declaration */
+ warning(2);
+ }
}
- | T_LPAREN expr T_RPAREN {
- if ($2 != NULL)
- $2->tn_parenthesized = true;
- $$ = $2;
+ | begin_type_declmods end_type notype_init_decls T_SEMI
+ | begin_type_declaration_specifiers end_type T_SEMI {
+ if (dcs->d_scl == TYPEDEF) {
+ /* typedef declares no type name */
+ warning(72);
+ } else if (!dcs->d_nonempty_decl) {
+ /* empty declaration */
+ warning(2);
+ }
}
- | generic_selection
- /* GCC primary-expression, see c_parser_postfix_expression */
- | T_BUILTIN_OFFSETOF T_LPAREN type_name T_COMMA identifier T_RPAREN {
- symtyp = FMEMBER;
- $$ = build_offsetof($3, getsym($5));
+ | begin_type_declaration_specifiers end_type type_init_decls T_SEMI
+ | error T_SEMI {
+ global_clean_up();
}
- ;
-
-/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
-generic_selection:
- T_GENERIC T_LPAREN assignment_expression T_COMMA
- generic_assoc_list T_RPAREN {
- /* generic selection requires C11 or later */
- c11ism(345);
- $$ = build_generic_selection($3, $5);
+ | error T_RBRACE {
+ global_clean_up();
}
;
-/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
-generic_assoc_list:
- generic_association
- | generic_assoc_list T_COMMA generic_association {
- $3->ga_prev = $1;
- $$ = $3;
- }
- ;
-
-/* K&R ---, C90 ---, C99 ---, C11 6.5.1.1, C18 6.5.1.1 */
-generic_association:
- type_name T_COLON assignment_expression {
- $$ = getblk(sizeof(*$$));
- $$->ga_arg = $1;
- $$->ga_result = $3;
- }
- | T_DEFAULT T_COLON assignment_expression {
- $$ = getblk(sizeof(*$$));
- $$->ga_arg = NULL;
- $$->ga_result = $3;
- }
- ;
-
-/* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2, C18 6.5.2 */
-postfix_expression:
- primary_expression
- | postfix_expression T_LBRACK expr T_RBRACK {
- $$ = build(INDIR, build(PLUS, $1, $3), NULL);
- }
- | postfix_expression T_LPAREN T_RPAREN {
- $$ = new_function_call_node($1, NULL);
- }
- | postfix_expression T_LPAREN argument_expression_list T_RPAREN {
- $$ = new_function_call_node($1, $3);
- }
- | postfix_expression point_or_arrow T_NAME {
- if ($1 != NULL) {
- sym_t *msym;
- /*
- * XXX struct_or_union_member should be integrated
- * in build()
- */
- if ($2 == ARROW) {
- /*
- * must do this before struct_or_union_member
- * is called
- */
- $1 = cconv($1);
- }
- msym = struct_or_union_member($1, $2, getsym($3));
- $$ = build($2, $1, new_name_node(msym, 0));
- } else {
- $$ = NULL;
+function_definition: /* C99 6.9.1 */
+ func_decl {
+ if ($1->s_type->t_tspec != FUNC) {
+ /* syntax error '%s' */
+ error(249, yytext);
+ YYERROR;
}
- }
- | postfix_expression T_INCDEC {
- $$ = build($2 == INC ? INCAFT : DECAFT, $1, NULL);
- }
- | T_LPAREN type_name T_RPAREN { /* C99 6.5.2.5 "Compound literals" */
- sym_t *tmp = mktempsym($2);
- begin_initialization(tmp);
- cgram_declare(tmp, true, NULL);
- } init_lbrace initializer_list comma_opt init_rbrace {
- if (!Sflag)
- /* compound literals are a C9X/GCC extension */
- gnuism(319);
- $$ = new_name_node(*current_initsym(), 0);
- end_initialization();
- }
- | T_LPAREN compound_statement_lbrace gcc_statement_expr_list {
- block_level--;
- mem_block_level--;
- begin_initialization(mktempsym(dup_type($3->tn_type)));
- mem_block_level++;
+ if ($1->s_type->t_typedef) {
+ /* ()-less function definition */
+ error(64);
+ YYERROR;
+ }
+ funcdef($1);
block_level++;
- /* ({ }) is a GCC extension */
- gnuism(320);
- } compound_statement_rbrace T_RPAREN {
- $$ = new_name_node(*current_initsym(), 0);
- end_initialization();
+ begin_declaration_level(ARG);
+ if (lwarn == LWARN_NONE)
+ $1->s_used = true;
+ } arg_declaration_list_opt {
+ end_declaration_level();
+ block_level--;
+ check_func_lint_directives();
+ check_func_old_style_arguments();
+ begin_control_statement(CS_FUNCTION_BODY);
+ } compound_statement {
+ funcend();
+ end_control_statement(CS_FUNCTION_BODY);
}
;
-/* K&R 7.1, C90 ???, C99 6.5.2, C11 6.5.2, C18 6.5.2 */
-argument_expression_list:
- expr %prec T_COMMA {
- $$ = new_function_argument_node(NULL, $1);
+func_decl:
+ begin_type end_type notype_decl {
+ $$ = $3;
}
- | argument_expression_list T_COMMA expr {
- $$ = new_function_argument_node($1, $3);
+ | begin_type_declmods end_type notype_decl {
+ $$ = $3;
}
+ | begin_type_declaration_specifiers end_type type_decl {
+ $$ = $3;
+ }
;
-/* K&R 7.2, C90 ???, C99 6.5.3, C11 6.5.3, C18 6.5.3 */
-unary_expression:
- postfix_expression
- | T_INCDEC unary_expression {
- $$ = build($1 == INC ? INCBEF : DECBEF, $2, NULL);
- }
- | T_AMPER cast_expression {
- $$ = build(ADDR, $2, NULL);
- }
- | T_ASTERISK cast_expression {
- $$ = build(INDIR, $2, NULL);
- }
- | T_ADDITIVE cast_expression {
- if (tflag && $1 == PLUS) {
- /* unary + is illegal in traditional C */
- warning(100);
- }
- $$ = build($1 == PLUS ? UPLUS : UMINUS, $2, NULL);
- }
- | T_COMPLEMENT cast_expression {
- $$ = build(COMPL, $2, NULL);
- }
- | T_LOGNOT cast_expression {
- $$ = build(NOT, $2, NULL);
- }
- | T_REAL cast_expression { /* GCC c_parser_unary_expression */
- $$ = build(REAL, $2, NULL);
- }
- | T_IMAG cast_expression { /* GCC c_parser_unary_expression */
- $$ = build(IMAG, $2, NULL);
- }
- | T_EXTENSION cast_expression { /* GCC c_parser_unary_expression */
- $$ = $2;
- }
- | T_SIZEOF unary_expression {
- $$ = $2 == NULL ? NULL : build_sizeof($2->tn_type);
- if ($$ != NULL)
- check_expr_misc($2, false, false, false, false, false, true);
- }
- | T_SIZEOF T_LPAREN type_name T_RPAREN {
- $$ = build_sizeof($3);
- }
- /* K&R ---, C90 ---, C99 ---, C11 6.5.3, C18 6.5.3 */
- | T_ALIGNOF T_LPAREN type_name T_RPAREN {
- $$ = build_alignof($3);
- }
+arg_declaration_list_opt: /* C99 6.9.1p13 example 1 */
+ /* empty */
+ | arg_declaration_list
;
-/* K&R 7.2, C90 ???, C99 6.5.4, C11 6.5.4, C18 6.5.4 */
-cast_expression:
- unary_expression
- | T_LPAREN type_name T_RPAREN cast_expression {
- $$ = cast($4, $2);
- }
+arg_declaration_list: /* C99 6.9.1p13 example 1 */
+ arg_declaration
+ | arg_declaration_list arg_declaration
+ /* XXX or better "arg_declaration error" ? */
+ | error
;
/*
- * The inner part of a GCC statement-expression of the form ({ ... }).
- *
- * https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html
+ * "arg_declaration" is separated from "declaration" because it
+ * needs other error handling.
*/
-gcc_statement_expr_list:
- gcc_statement_expr_item
- | gcc_statement_expr_list gcc_statement_expr_item {
- $$ = $2;
+arg_declaration:
+ begin_type_declmods end_type T_SEMI {
+ /* empty declaration */
+ warning(2);
}
- ;
-
-gcc_statement_expr_item:
- declaration {
- clear_warning_flags();
- $$ = NULL;
- }
- | non_expr_statement {
- $$ = expr_zalloc_tnode();
- $$->tn_type = gettyp(VOID);
- }
- | expr T_SEMI {
- if ($1 == NULL) { /* in case of syntax errors */
- $$ = expr_zalloc_tnode();
- $$->tn_type = gettyp(VOID);
+ | begin_type_declmods end_type notype_init_decls T_SEMI
+ | begin_type_declaration_specifiers end_type T_SEMI {
+ if (!dcs->d_nonempty_decl) {
+ /* empty declaration */
+ warning(2);
} else {
- /* XXX: do that only on the last name */
- if ($1->tn_op == NAME)
- $1->tn_sym->s_used = true;
- $$ = $1;
- expr($1, false, false, false, false);
- seen_fallthrough = false;
+ /* '%s' declared in argument declaration list */
+ warning(3, type_name(dcs->d_type));
}
}
- ;
-
-string:
- T_STRING
- | T_STRING string2 {
- $$ = cat_strings($1, $2);
- }
- ;
-
-string2:
- T_STRING {
- if (tflag) {
- /* concatenated strings are illegal in traditional C */
- warning(219);
+ | begin_type_declaration_specifiers end_type type_init_decls T_SEMI {
+ if (dcs->d_nonempty_decl) {
+ /* '%s' declared in argument declaration list */
+ warning(3, type_name(dcs->d_type));
}
- $$ = $1;
}
- | string2 T_STRING {
- $$ = cat_strings($1, $2);
- }
- ;
-
-point_or_arrow:
- T_POINT {
- symtyp = FMEMBER;
- $$ = POINT;
- }
- | T_ARROW {
- symtyp = FMEMBER;
- $$ = ARROW;
- }
- ;
-
-identifier_sym:
- identifier {
- $$ = getsym($1);
- }
- ;
-
-identifier: /* C99 6.4.2.1 */
- T_NAME {
- $$ = $1;
- cgram_debug("name '%s'", $$->sb_name);
- }
- | T_TYPENAME {
- $$ = $1;
- cgram_debug("typename '%s'", $$->sb_name);
- }
- ;
-
-comma_opt:
- /* empty */
- | T_COMMA
+ | begin_type_declmods error
+ | begin_type_declaration_specifiers error
;
gcc_attribute_spec_list: