short typedef yepp;
makes all hope of writing a specific grammar for typedefs illusory.
*/
+/* We do not accept the whole of the grammar, since when we see
+ something like 'unsigned plain' (where plain is a typedef) is
+ illegal if 'plain' is a typedef. Therefore, we assume that
+ 'plain' is the identifier of a declarator. Unfortunately, this
+ causes declarations like 'unsigned plain x;' to be rejected on the
+ grounds of syntax, even though it is syntactically right. This may
+ cause a lot of extra messages.
+ To do this, decl_specifiers is divided into:
+ 1: normal specifiers == storage class specifiers + type_qualifiers
+ 2: special specifiers == short + long + signed + unsigned
+ 3: basic types == void + char + int + float + double
+ 4: single type specifiers == struct or union specifiers
+ + enum specifiers + typedef names
+ */
decl_specifiers /* non-empty */ (register struct decspecs *ds;)
/* Reads a non-empty decl_specifiers and fills the struct
decspecs *ds.
*/
:
-[
- other_specifier(ds)+
- [%if (DOT != IDENTIFIER || AHEAD == IDENTIFIER)
- /* the thin ice in R.M. 11.1 */
- single_type_specifier(ds) other_specifier(ds)*
- |
- empty
- ]
+[ %if (AHEAD == IDENTIFIER) /* like: register i; */
+ normal_specifier(ds)
|
- single_type_specifier(ds) other_specifier(ds)*
+ normal_specifier(ds)*
+ [ special_specifier(ds)
+ | basic_type(ds)
+ | single_type_specifier(ds)
+ ]
+ [ normal_specifier(ds)
+ | special_specifier(ds)
+ | basic_type(ds)
+ ]*
]
{do_decspecs(ds);}
;
-/* 3.5.1 & 3.5.2 (partially) & 3.5.3 (partially) */
-other_specifier(register struct decspecs *ds;)
+normal_specifier(register struct decspecs *ds;)
:
[ AUTO | STATIC | EXTERN | TYPEDEF | REGISTER ]
{ if (ds->ds_sc_given)
ds->ds_sc_given = 1;
ds->ds_sc = DOT;
}
-|
- [ SHORT | LONG ]
- { if (ds->ds_size)
- error("repeated size specifier");
- ds->ds_size = DOT;
- }
-|
- [ SIGNED | UNSIGNED ]
- { if (ds->ds_unsigned != 0)
- error("repeated sign specifier");
- ds->ds_unsigned = DOT;
- }
|
/* This qualifier applies to the top type.
E.g. volatile float * is a pointer to volatile float.
}
;
+special_specifier(register struct decspecs *ds;)
+:
+ [ SHORT | LONG ]
+ { if (ds->ds_size)
+ error("repeated size specifier");
+ ds->ds_size = DOT;
+ }
+|
+ [ SIGNED | UNSIGNED ]
+ { if (ds->ds_unsigned != 0)
+ error("repeated sign specifier");
+ ds->ds_unsigned = DOT;
+ }
+;
+
/* 3.5.2 */
type_specifier(struct type **tpp;)
/* Used in struct/union declarations and in casts; only the
{*tpp = Ds.ds_type;}
;
+basic_type(register struct decspecs *ds;):
+ [ VOID | CHAR | INT | FLOAT | DOUBLE ]
+ {
+ idf2type(dot.tk_idf, &ds->ds_type);
+ ds->ds_typedef = 0;
+ }
+;
+
single_type_specifier(register struct decspecs *ds;):
%default TYPE_IDENTIFIER /* this includes INT, CHAR, etc. */
- {idf2type(dot.tk_idf, &ds->ds_type);}
+ {
+ idf2type(dot.tk_idf, &ds->ds_type);
+ ds->ds_typedef = 1;
+ }
|
IDENTIFIER
{
|
formal_list(&fm)
|
- empty
+ /* empty */
]
')'
{ add_decl_unary(dc, FUNCTION, 0, (arith)0, fm, pl);
{ struct expr *expr; }
:
'['
+ { *sizep = (arith)-1; }
[
constant_expression(&expr)
{
*sizep = expr->VL_VALUE;
free_expression(expr);
}
- |
- empty
- { *sizep = (arith)-1; }
- ]
+ ]?
']'
;
enumerator_pack(*tpp, &l)
|
{apply_struct(ENUM, idf, tpp);}
- empty
+ /* empty */
]
]
;
if (DOT == ';') declare_struct(fund, idf, tpp);
else apply_struct(fund, idf, tpp);
}
- empty
+ /* empty */
]
]
;
[
parameter_type_list(&pl)
|
- empty
+ /* empty */
]
')'
{add_decl_unary(dc, FUNCTION, 0, (arith)0, NO_PARAMS, pl);}
primary_abstract_declarator(struct declarator *dc;)
:
[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD))
- empty
+ /* empty */
|
'(' abstract_declarator(dc) ')'
]
:
[%if (AHEAD == ')' || first_of_parameter_type_list(AHEAD)
&& (AHEAD != IDENTIFIER))
- empty
+ /* empty */
|
identifier(&dc->dc_idf)
|
ds->ds_notypegiven = 1;
tp = int_type;
}
- switch (ds->ds_size) {
- case SHORT:
- if (tp == int_type)
- tp = short_type;
- else
- error("short with illegal type");
- break;
- case LONG:
- if (tp == int_type)
- tp = long_type;
- else
- if (tp == double_type)
+ if (ds->ds_size) {
+ register int ds_isshort = (ds->ds_size == SHORT);
+
+ if (ds->ds_typedef) goto SIZE_ERROR; /* yes */
+ if (tp == int_type) {
+ if (ds_isshort) tp = short_type;
+ else tp = long_type;
+ } else if (tp == double_type && !ds_isshort ) {
tp = lngdbl_type;
- else
- error("long with illegal type");
- break;
- }
- if (ds->ds_unsigned == UNSIGNED) {
- switch (tp->tp_fund) {
- case CHAR:
- tp = uchar_type;
- break;
- case SHORT:
- tp = ushort_type;
- break;
- case INT:
- tp = uint_type;
- break;
- case LONG:
- tp = ulong_type;
- break;
- default:
- error("unsigned with illegal type");
- break;
+ } else {
+ SIZE_ERROR:
+ error("%s with illegal type",symbol2str(ds->ds_size));
}
}
- if (ds->ds_unsigned == SIGNED) {
- switch (tp->tp_fund) {
- case CHAR:
- tp = schar_type;
- break;
- case SHORT:
- tp = short_type;
- break;
- case INT:
- tp = int_type;
- break;
- case LONG:
- tp = long_type;
- break;
- default:
- error("signed with illegal type");
- break;
+ if (ds->ds_unsigned) {
+ register int ds_isunsigned = (ds->ds_unsigned == UNSIGNED);
+
+ if (ds->ds_typedef) goto SIGN_ERROR; /* yes */
+ /*
+ * All integral types are signed by default (char too),
+ * so the case that ds->ds_unsigned == SIGNED can be ignored.
+ */
+ if (tp == schar_type) {
+ if (ds_isunsigned) tp = uchar_type;
+ } else if (tp == short_type) {
+ if (ds_isunsigned) tp = ushort_type;
+ } else if (tp == int_type) {
+ if (ds_isunsigned) tp = uint_type;
+ } else if (tp == long_type) {
+ if (ds_isunsigned) tp = ulong_type;
+ } else {
+ SIGN_ERROR:
+ error("%s with illegal type"
+ , symbol2str(ds->ds_unsigned));
}
}
-
ds->ds_type = qualifier_type(tp, ds->ds_typequal);
}