/* * Copyright (c) 2004 - 2007, Nils R. Weller * 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. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. * * Parsing of declarations */ #include "decl.h" #include #include #include #include "error.h" #include "defs.h" #include "token.h" #include "type.h" #include "misc.h" #include "scope.h" #include "symlist.h" #include "expr.h" #include "icode.h" /* expr_to_icode() for evaluating typeof() argument */ #include "decl_adv.h" #include "cc1_main.h" #include "attribute.h" #include "inlineasm.h" #include "debug.h" #include "backend.h" #include "n_libc.h" struct decl * alloc_decl(void) { struct decl *ret; static struct decl nulldecl; ret = n_xmalloc(sizeof *ret); *ret = nulldecl; return ret; } void append_decl(struct decl **head, struct decl **tail, struct decl *d) { if (*head == NULL) { *head = *tail = d; } else { (*tail)->next = d; *tail = (*tail)->next; } } static struct token *find_cast_start(struct token *pos, int mode); /* * Searches for next occurance of identifier in list pointed to by pos. Returns * a pointer to the identifier on success, else a null pointer. * Used to determine identifier in declarations. */ static struct token * find_ident(struct token *pos, int mode, struct type *ty) { struct token *ret = NULL; struct token *start; struct token *prevtok = NULL; /* Characters that might occur in first part of declarator */ static int okay[] = { /* Pointer */ TOK_OP_AMB_MULTI, TOK_PAREN_OPEN, /* Pointer qualifiers, as in ``char *restrict p;'' */ TOK_KEY_CONST, TOK_KEY_RESTRICT, TOK_KEY_VOLATILE, 0 }; /* Might be needed if this is a function argument */ start = pos; #ifdef DEBUG2 puts("Searching for identifier in declaration"); #endif for (; pos != NULL; pos = pos->next) { prevtok = pos; #ifdef DEBUG2 printf("%s ", pos->ascii); #endif if (pos->type == TOK_IDENTIFIER) { /* Found! */ ret = pos; break; } else if (pos->type == TOK_KEY_ATTRIBUTE) { struct attrib *attr; struct token *start = pos; /* * We have to parse and UNLINK any attributes * here because of nonsense stuff like; * * void *__attribute__((pure)) foo(); * * Yes this is legal, you can put attributes * anywhere, and regex of course uses this. * The parser will get confused later if we * don't remove this here */ attr = get_attribute(ty, &pos); if (pos) { pos = pos->prev; } if (start->prev != NULL) { start->prev->next = pos; } if (pos != NULL) { pos->prev = start->prev; } continue; } else { /* * Let's see whether the character is legal * (catch syntax errors) */ int i; int type; if (pos->type == TOK_OPERATOR) { type = *(int *)pos->data; } else { type = pos->type; } for (i = 0; okay[i] != 0; ++i) { if (type == okay[i]) { /* Found */ break; } } if (okay[i] == 0) { /* * Character is illegal, but might be okay if * we are parsing a function argument */ if (mode == DECL_FUNCARG) { /* * Alright, perhaps this must be parsed * cast-like, since function arguments * in prototypes might be mere type * names, e.g. ``void f(int[]);'' * Caller must check for defintions - * ``void f(int[]) { puts("hello"); }'' * is illegal! */ ret = find_cast_start(start, TOK_OP_COMMA); return ret; } errorfl(pos, "Syntax error at %s", pos->ascii); return NULL; } } } if (ret == NULL) { errorfl(prevtok, "Unexpected end of file"); } return ret; } /* * Finds starting point to parse a cast, starting from position pos. * Returns a pointer to the starting point on success, else a null * pointer. * Since a cast MUST be a scalar type (that is, an integral, floating * point or pointer type), the token we are searching for is an * asterisk. This is because this routine might only be called if the * base type (such as ``int'' or ``unsigned long'') does NOT constitute * the entire cast. The effect is that we can only get a scalar out of * this declarator if it really is a pointer * * XXX C99 compound literals also permit stuff like array-casts! * * char *p = (char[4]){ 'a', 'b', 'c', 'd' }; */ static struct token * find_cast_start(struct token *pos, int mode) { struct token *prevtok = NULL; struct token *asterisk = NULL; #ifdef DEBUG printf("Searching for start of cast ... "); #endif for (; pos != NULL; pos = pos->next) { int type; prevtok = pos; #ifdef DEBUG2 printf("%s ", pos->ascii); #endif if (pos->type == TOK_OPERATOR) { type = *(int *)pos->data; } else { type = pos->type; } if (type == TOK_PAREN_OPEN) { /* This is OK */ if (mode == TOK_OP_COMMA) { /* * Might be funtion pointer of form ``int()'' */ asterisk = pos; } continue; } else if (type == TOK_PAREN_CLOSE) { if (asterisk != NULL) { /* * The asterisk was found at the last * iteration! */ #ifdef DEBUG2 printf(" - found!\n"); #endif return asterisk; } else { errorfl(pos, "Cast specifies non-scalar type"); return NULL; } } else if (type == TOK_OP_AMB_MULTI) { /* * Might be beginning, but does not have to - * Parentheses must be used to judge for * pathological cases like a pointer to an * array of pointers to an array, i.e. * * (char (*(*)[20])[40])foo; * * ...where in this example we are interested * in the second asterisk. The strategy is to * preserve a pointer to this token and check * it at the next occurance of a closing * parentheses */ asterisk = pos; } else if (type == TOK_OP_COMMA && mode == TOK_OP_COMMA) { /* function argument */ return asterisk; } else if (type == TOK_PAREN_CLOSE && mode == TOK_OP_COMMA) { /* final function argument */ return asterisk; } else { if (asterisk != NULL) { /* Qualifier in pointer cast */ if (IS_QUALIFIER(type)) { /* Just ignore */ continue; } } /* * C99 permits array casts for compound literals - * char *p = (char[]){ 'a', 'b', 'c', 0 }; * char (*p)[2] = (char[][2]) { * { 'a', 'b' }, * { 'c', 'd' } * }; */ if (type == TOK_ARRAY_OPEN) { #ifdef DEBUG2 printf(" - found!\n"); #endif /* * If ``*'' has been reached, we must return * that */ if (asterisk) { return asterisk; } else { return pos; } } /* * This cast is definitely illegal */ errorfl(pos, "Syntax error at %s", pos->ascii); return NULL; } } errorfl(pos, "Unexpected end of file"); return NULL; } /* * Parses the declarations base type, including storage class, * signedness specifiers and const/volatile/etc qualifiers. The result * is a pointer to a dynamically allocated ``struct type'' structure * on success, else a null pointer * On success, *curtok is also updated to point to the current token */ #define MAKE_TYPE(ty) \ (ty == DECL_CAST ? "cast" : "declaration") static struct type * get_base_type(struct token **curtok, int type) { struct type *ty; struct type *tytmp; struct token *tok; struct token *prevtok = NULL; #ifdef DEBUG2 char decascii[1024] = { 0 }; #endif char *tag; char *curfile; int repetitions = 0; int curtype; int errors = 0; struct ty_struct *is_struct_def = NULL; ty = alloc_type(); ty->line = (*curtok)->line; ty->file = (*curtok)->file; if (!IS_KEYWORD((*curtok)->type) && ((*curtok)->type != TOK_IDENTIFIER || lookup_typedef(curscope, (*curtok)->data) == NULL)) { /* No base type specified - implicit int! ... as in main() {} */ ty->code = TY_INT; ty->sign = TOK_KEY_SIGNED; ty->implicit = 1; return ty; } curfile = (*curtok)->file; /* Read base type and storage class/signess specifiers */ for (tok = *curtok; tok != NULL; tok = tok->next) { int was_attribute = 0; prevtok = tok; while (tok->type == TOK_KEY_ATTRIBUTE) { /* XXX */ struct attrib *a; struct token *start = tok; was_attribute = 1; if ((a = get_attribute(ty, &tok)) == NULL) { continue; } if (is_struct_def) { stupid_append_attr(&is_struct_def->attrib, dup_attr_list(a)); } /* * Unlink attribute stuff so the declarator * parsing can ignore it * XXXXXXXXXXXXXXX WARNING ATTENTION DANGER * This means we can't correctly retry this * operation! Is that OK? */ if (start->prev != NULL) { start->prev->next = tok; } if (tok != NULL) { tok->prev = start->prev; } } if (was_attribute) { if (tok->prev) { tok = tok->prev; } else { /* XXX :-( */ static struct token dummy; dummy.next = tok; tok = &dummy; } continue; } if (!IS_KEYWORD(tok->type) && tok->type != TOK_IDENTIFIER) { /* End of base type found */ break; } switch (tok->type) { case TOK_KEY_UNSIGNED: case TOK_KEY_SIGNED: if (ty->sign) { /* Sign already specified */ if (ty->sign != tok->type) { errorfl(tok, "Type cannot be both signed and unsigned"); free(ty); return NULL; } else { warningfl(tok, "Duplicate use of signedness specifier"); } } ty->sign = tok->type; break; case TOK_KEY_VOLATILE: if (ty->is_volatile) { warningfl(tok, "Duplicate use of `volatile' qualifier"); } ty->is_volatile = 1; break; case TOK_KEY_INLINE: if (ty->is_inline) { warningfl(tok, "Duplicate use of `inline' qualifier"); } ty->is_inline = 1; break; case TOK_KEY_RESTRICT: if (ty->is_restrict) { warningfl(tok, "Duplicate use of `restrict' qualifier"); } ty->is_restrict = 1; break; case TOK_KEY_CONST: if (ty->is_const) { warningfl(tok, "Duplicate use of const specifier"); } ty->is_const = 1; break; case TOK_KEY_TYPEDEF: /* * typedefs are storage class specifiers for convenient * syntax */ case TOK_KEY_STATIC: case TOK_KEY_EXTERN: case TOK_KEY_AUTO: case TOK_KEY_REGISTER: /* * For now the register keyword does not have an * effect */ if (ty->storage != 0) { if (ty->storage != tok->type) { errorfl(tok, "Multiple storage classes specified"); free(ty); return NULL; } } ty->storage = tok->type; break; case TOK_KEY_STRUCT: case TOK_KEY_UNION: case TOK_KEY_ENUM: /* Sanity checking */ if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } if (prevtok->type == TOK_KEY_STRUCT) { curtype = ty->code = TY_STRUCT; } else if (prevtok->type == TOK_KEY_UNION) { curtype = ty->code = TY_UNION; } else { curtype = ty->code = TY_ENUM; } /* Proceed to tag or { */ if (next_token(&tok) != 0) { free(ty); return NULL; } /* Check whether structure has tag */ if (tok->type == TOK_COMP_OPEN) { /* * Nope, is anonymous, as in struct * { int x; } bar; */ tag = NULL; /* tag = NULL indicates anon */ } else if (tok->type != TOK_IDENTIFIER) { errorfl(tok, "Syntax error at %s", tok->ascii); free(ty); return NULL; } else { tag = tok->data; /* Is this actually a definition? */ if (tok->next == NULL) { errorfl(tok, "Unexpected end of file"); free(ty); return NULL; } if (tok->next->type == TOK_COMP_OPEN) { /* * Yes, definition! Prepare for * parsing */ tok = tok->next; } } /* * If this is a structure definition, parse it. * This used to be done by the caller of this * function, but we must also pick up * definitions ``along the way'' with all the * other base type information so we can handle * pathological cases like * ``struct foo { ... } typedef bar;'' * ^ can't return at this point * already! */ if (curtype == TY_STRUCT || curtype == TY_UNION) { if (tok->type == TOK_COMP_OPEN) { /* This has got to be a definition */ struct ty_struct *ts; struct ty_struct *inc = NULL; if (next_token(&tok) != 0) { free(ty); return NULL; } /* * save name of structure in list * of incomplete structures, else * struct foo { struct foo *next;} * does not work! */ if (tag != NULL) { inc = lookup_struct(curscope, tag, 1); if (inc != NULL) { if (!inc->incomplete) { inc = NULL; } } if (inc == NULL) { inc = alloc_ty_struct(); inc->tag = tag; inc->incomplete = 0; inc->is_union = curtype == TY_UNION; inc->attrib = ty->attributes; store_def_scope( curscope, inc, NULL, tok); inc->incomplete = 1; } } if ((ts = parse_struct(&tok, tag, curtype)) == NULL) { free(ty); return NULL; } ts->is_union = curtype == TY_UNION; if (inc != NULL) { ts->parentscope = curscope; complete_type(inc, ts); } else { ts->attrib= ty->attributes; store_def_scope(curscope, ts, NULL, tok); } if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { warningfl(tok, "Structure type of argument has prototype or block scope"); } ty->tstruc = inc? inc: ts; is_struct_def = ty->tstruc; } else if (tok->next->type != TOK_SEMICOLON) { /* * This declaration uses either * an existing structure type or * introduces a new incomplete * declaration */ struct ty_struct *ts; if ((ty->tstruc = lookup_struct(curscope, tag, SCOPE_NESTED)) == NULL) { /* * This is a new incomplete type */ ts = alloc_ty_struct(); ts->tag = tag; ts->incomplete = 1; ts->attrib = dup_attr_list(ty->attributes); store_def_scope(curscope, ts, NULL, tok); if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { warningfl(tok, "Structure type of argument has prototype or block scope"); } ty->tstruc = ts; } else if ((ty->code == TY_UNION) != ty->tstruc->is_union) { errorfl(tok, "`%s' is not %s type", tag, ty->code == TY_UNION? "union": "structure"); return NULL; } } else { /* * This is a forward-declaration as in * ``struct foo;'' */ struct ty_struct *ts; if (type == DECL_STRUCT || type == DECL_FUNCARG) { errorfl(tok, "Invalid forward declaration"); free(ty); return NULL; } ts = alloc_ty_struct(); ts->tag = tag; ts->incomplete = 1; ts->is_union = curtype == TY_UNION; if (ty->storage || ty->sign) { warningfl(tok, "Useless specifier in forward declaration"); } ts->attrib = ty->attributes; store_def_scope(curscope, ts, NULL, tok); free(ty); return NULL; } } else { /* TY_ENUM */ if (tok->type == TOK_COMP_OPEN) { /* This has got to be a definition */ struct ty_enum *te; if (next_token(&tok) != 0) { free(ty); return NULL; } if ((te = parse_enum(&tok)) == NULL) { free(ty); return NULL; } te->tag = tag; store_def_scope(curscope, NULL, te, tok); ty->tenum = te; } else if (tok->next->type != TOK_SEMICOLON) { /* * This declaration uses an existing * enum type */ if ((ty->tenum = lookup_enum(curscope, tag, 1)) == NULL) { /* Handle error */ errorfl(tok, "Undefined enum" " `%s'", tag); free(ty); return NULL; } } else { errorfl(tok, "Forward declarations of " "enumerations not allowed"); free(ty); return NULL; } } break; case TOK_KEY_INT: if (ty->code == TY_LONG || ty->code == TY_SHORT || ty->code == TY_LLONG) { if (repetitions > 0 && (ty->code != TY_LLONG || repetitions > 1)) { errorfl(tok, "Two or more types " "specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } /* ``long int'' or ``short int''- ignore*/ ++repetitions; continue; } else if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } ty->code = TY_INT; break; case TOK_KEY_CHAR: if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); } ty->code = TY_CHAR; break; case TOK_KEY_SHORT: if (ty->code == TY_INT) { /* ``short int'' */ ty->code = TY_SHORT; ++repetitions; } else if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } ty->code = TY_SHORT; break; case TOK_KEY_LONG: if (ty->code == TY_INT) { /* ``long int'' */ ty->code = TY_LONG; ++repetitions; } else if (ty->code == TY_LONG) { /* C99 ``long long'' */ ty->code = TY_LLONG; --repetitions; } else if (ty->code == TY_LLONG) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } else if (ty->code == TY_DOUBLE) { /* ``long double'' */ ty->code = TY_LDOUBLE; } else if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } else { ty->code = TY_LONG; continue; } if (repetitions > 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } ++repetitions; break; case TOK_KEY_FLOAT: if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } ty->code = TY_FLOAT; break; case TOK_KEY_DOUBLE: if (ty->code == TY_LONG) { ty->code = TY_LDOUBLE; } else if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } else { ty->code = TY_DOUBLE; } if (repetitions > 1) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } break; case TOK_KEY_BOOL: if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); free(ty); return NULL; } ty->code = TY_BOOL; break; case TOK_KEY_VOID: if (ty->code != 0) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); } ty->code = TY_VOID; break; case TOK_IDENTIFIER: /* * Typedef? Only check if no type specified yet, * typedef int x; int x; should work */ if (ty->code != 0 || (tytmp = lookup_typedef(curscope, tok->data)) == NULL) { /* Must be identifier in declaration */ goto exit_swtch; } else { /* * This does not have to be typedef, * see C99 6.7.7, 8 */ if (ty->sign) { goto exit_swtch; } } /* Okay, so this is an instance of a typedef'ed type */ /* * XXX Argh - adhoc copy, source of nasty bugs, * why not use copy_type() ... */ if (ty->code) { errorfl(tok, "Two or more types specified in %s", MAKE_TYPE(type)); ++errors; } ty->code = tytmp->code; ty->incomplete = tytmp->incomplete; ty->attributes = dup_attr_list(tytmp->attributes); ty->fastattr = tytmp->fastattr; /* * XXX typedef int foo; unsigned foo f; should * yield a diagnostic */ if (tytmp->sign && ty->sign) { if (tytmp->sign != ty->sign) { errorfl(tok, "Type cannot be both " "signed and unsigned"); ++errors; } else { warningfl(tok, "Duplicate use of signedness " "specifier"); } } else if (ty->sign == 0) { if (ty->code == TY_CHAR) { /* * Let's not trash the distinction * of ``char'' vs ``signed/unsigned * char'' here */ ; } else { ty->sign = tytmp->sign; } } if (tytmp->is_const && ty->is_const) { warningfl(tok, "Duplicate use of const specifier"); } ty->is_const |= tytmp->is_const; if (tytmp->is_volatile && ty->is_const) { warningfl(tok, "Duplicate use of volatile specifier"); } ty->is_volatile |= tytmp->is_volatile; if (tytmp->is_restrict && ty->is_volatile) { warningfl(tok, "Duplicate use of restrict specifier"); } ty->is_restrict |= tytmp->is_restrict; if (errors) { free(ty); return NULL; } ty->tstruc = tytmp->tstruc; ty->tenum = tytmp->tenum; ty->tbit = tytmp->tbit; ty->tlist = tytmp->tlist; ty->is_def = tytmp->is_def; ty->is_func = tytmp->is_func; ty->is_vla = tytmp->is_vla; ty->tlist_tail = tytmp->tlist_tail; break; case TOK_KEY_TYPEOF: { /* * Is GNU C typeof() declaration; * int *x; * typeof(x) y; * ... y now has type ``int *'' * * Like with alignof and sizeof, typename and sub-expression * operands are allowed, but unlike those typeof in GNU C * always seems to require parentheses, so we do so too */ struct expr *ex; struct vreg *vr; struct decl **dec; if (next_token(&tok) != 0) { return NULL; } if (tok->type != TOK_PAREN_OPEN) { errorfl(tok, "Syntax error - Opening parentheses " "expected, got %s", tok->ascii); return NULL; } if (next_token(&tok) != 0) { return NULL; } if (IS_TYPE(tok)) { /* typeof(typename) */ dec = parse_decl(&tok, DECL_CAST); if (dec == NULL) { return NULL; } ty = dec[0]->dtype; } else { /* typeof(expr) */ if ((ex = parse_expr(&tok, TOK_PAREN_CLOSE, 0, 0, 1)) == NULL) { return NULL; } if ((vr = expr_to_icode(ex, NULL, NULL, 0, 0)) == NULL) { return NULL; } ty = vr->type; } #if 0 if (next_token(&tok) != 0) { return NULL; } #endif break; } case TOK_KEY_ASM: /* Assembler name given for variable */ goto exit_swtch; break; default: printf("BUG: get_base_type: %s\n", tok->ascii); exit(EXIT_FAILURE); } #ifdef DEBUG2 strncat(decascii, prevtok->ascii, sizeof decascii - strlen(prevtok->ascii)); #endif } exit_swtch: #ifdef DEBUG2 printf("Base type is - %s\n", decascii); #endif /* * Do some sanity checking on correctness of type, use implicit * int where necessary */ if ((ty->storage || ty->sign) && ty->code == 0) { if (ty->sign == 0) { /* * Don't warn for ``unsigned foo'', but for * ``register bar'' */ warningfl(*curtok, "Implicit int declarations are illegal in C99"); } ty->code = TY_INT; } /* XXX MIPS/PowerPC compatibiliy kludge */ if ((backend->arch == ARCH_MIPS || backend->arch == ARCH_POWER) && ty->code == TY_LDOUBLE) { #if 0 /* the warning seems too verbose ... */ static int warned; if (!warned) { warningfl(prevtok, "This program uses `long double', which is " "unsupported on MIPS. I'll pretend it used " "`double' instead, which may cause the program to " "behave badly"); warned = 1; } #endif ty->code = TY_DOUBLE; } #if 0 if (standard == C89) { if ((IS_LLONG(ty->code) || ty->code == TY_BOOL) && ty->tlist == NULL) { warningfl(*curtok, "`%s' isn't available in C89 (don't " "compile with -ansi or -std=c89)", ty->code == TY_BOOL? "_Bool": "long long"); } } #endif /* Sign specified? */ if (ty->code == TY_STRUCT || ty->code == TY_ENUM || ty->code == TY_UNION || ty->code == TY_VOID || ty->code == TY_FLOAT || ty->code == TY_DOUBLE || ty->code == TY_LDOUBLE) { if (ty->sign != 0) { errorfl(*curtok, "Invalid use of signedness specifier"); free(ty); return NULL; } } else { /* * Integral types except ``char'' and ``_Bool'' are signed by * default */ if (ty->sign == 0) { if (ty->code == TY_CHAR) { /* * XXX temporary botch to avoid passing flags * to libc */ if (CHAR_MIN != SCHAR_MIN) { ty->sign = TOK_KEY_UNSIGNED; } else { ty->sign = TOK_KEY_SIGNED; } } else if (ty->code == TY_BOOL) { ty->sign = TOK_KEY_UNSIGNED; } else { ty->sign = TOK_KEY_SIGNED; } } else if (ty->sign == TOK_KEY_UNSIGNED) { /* Unsigned */ if (ty->code == TY_CHAR) { ty->code = TY_UCHAR; } else if (ty->code == TY_SHORT) { ty->code = TY_USHORT; } else if (ty->code == TY_INT) { ty->code = TY_UINT; } else if (ty->code == TY_LONG) { ty->code = TY_ULONG; } else if (ty->code == TY_LLONG) { ty->code = TY_ULLONG; } } else { /* Explicitly signed */ if (ty->code == TY_CHAR) { ty->code = TY_SCHAR; } } } if (tok == NULL) { errorfl(prevtok, "Unexpected end of file"); free(ty); return NULL; } /* * Make sure no storage class specifiers are used in structure * members */ if (type == DECL_STRUCT) { if (ty->storage /*&& ty->storage != TOK_KEY_TYPEDEF*/) { errorfl(*curtok, "Invalid use of storage class specifier"); return NULL; } } else if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { if (ty->storage && ty->storage != TOK_KEY_REGISTER) { errorfl(*curtok, "Invalid use of storage class specifier"); return NULL; } } *curtok = tok; return ty; } /* * Helper for parse_declarator() - Must be called with tok pointing to a * qualifier token. Returns 0 if this is a qualified pointer (and updates * tok to point to (*tok)->prev, else 1 */ static int try_qualified(struct token **tok) { struct token *t; t = (*tok)->prev; if (t->type == TOK_OPERATOR) { if (*(int *)t->data == TOK_OP_AMB_MULTI) { /* Is qualified pointer indeed! */ *tok = t; return 0; } } /* Not a pointer - syntax error */ errorfl(*tok, "Syntax error at %s", (*tok)->ascii); return 1; } static void merge_typedef_tlist( struct type *base, struct type_node *tlist, struct type_node *tlist_tail) { /* * 08/01/07: OUCH the copy was missing!!! Thus * * typedef struct __bogus {...} va_list[1]; * * void foo(va_list va) { .... } * void bar() { va_list va; ....} * * ... would make the bar() instance of va a pointer * instead of an array because the typelist was trashed * at foo() (since ``T[]'' becomes ``T *'' as a function * parameter.) */ tlist_tail = copy_tlist(&tlist, tlist); if (base->tlist == NULL) { base->tlist = tlist; base->tlist_tail = tlist_tail; } else if (tlist != NULL) { base->tlist_tail->next = tlist; tlist->prev = base->tlist_tail; base->tlist_tail = tlist_tail; } } /* * Does actual parsing of declarator in declaration, i.e. in * char (*p)[20] = foobar; * ... the part (*p)[20] would be parsed here. * Used by parse_decl(), which also grabs the optional initializer */ static struct type * parse_declarator(struct token **curtok, struct type *base, int type) { struct token *t; struct token *start; struct token *left; struct token *right; struct token *arstart; struct type *ret; struct ty_func *tfunc = NULL; struct expr *ex; struct type_node *base_tlist; struct type_node *base_tlist_tail; char *name = NULL; int parens; int newrparen = 1; int newlparen = 1; int left_type; int right_was_func; int array_const; int ac_for_all_dims = 1; int ac_node; int is_vla = 0; /* * 07/21/07: This is a kludge to allow this construct: * * void foo(char buf[restrict]); * * ... which has the same effect as ``char *restrict buf''. * We introduce a new expression type - * EXPR_CONST_FUNCARRAYPARAM - because parse_expr() can * most conveniently handle this */ if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { array_const = EXPR_CONST_FUNCARRAYPARAM; /* XXX hmmmm not really true, huh? */ ac_for_all_dims = 0; #if 0 } else if (type == -3333) { #endif } else if (type == DECL_VARINIT) { array_const = EXPR_CONST; if (curscope != &global_scope) { /* * 07/22/07: XXX (It would probably better to do this * in analyze() and use DECL_CONSTINIT there if * required!) * * Allow automatic variable arrays */ if (base->storage != TOK_KEY_EXTERN && base->storage != TOK_KEY_STATIC && base->storage != TOK_KEY_REGISTER) { array_const = EXPR_OPTCONSTARRAYSIZE; } } } else { array_const = EXPR_CONST; } /* * When using an instance of a typedef'ed type, the base type may * already have a tlist; * typedef char *p; * p array[5]; * ... and that tlist stuff should be appended after the declarator's * tlist such that the above reads ``array of 5 pointers to char''. */ base_tlist = base->tlist; base_tlist_tail = base->tlist_tail; /* * Of course, *curtok is the actual start, but when parsing it is * easier to exclude the previous element, because *curtok must be * included in parsing */ start = (*curtok)->prev; if (start == NULL) { /* * Pathological case encountered: First token in file is part * of an implicit declaration, as in ``main() {}''. We set * start to *curtok for now - the later code will detect this * curiosity and set the ``left'' pointer to NULL */ start = *curtok; } /* Allocate declaration structure to be returned */ ret = alloc_type(); *ret = *base; ret->tlist = NULL; ret->tlist_tail = NULL; ret->line = (*curtok)->line; if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { /* * Before we try to get the identifier, make sure this is an * extended type, i.e. pointer, array, function-pointer or a * combination thereof, because find_ident() would reject e.g. * a plain ``int'' */ int tmp; if ((*curtok)->type == TOK_OPERATOR) { tmp = *(int *)(*curtok)->data; } else { tmp = (*curtok)->type; } if (tmp != TOK_OP_COMMA && tmp != TOK_PAREN_CLOSE) { if ((t = find_ident(*curtok, type, ret)) == NULL) { free(ret); return NULL; } } else { /* We are done */ merge_typedef_tlist(ret, base_tlist, base_tlist_tail); return ret; } } if (type == DECL_CAST || ((type == DECL_FUNCARG || type == DECL_FUNCARG_KR) && t->type != TOK_IDENTIFIER)) { /* Find beginning of cast or function argument */ if (type == DECL_CAST && (*curtok)->type == TOK_PAREN_CLOSE) { /* * The cast ends here, so we are done parsing the cast's * ``declarator'' already! */ merge_typedef_tlist(ret, base_tlist, base_tlist_tail); return ret; } if (type == DECL_CAST) { if ((t = find_cast_start(*curtok, TOK_PAREN_CLOSE)) == NULL) { free(ret); return NULL; } } left = t; if (left->type == TOK_OPERATOR) { left_type = *(int *)left->data; } else { left_type = left->type; } /* * Since this function might only be called if this is a cast * or function argument of extended type, there are only two * possiblities: * 1) the left side is a ``*''. In this case, the right must * either be a closing parentheses/comma or array designator * 2) the left side is a ``[]''. In this case, the right must * be a closing parentheses/comma */ if (left_type == TOK_OP_AMB_MULTI) { if (next_token(&t) != 0) { free(ret); return NULL; } if (t->type == TOK_PAREN_CLOSE) { right = t; } else if (t->type == TOK_ARRAY_OPEN) { right = t; } else if (t->type == TOK_KEY_CONST || t->type == TOK_KEY_RESTRICT || t->type == TOK_KEY_VOLATILE) { right = t; /* This is changed by code below */ } else if ( t->type != TOK_SEMICOLON && !(t->type == TOK_OPERATOR && *(int *)t->data == TOK_OP_COMMA)) { errorfl(t, "Syntax error at %s", t->ascii); free(ret); return NULL; } else { right = t; } } else { /* * The left side is the leftmost dimension of a possibly * multidimensional array. Because of this, it makes * more sense to use the right pointer in order to parse * it, because it steps left-to-right, which is the * natural way of reading array dimensions as well; * char buf[5][6]; <-- 5 arrays of arrays */ right = left; if (start != *curtok) { left = left->prev; } } } else { /* Find identifier to start from there */ if (type == DECL_STRUCT && (*curtok)->type == TOK_OPERATOR && *(int *)(*curtok)->data == TOK_OP_AMB_COND2) { /* Anonymous bitfield */ t = *curtok; goto do_bitfield; } if (type != DECL_FUNCARG && type != DECL_FUNCARG_KR) { if ((t = find_ident(*curtok, type, ret)) == NULL) { free(ret); return NULL; } } ret->name = t->data; ret->line = t->line; if (start != *curtok) { /* left not first token */ left = t->prev; } else { left = t; } if ((right = t->next) == NULL) { errorfl(t, "Unexpected end of file"); free(ret); return NULL; } name = t->data; } /* XXX does this work? */ if (left->type == TOK_OPERATOR && *(int *)left->data == TOK_OP_AMB_MULTI) { if (IS_QUALIFIER(left->next->type)) { left = left->next; right = right->next; } } #ifdef DEBUG2 printf("Left = %s\n", left->ascii); printf("Right = %s\n", right->ascii); printf("Parsing %s for ``%s''\n", type == DECL_CAST ? "cast" : type == DECL_FUNCARG || type == DECL_FUNCARG_KR ? "function argument" : "declaration", (char *)t->ascii); #endif if (t->next == NULL) { errorfl(t, "Unexpected end of file"); free(ret); return NULL; } /* * 10/03/07: This was missing a check for DECL_CAST! Otherwise * things like * * foo? __builtin_va_arg(bla, void *): NULL * * ... would break since the second part of the conditional * operator was considered a potential candidate for a bitfield * declarator */ if ((t->next->type == TOK_OPERATOR && *(int *)t->next->data == TOK_OP_AMB_COND2) && type != DECL_CAST) { /* This is a colon indicating a bitfield! */ /* XXX only supports foo:bar, not (foo):bar */ do_bitfield: if (type != DECL_STRUCT) { /* Attempt to declare bitfield outside of structure! */ errorfl(t, "Syntax error at `%s'", t->ascii); free(ret); return NULL; } /* * ISO C only allows bitfield members of type int, unsigned * int and _Bool */ if (ansiflag) { if (ret->code != TY_INT && ret->code != TY_UINT && ret->code != TY_BOOL) { errorfl(t, "Bitfield member must be int, " "unsigned int or _Bool"); /* XXX recover :( */ free(ret); return NULL; } } /* * Okay, this is a valid bitfield. The number of bits is a * constant expression that might contain operators, so we * cannot rely on it being just a number, as is usually the * case */ if (name != NULL) { t = t->next; /* Now at ``:'' */ } if (next_token(&t) != 0) { free(ret); return NULL; } if ((ex = parse_expr(&t, TOK_OP_COMMA, TOK_SEMICOLON, EXPR_CONST, 1)) == NULL) { #ifndef NO_EXPR /* parse_expr() always returns null if no_expr */ free(ret); return NULL; #endif } ret->tbit = n_xmalloc(sizeof *ret->tbit); ret->tbit->name = name; *curtok = t; merge_typedef_tlist(ret, base_tlist, base_tlist_tail); return ret; } #ifdef DEBUG2 if (ret->name) { printf("%s is:\n", ret->name); } else { printf("Cast is:\n"); } #endif /* * Loop until end of both sides of declatator is reached. * * Let us recall the rules for C's declaration syntax briefly ... * * A declaration basically consists of a theoretically unlimited * number of combined pointer-to, array-of and function call * designators which are applied by placing them on either side of * the identifier. Pointer-to is always placed on the left, array-of * and function call on the right side. To read a declaration, you * have to begin at the identifier (or in the case of a cast, where * the identifier would be placed if it were a declaration!). You * then look on the left side and on the right side. If either side * is a parentheses, you pick the other side as ``significant'' * designator and advance this side. If it is a parentheses as well, * both sides are advanced. * If you have a pointer-to on the left side and an array-of or * function call on the right side, the right side wins because * those have higher precedence. * Example: * char (*(*buf)[256])[256]; * ...step to buf. Left side is ``*'', right side is parentheses, * thus read ``buf is a pointer to...'' * * ...advance left side. This is a parentheses. Advance both sides * * ...left side is ``*'', right side is ``[256]''. [] has higher * precedence, so read ``buf is a pointer to an array of 256...'' * * ...advance right side. This is a parentheses, so pick left side * now and read ``buf is a pointer to an array of 256 pointers'' * * ...advance left side. This is a parentheses. Advance both sides. * The left side has reached the end of the declaration, the right * side is ``[256]'', so read ``buf is a pointer to an array of * 256 pointers to an array of 256 chars'' * * On a final note, everything encountered after a function * designator has been read is treated as the return type of that * function */ if (type == DECL_CAST) { parens = 1; } else { parens = 0; } for (t = *curtok; t != right; t = t->next) { if (t->type == TOK_PAREN_OPEN) { ++parens; } } if (right->type == TOK_PAREN_CLOSE) { if (right->next && (right->next->type == TOK_SEMICOLON || right->next->type == TOK_COMP_OPEN)) { *curtok = right; right = NULL; --parens; } } while (left != NULL || right != NULL) { int right_paren_was_accounted_for = 0; if (left == start) { /* left end of declarator reached */ left = NULL; } right_was_func = 0; if (right) { if (right->type == TOK_SEMICOLON) { /* right end of declarator reached */ *curtok = right; right = NULL; } else if (right->type == TOK_OPERATOR) { int op = *(int *)right->data; if (op == TOK_OP_COMMA || op == TOK_OP_ASSIGN) { /* right end of declarator reached */ *curtok = right; right = NULL; } } else if (right->type == TOK_PAREN_CLOSE) { /* * If this is a cast, let's see whether * this closing parentheses is the end * of it! * It is important to check that this * code is not ran more than once on * the same parentheses, which turned * into an obscure bug ... When a * parentheses is kept for more than * one run because the other side is * significant and evaluated first, * only one parentheses might be * counted */ if (newrparen) { --parens; /* * 08/22/07: This variable was missing! * Otherwise the code for left = ( and * right ) decremented parens once more * and stuff like ``int (foo)[20];'' * failed */ right_paren_was_accounted_for = 1; if (type == DECL_CAST) { if (parens == 0) { /* Yes! */ *curtok = right; right = NULL; } } else if (type == DECL_FUNCARG) { if (parens == -1) { /* * Closing parentheses * reached */ *curtok = right; right = NULL; } } newrparen = 0; } } } if (left && right) { /* Precedence or parentheses must decide */ if (left->type == TOK_PAREN_OPEN) { if (right->type == TOK_PAREN_CLOSE) { /* Skip parentheses */ if (right->next == NULL) { *curtok = right; } right = right->next; newrparen = 1; left = left->prev; newlparen = 1; if (!right_paren_was_accounted_for && --parens == -1) { if (right) *curtok = right; if (right && right->type == TOK_PAREN_OPEN) { ; } else { right = NULL; } } continue; } else { /* Right is significant */ if (right->type == TOK_ARRAY_OPEN) { #ifdef DEBUG2 puts("[right] array of N ..."); #endif arstart = right; if (next_token(&right) != 0) { free(ret); return NULL; } ex = parse_expr(&right, TOK_ARRAY_CLOSE, 0, (ac_for_all_dims || ret->tlist == NULL)? array_const: EXPR_CONST, 1); if (ex == NULL) { free(ret); return NULL; } if (ex->is_const) { ac_node = TN_ARRAY_OF; } else { ac_node = TN_VARARRAY_OF; is_vla = 1; } append_typelist(ret, ac_node, ex, NULL, arstart); } else if (right->type == TOK_PAREN_OPEN) { #ifdef DEBUG2 puts("[right] function..."); #endif right_was_func = 1; if ((tfunc=parse_func(&right, name)) == NULL) { free(ret); return NULL; } if ((type == DECL_FUNCARG || type == DECL_FUNCARG_KR) && ret->tlist == NULL) { append_typelist(ret, TN_POINTER_TO, 0, NULL, NULL); } append_typelist(ret, TN_FUNCTION, 0, tfunc, NULL); } else if (right->type == TOK_OPERATOR && *(int *)right->data == TOK_OP_AMB_MULTI) { #ifdef DEBUG2 puts("[right] pointer to..."); #endif append_typelist(ret, TN_POINTER_TO, 0, NULL, NULL); } else { #ifdef DEBUG2 printf("[right] syntax error? " "code = %d\n", right->type); #endif /* * XXX is this an * improvement? */ *curtok = right; right = NULL; } } } else if (right->type == TOK_PAREN_CLOSE) { /* Left is significant */ if (left->type == TOK_ARRAY_OPEN) { #ifdef DEBUG2 puts("[left] array of N..."); puts("XXX what 2 do here"); #endif arstart = left; if (next_token(&left) != 0) { free(ret); return NULL; } ex = parse_expr(&left, TOK_ARRAY_CLOSE, 0, (ac_for_all_dims || ret->tlist == NULL)? array_const: EXPR_CONST, 1); if (ex == NULL) { free(ret); return NULL; } if (ex->is_const) { ac_node = TN_ARRAY_OF; } else { ac_node = TN_VARARRAY_OF; is_vla = 1; } append_typelist(ret, ac_node, ex, NULL, arstart); } else if (left->type == TOK_OPERATOR && *(int *)left->data == TOK_OP_AMB_MULTI) { #ifdef DEBUG2 puts("[left] pointer to..."); #endif append_typelist(ret, TN_POINTER_TO, 0, NULL, NULL); } else { #ifdef DEBUG2 printf("[left] syntax error? code " "= %d\n", left->type); #endif /* Qualified pointer? */ if (IS_QUALIFIER(left->type)) { int *qualifier = &left->type; if (try_qualified(&left) == 1) { free(ret); return NULL; } else { append_typelist(ret, TN_POINTER_TO, qualifier, NULL, NULL); } } } if (newrparen && --parens == -1) { *curtok = right; right = NULL; } } else { /* * The right side always has precedence * if both are not parentheses, because * it must either be a function or array * designator, both of which ``bind * tighter'' than pointer-to */ if (right->type == TOK_ARRAY_OPEN) { #ifdef DEBUG2 puts("[right] array of N..."); #endif arstart = right; if (next_token(&right) != 0) { free(ret); return NULL; } ex = parse_expr(&right, TOK_ARRAY_CLOSE, 0, (ac_for_all_dims || ret->tlist == NULL)? array_const: EXPR_CONST, 1); if (ex == NULL) { free(ret); return NULL; } if (ex->is_const) { ac_node = TN_ARRAY_OF; } else { ac_node = TN_VARARRAY_OF; is_vla = 1; } append_typelist(ret, ac_node, ex, NULL, arstart); } else if (right->type == TOK_PAREN_OPEN) { #ifdef DEBUG2 puts("[right] function..."); #endif right_was_func = 1; if ((tfunc = parse_func(&right, name)) == NULL) { free(ret); return NULL; } if ((type == DECL_FUNCARG || type == DECL_FUNCARG_KR) && ret->tlist == NULL) { append_typelist(ret, TN_POINTER_TO, NULL, NULL, NULL); } append_typelist(ret, TN_FUNCTION, NULL, tfunc, NULL); } else { #ifdef DEBUG2 printf("[right] syntax error? " "code = %d\n", right->type); #endif /* XXX is this an improvement? */ *curtok = right; right = NULL; } if (right && right->next == NULL) { *curtok = right; } if (right) right = right->next; newrparen = 1; continue; } } else if (left != NULL || right != NULL) { /* Either left or right is significant */ char *side = NULL; struct token *tmp = NULL; if (left) { /* Left is sig. */ side = "left"; tmp = left; } else { /* Right is sig. */ side = "right"; tmp = right; } if (tmp->type == TOK_ARRAY_OPEN) { #ifdef DEBUG2 printf("%s array of N...\n", side); #endif arstart = tmp; if (next_token(&tmp) != 0) { free(ret); return NULL; } ex = parse_expr(&tmp, TOK_ARRAY_CLOSE, 0, (ac_for_all_dims || ret->tlist == NULL)? array_const : EXPR_CONST, 1); if (ex == NULL) { return NULL; } if (ex->is_const) { ac_node = TN_ARRAY_OF; } else { ac_node = TN_VARARRAY_OF; is_vla = 1; } append_typelist(ret, ac_node, ex, NULL, arstart); } else if (tmp->type == TOK_OPERATOR && *(int *)tmp->data == TOK_OP_AMB_MULTI) { #ifdef DEBUG2 printf("%s pointer to...\n", side); #endif append_typelist(ret, TN_POINTER_TO, NULL, NULL, NULL); } else if (tmp->type == TOK_PAREN_OPEN) { if (tmp == right) { #ifdef DEBUG2 printf("%s function...\n", side); #endif right_was_func = 1; if ((tfunc = parse_func(&tmp, name)) == NULL) { free(ret); return NULL; } if ((type == DECL_FUNCARG || type == DECL_FUNCARG_KR) && ret->tlist == NULL) { append_typelist(ret, TN_POINTER_TO, NULL, NULL, NULL); } append_typelist(ret, TN_FUNCTION, NULL, tfunc, NULL); } else { /* XXX handle error! Can't happen! */ } } else if (tmp->type == TOK_PAREN_CLOSE) { if (tmp == right) { if (newrparen && --parens == -1) { *curtok = right; right = NULL; } } else { #ifdef DEBUG2 printf("%s syntax error? code = %d\n", side, tmp->type); #endif /* XXX is the below an improvement? */ if (tmp == right) *curtok = right; right = NULL; } } else { #ifdef DEBUG2 printf("%s syntax error? code = %d\n", side, tmp->type); #endif /* XXX is this an improvement? */ if (tmp == right) { *curtok = right; right = NULL; } else { if (IS_QUALIFIER(tmp->type)) { int *qualifier = &tmp->type; if (try_qualified(&left) == 1) { free(ret); return NULL; } else { append_typelist(ret, TN_POINTER_TO, qualifier, NULL, NULL); tmp = left; } } } } if (left) { left = tmp; newlparen = 1; } else if (right) { right = tmp; newrparen = 1; } } /* * We only proceed either side if it isn't a parentheses. The * case where both sides are parentheses is handled above */ if (left) { if (left->type != TOK_PAREN_OPEN || right == NULL) { left = left->prev; if (left->type == TOK_PAREN_OPEN) { ++parens; newlparen = 0; } } } if (right) { /* * 06/30/07: right_was_func added. Lack of this * check caused things like: * * void foo(int (bar()), void *p); * * ... to break (GNU tar uses this.) * * The problem was that the parse_func() for the * bar() declaration left a ) token, which has * to be skipped here despite being a parentheses. * Because otherwise it will incorrectly match * with the ( before ``bar'', thus yielding * parentheses mismatch */ if ((right->type != TOK_PAREN_CLOSE || right_was_func) || left == NULL) { if (right->next) *curtok = right; right = right->next; newrparen = 1; } } } while ((*curtok)->type == TOK_KEY_ATTRIBUTE) { (void) get_attribute(ret, curtok); } /* * Finally we can check all attributes for correctness and set the * fastattr flags */ merge_attr_with_type(ret); /* * 073107: Merge typelist with the possible base typelist if this * is a typedef'ed type. This was wrongly done after the ``array'' * parameter transformation below, such that * * typedef struct blabla { } va_list[1]; * * void foo(va_list v) { * * ... wrongly declared v as an array instead of a pointer */ merge_typedef_tlist(ret, base_tlist, base_tlist_tail); if (type != DECL_FUNCARG && type != DECL_FUNCARG_KR && type != DECL_CAST) { if ((*curtok)->type == TOK_PAREN_CLOSE) { *curtok = (*curtok)->next; } } else if (type == DECL_FUNCARG || type == DECL_FUNCARG_KR) { /* There are no array arguments; Only pointers */ if (ret->tlist != NULL && ret->tlist->type == TN_ARRAY_OF) { ret->tlist->type = TN_POINTER_TO; if (ret->tlist->next && ret->tlist->next->type == TN_ARRAY_OF) { } } } ret->is_vla += is_vla; /* typedef'ed base may already be VLA! */ return ret; } static void store_decl(struct decl ***d, struct decl *dec, int *nalloc, int *index) { if (*index >= (*nalloc - 2)) { *nalloc += 8; *d = n_xrealloc(*d, *nalloc * sizeof **d); } (*d)[*index] = dec; (*d)[++*index] = NULL; } /* * Parses declaration beginning from token list beginning at *curtok * and, if the mode permits it, the optional initializer. The end of a * declaration is indicated by either a semicolon or a comma (,). If the * latter is encountered, the function just uses the same base type to * parse the next declarator. * On success, a pointer to a newly allocated declaration structure is * returned, else NULL. *curtok is updated to point to the next token * after this declaration. */ struct decl ** parse_decl(struct token **curtok, int mode) { struct decl **ret = NULL; struct decl *tmp; struct type *ty; struct initializer *init; int alloc = 0; int index = 0; #ifdef DEBUG2 printf("Reading decl -- %s\n", (*curtok)->ascii); #endif if ((ty = get_base_type(curtok, mode)) == NULL) { #if 0 /* XXX */ recover(curtok, TOK_OP_COMMA, TOK_SEMICOLON); #endif return NULL; } if ((*curtok)->type == TOK_SEMICOLON) { if (ty->tstruc == NULL && ty->code != TY_ENUM) { errorfl(*curtok, "Syntax error at `;'"); return NULL; } else { static struct decl *dummy[2]; static struct decl dummy2; /* * 08/18/07: Wow, this always ended up using * the same declaration for every anonymous * union! So now the declaration is copied. * Was probably wrong for lots eof other * things too, how come it seemed to work?!? */ dummy[0] = n_xmemdup(&dummy2, sizeof dummy2); /* XXX misleading for struct foo; */ dummy[0]->dtype = ty; dummy[0]->dtype->is_def = 1; dummy[0]->dtype = ty; dummy[1] = NULL; merge_attr_with_type(ty); return dummy; } } /* * Now that we have the base type, the declarator list can be * read - separated by commas in case there are more than one */ for (;;) { struct type *decty; struct token *declstart = *curtok; decty = parse_declarator(curtok, ty, mode); if (decty != NULL) { char *asmname = NULL; /* Store declaration */ debug_print_type(decty, mode, 0); if ((*curtok)->type == TOK_KEY_ASM) { if (curscope != &global_scope && decty->storage != TOK_KEY_EXTERN && decty->storage != TOK_KEY_STATIC) { errorfl(*curtok, "Cannot give asm name to " "nonstatic variable"); return ret; } asmname = parse_asm_varname(curtok); if (asmname == NULL) { return NULL; } } if (decty->code == TY_VOID && decty->tlist == NULL && mode != DECL_CAST && decty->storage != TOK_KEY_TYPEDEF) { errorfl(declstart, "Cannot create object of type `void'"); return ret; } else if ((decty->code == TY_STRUCT || decty->code == TY_UNION) && decty->storage != TOK_KEY_TYPEDEF && decty->storage != TOK_KEY_EXTERN && decty->tstruc->incomplete && !decty->is_def && (decty->tlist == NULL || (decty->tlist->type != TN_FUNCTION && !is_arr_of_ptr(decty)))) { errorfl(declstart, "Cannot instantiate object of incomplete type"); return ret; } if (decty->implicit && decty->name != NULL) { if (decty->is_func && (*curtok)->type == TOK_COMP_OPEN) { warningfl(*curtok, "Return type of `%s' defaults " "to `int'", decty->name); } else { errorfl(*curtok, "No type or storage class specified for `%s'", decty->name); return ret; } } if (decty->storage == 0) { #if 0 if (curscope == &global_scope) { decty->storage = TOK_KEY_EXTERN; } #endif } else if (decty->storage == TOK_KEY_EXTERN) { if (curscope != &global_scope) { /* * ``extern'' declarations with block * scope may not have an initializer! */ #if 0 errorfl(*curtok, "Invalid initializer for ``extern'' declaration at block scope"); #endif } } tmp = alloc_decl(); tmp->tok = declstart; tmp->dtype = decty; if (decty->is_func && decty->tlist->type == TN_FUNCTION) { tmp->asmname = decty->tlist->tfunc->asmname; } else { tmp->asmname = asmname; } if (mode == DECL_VARINIT) { struct decl *dummy[2]; dummy[0] = tmp; dummy[1] = NULL; if ((*curtok)->type == TOK_COMP_OPEN && tmp->dtype->is_func) { tmp->dtype->is_def = 1; store_decl_scope(curscope->parent, dummy); } else if (!tmp->dtype->is_def || (tmp->dtype->code != TY_ENUM && tmp->dtype->code != TY_STRUCT && tmp->dtype->code != TY_UNION)) { if ((*curtok)->type == TOK_OPERATOR && *(int *)(*curtok)->data == TOK_OP_ASSIGN) { /* * store_decl_scope() will look * at the initializer, which * has not been read yet ... * So use dummy initializer to * fool it */ static struct initializer in; tmp->init = ∈ } store_decl_scope(curscope, dummy); } } store_decl(&ret, tmp, &alloc, &index); /* * If this is an array declaration, check whether the * size was specified (if necessary!). important: Need * to take initializer into account; * int foo[] = { ... }; is OK */ if (decty->storage != TOK_KEY_EXTERN && decty->storage != TOK_KEY_TYPEDEF && decty->tlist != NULL && decty->tlist->type == TN_ARRAY_OF && decty->tlist->arrarg->const_value == NULL && mode != DECL_FUNCARG && mode != DECL_FUNCARG_KR && mode != DECL_STRUCT && mode != DECL_CAST && ((*curtok)->type != TOK_OPERATOR || *(int *)(*curtok)->data != TOK_OP_ASSIGN)) { errorfl(declstart, "Array declaration misses size"); return ret; } if (mode == 0) { /* Is init */ return ret; } } else { return ret; } if (*curtok == NULL) return ret; if ((*curtok)->type == TOK_SEMICOLON) { break; /* done */ } else if ((*curtok)->type == TOK_PAREN_CLOSE && (mode == DECL_CAST || mode == DECL_FUNCARG || mode == DECL_FUNCARG_KR)) { return ret; } else if ((*curtok)->type == TOK_OPERATOR && *(int *)(*curtok)->data == TOK_OP_COMMA) { /* * If this is an ISO function argument, the base * type cannot be reused, so we must start * from scratch again - return. However, in K&R * definitions, it can be reused! */ if (mode == DECL_FUNCARG) { return ret; } if (next_token(curtok) != 0) { return ret; } continue; } else if ((*curtok)->type == TOK_OPERATOR && *(int *)(*curtok)->data == TOK_OP_ASSIGN) { if (decty->is_vla) { errorfl(*curtok, "Variable-length arrays " "may not have initializers"); return ret; } else if (mode == DECL_STRUCT) { errorfl(*curtok, "Invalid initializer for " "structure member"); return ret; } else if (mode == DECL_FUNCARG || mode == DECL_FUNCARG_KR) { errorfl(*curtok, "Initializer given for " "function argument"); return ret; } else { /* Read initializer */ if (tmp->dtype->storage == TOK_KEY_TYPEDEF) { errorfl(*curtok, "Initializer " "specified for typedef"); ; } if (next_token(curtok) != 0) { return ret; } if (((tmp->dtype->tlist && tmp->dtype->tlist->type == TN_ARRAY_OF) || ((tmp->dtype->code == TY_STRUCT || tmp->dtype->code == TY_UNION) && tmp->dtype->tlist == NULL)) && tmp->dtype->storage != TOK_KEY_STATIC && tmp->dtype->storage != TOK_KEY_EXTERN) { /* * Automatic struct or array. These are * now allowed to have variable * initializers (as per GNU C/C99), but * constants are preferred - thus use * EXPR_OPTCONST */ init = get_init_expr(curtok, EXPR_OPTCONSTINIT, tmp->dtype, 1, 0); } else if (tmp->dtype->storage == TOK_KEY_STATIC || tmp->dtype->storage == TOK_KEY_EXTERN) { init = get_init_expr(curtok, EXPR_CONSTINIT, tmp->dtype, 1, 0); } else { init = get_init_expr( curtok, EXPR_INIT, tmp->dtype, 1, 0); } if (init == NULL) { return ret; } tmp->init = init; if (tmp->dtype->tlist != NULL && tmp->dtype->tlist->type == TN_ARRAY_OF &&tmp->dtype->tlist->arrarg->const_value == NULL) { /* * Array size determined by * initializer * XXX this is completely bogus and * only works for 1d arrays ... need * to do this in get_init_expr()?! */ init_to_array_size(tmp->dtype, init); } #ifdef DEBUG2 if (*curtok) { printf("returned at %s\n", (*curtok)->ascii); } #endif if ((*curtok)->type == TOK_SEMICOLON) { break; } else if ((*curtok)->type == TOK_OPERATOR && *(int *)(*curtok)->data == TOK_OP_COMMA) { if (next_token(curtok) != 0) { return ret; } } } } else if ((*curtok)->type == TOK_COMP_OPEN) { return ret; } else { errorfl(*curtok, "Syntax error at `%s'", (*curtok)->ascii); return ret; } } /**curtok = tok;*/ return ret; }