/* * Copyright (c) 2003 - 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. * * This file contains the hierarchial source analyzer, called * analyze(). This function uses the global variable * ``toklist'' which must point to the complete translation unit */ #include "analyze.h" #include #include #include "token.h" #include "decl.h" #include "error.h" #include "backend.h" #include "scope.h" #include "symlist.h" #include "type.h" #include "expr.h" #include "misc.h" #include "functions.h" #include "debug.h" #include "builtins.h" #include "inlineasm.h" #include "icode.h" #include "control.h" #include "n_libc.h" static void check_main(struct token *t, struct type *ty) { static struct type *maindef = NULL; struct ty_func *tfunc = ty->tlist->tfunc; struct sym_entry *se; struct type *tytmp; if (maindef != NULL) return; if (ty->name[0] != 'm' || strcmp(ty->name + 1, "ain") != 0) { return; } maindef = ty; /* XXX why is it always null??? */ if (ty->code != TY_INT || ty->tlist->next != NULL) { warningfl(t, "Illegal return type for main(). ISO C says it must be `int'!"); return; } else if (ty->storage == TOK_KEY_STATIC) { errorfl(t, "Static (file scope) declaration of main()"); return; } switch (tfunc->nargs) { case 0: case -1: /* int main(void) or int main() */ break; case 1: errorfl(t, "main() should take no, two or three arguments"); break; case 2: case 3: /* XXX check arg1 + 2 = int,char** */ se = tfunc->scope->slist; tytmp = make_basic_type(TY_INT); if (compare_types(se->dec->dtype, tytmp, CMPTY_SIGN|CMPTY_CONST) != 0) { errorfl(t, "First argument of main is not \ `int' as it should be"); } tytmp = n_xmemdup(make_basic_type(TY_CHAR), sizeof *tytmp); append_typelist(tytmp, TN_POINTER_TO, 0, NULL, NULL); append_typelist(tytmp, TN_POINTER_TO, 0, NULL, NULL); if (compare_types(se->next->dec->dtype, tytmp, CMPTY_SIGN|CMPTY_CONST) != 0) { errorfl(t, "Second argument of main is not \ `char **' as it should be"); } free(tytmp); if (tfunc->nargs == 3) { /* XXX check arg3 = char** */ } } } /* * Do semantic analysis of translation unit. * Initialize functions, structure, globals subsystems * Returns 0 if no errors were found, else 1 */ int analyze(struct token **curtok) { struct token *t; struct decl **d; struct expr *ex; struct function *func = NULL; struct token *builtin_tok = NULL; struct token *starttok; struct decl **builtin_decl = NULL; static int level; int braces = 0; int is_func; int i; if (++level == 1) { static int ptropval = TOK_OP_AMB_MULTI; static int num = 1; static const struct { void *p; int tokval; } normal_va_list[] = { { "typedef", TOK_IDENTIFIER }, { "char", TOK_IDENTIFIER }, { &ptropval, TOK_OPERATOR }, { "__builtin_va_list", TOK_IDENTIFIER }, { NULL, TOK_SEMICOLON }, { NULL, 0 } }, amd64_va_list[] = { /* typedef struct { */ { "typedef", TOK_IDENTIFIER }, { "struct", TOK_IDENTIFIER }, { NULL, TOK_COMP_OPEN }, /* unsigned gp_offset; */ { "unsigned", TOK_IDENTIFIER }, { "gp_offset", TOK_IDENTIFIER }, { NULL, TOK_SEMICOLON }, /* unsigned fp_offset; */ { "unsigned", TOK_IDENTIFIER }, { "fp_offset", TOK_IDENTIFIER }, { NULL, TOK_SEMICOLON }, /* void *overflow_arg_area; */ { "void", TOK_IDENTIFIER }, { &ptropval, TOK_OPERATOR }, { "overflow_arg_area", TOK_IDENTIFIER }, { NULL, TOK_SEMICOLON }, /* void *reg_save_area; */ { "void", TOK_IDENTIFIER }, { &ptropval, TOK_OPERATOR }, { "reg_save_area", TOK_IDENTIFIER }, { NULL, TOK_SEMICOLON }, /* } __builtin_va_list[1]; */ { NULL, TOK_COMP_CLOSE }, { "__builtin_va_list", TOK_IDENTIFIER }, { NULL, TOK_ARRAY_OPEN }, { &num, TY_INT }, { NULL, TOK_ARRAY_CLOSE }, { NULL, TOK_SEMICOLON }, { NULL, 0 } }, *vatok; /* Initial call; Otherwise called by parse_expr() */ curscope = &global_scope; #if 0 store_token(&builtin_tok, n_xstrdup("typedef"), TOK_IDENTIFIER, 0); store_token(&builtin_tok, n_xstrdup("char"), TOK_IDENTIFIER, 0); i = TOK_OP_AMB_MULTI; store_token(&builtin_tok, &i, TOK_OPERATOR, 0); store_token(&builtin_tok, "__builtin_va_list", TOK_IDENTIFIER, 0); store_token(&builtin_tok, 0, TOK_SEMICOLON, 0); store_token(&builtin_tok, NULL, 0, 0); if ((builtin_decl = parse_decl(&builtin_tok, 0)) != NULL) { store_decl_scope(&global_scope, builtin_decl); } else { warningfl(NULL, "Cannot create builtins"); } #endif if (backend->arch == ARCH_AMD64) { vatok = amd64_va_list; } else { vatok = normal_va_list; } for (i = 0; vatok[i].p || vatok[i].tokval; ++i) { void *p; int *dummyptr = n_xmalloc(sizeof *dummyptr); if (vatok[i].tokval == TOK_IDENTIFIER) { p = n_xstrdup(vatok[i].p); } else if (vatok[i].tokval == TY_INT) { #if 0 p = n_xmemdup(vatok[i].p, sizeof(int)); #endif p = n_xmalloc(16); /* XXX */ memcpy(p, vatok[i].p, sizeof(int)); /* XXX */ } else { if (vatok[i].p != NULL) { p = vatok[i].p; } else { p = dummyptr; } } store_token(&builtin_tok, p, vatok[i].tokval, 0, NULL); } if ((builtin_decl = parse_decl(&builtin_tok, 0)) != NULL) { store_decl_scope(&global_scope, builtin_decl); builtin_va_list_type = builtin_decl[0]->dtype; } else { warningfl(NULL, "Cannot create builtins"); } t = toklist; /* Start at beginning */ } else { t = *curtok; /* Start at current token */ } for (; t != NULL; t = t->next) { if (t->prev && (t->prev->type == TOK_COMP_OPEN || t->prev->type == TOK_COMP_CLOSE || t->prev->type == TOK_SEMICOLON)) { if (!errors) { /* * 09/01/07: XXX This token is apparently * still sometimes used if we have parse * errors!!!! */ free(t->prev); t->prev = NULL; } } /* * 08/19/07: Check with lookup_symbol() added. Otherwise * stuff like * * typedef int foo; * { * int foo; * foo = 0; <--- bad!! * } * * ... yields a syntax error because ``foo = 0;'' is * interpreted as a declaration */ if (IS_TYPE(t) && (t->type != TOK_IDENTIFIER || lookup_symbol(curscope, t->data, 1) == NULL)) { do_decl: starttok = t; d = parse_decl(&t, DECL_VARINIT); if (d == NULL) { /* * XXX call recover() instead? */ t = t->next; while (t != NULL && t->type != TOK_SEMICOLON && !IS_KEYWORD(t->type)) { t = t->next; } if (t == NULL) { break; } if (IS_KEYWORD(t->type)) { t = t->prev; } continue; } else { int k; /* * 07/23/07: Don't free tokens if there's a * VLA involved somewhere, cuz otherwise we * still need to evaluate the expression(s) */ for (k = 0; d[k] != NULL; ++k) { if (d[k]->dtype->is_vla) { break; } } if (d[k] == NULL) { free_tokens(starttok, t->prev, FREE_DECL); } } is_func = 0; if ((d[0]->dtype->code == TY_STRUCT || d[0]->dtype->code == TY_ENUM || d[0]->dtype->code == TY_UNION) && d[0]->dtype->is_def) { if (!d[0]->dtype->is_func) { continue; } } #ifdef DEBUG2 printf("Parsed declaration successfully!\n"); #endif if (t->type == TOK_COMP_OPEN) { ++braces; for (i = 0; d[i] != NULL; ++i) { if (d[i]->dtype->is_func) { is_func = 1; } } if (is_func && i > 1) { /* * This must be illegal, as in * int foo, bar(void) { ... } */ errorfl(t, "Syntax error at %s - function definitions may not be paired with " "other declarations!", t->ascii); /* XXX what to do here? */ } else if (is_func) { if (curscope->parent != &global_scope) { /* * ->parent because * parse_func() already * opens new scope */ errorfl(t, "Nested function definitions are not allowed"); /*XXX what to do here?*/ } else { d[0]->dtype->is_def = 1; func = alloc_function(); /*func->scope = curscope;*/ func->proto = d[0]; func->fty = d[0]->dtype->tlist->tfunc; /* XXX complete ... */ check_main(t, d[0]->dtype); curfunc = func; /* * Note that in cases like * void (*foo())() { ... * (function returning * function pointer), the * current scope will now * be that of the return * type function declaration. * So it has to be set to that * of the function definition * here */ curscope = d[0]->dtype-> tlist->tfunc->scope; func->scope = curscope; } } else { errorfl(t, "Syntax error at `%s'", t->ascii); /* XXX what to do here? */ } } } else if (t->type == TOK_KEY_ASM) { /* Inline assembler statement */ struct statement *st; struct inline_asm_stmt *inl; if ((inl = parse_inline_asm(&t)) != NULL) { st = alloc_statement(); st->type = ST_ASM; st->data = inl; append_statement(&curscope->code, &curscope->code_tail, st); t = t->next; } } else if (IS_CONTROL(t->type)) { (void) parse_ctrl(curcont, &t, 1, NULL); #ifdef NO_EXPR /* * If the expression parser is used, it will parse casts on its own - * if it's not, we still want to parse casts in order to debug the * code responsible for it! */ } else if (t->type == TOK_PAREN_OPEN && curscope != &global_scope) { if (t->next == NULL) { errorfl(t, "Unexpected end of file"); break; /* XXX */ } if (IS_TYPE(t->next)) { /* This has got to be a cast */ t = t->next; d = parse_decl(&t, DECL_CAST); if (d != NULL) { #ifdef DEBUG2 printf("Parsed cast successfully!\n"); #endif } else { /* Recover from error */ while (t != NULL && t->type != TOK_SEMICOLON) { t = t->next; } if (t == NULL) { break; } } } #endif } else if (t->type == TOK_COMP_OPEN) { /* Opening a compound statement - new scope! */ struct statement *st; if (curscope == &global_scope) { errorfl(t, "Invalid compound statement at top level"); /* Create new scope anyway, to match with } */ } if (curcont != NULL && curcont->stmt == NULL) { curcont->compound_body = 1; curcont->stmt = alloc_statement(); curcont->stmt->type = ST_COMP; curcont->stmt->data = new_scope(SCOPE_CODE); curcont->braces = braces; } else { st = alloc_statement(); st->type = ST_COMP; append_statement(&curscope->code, &curscope->code_tail, st); st->data = new_scope(SCOPE_CODE); } ++braces; } else if (t->type == TOK_COMP_CLOSE) { /* Closing compound statement - leaving scope! */ close_scope(); if (--braces == 0 && func) { #if 0 if (func && --braces == 0) { #endif /* This is the end of a function definition */ func->next = funclist; funclist = func; #if 0 if (funclist == NULL) { funclist = funclist_tail = func; } else { funclist_tail->next = func; funclist_tail = func; } #endif curfunc = func = NULL; } if (curcont && braces == curcont->braces) { complete_ctrl(&t, curcont); } if (braces == 0 && level > 1) { /* GNU statement-as-expression ends here */ *curtok = t; break; } } else { if (curscope == &global_scope) { /* Must be implicit function declaration */ if (t->type == TOK_SEMICOLON) { warningfl(t, "Empty expression used outside" " of function - illegal in ISO" " C"); continue; } goto do_decl; } if (t->type == TOK_IDENTIFIER) { if (try_label(&t, NULL)) { /* was label */ continue; } } ex = parse_expr(&t, TOK_SEMICOLON, 0, 0, 1); if (ex != NULL) { put_expr_scope(ex); } } if (t == NULL) { break; } } if (level == 1) { curscope = &global_scope; } if (braces > 0) { errorfl(NULL, "Parse error at end of input - " "%d missing `}' tokens", braces); } --level; if (!errors) { if (level == 0) { for (func = funclist; func != NULL; func = func->next) { debug_print_function(func); curfunc = func; curscope = func->scope; func->icode = xlate_to_icode(func->scope->code, 1); /* * 10/31/07: Added this to make sure that all * registers are completely thrown away when a * function ends. Anything else is just nonsense * and causes subsequent function definitions to * perform unnecessary saves of these registers */ backend->invalidate_gprs(NULL, 0); } } } else if (level != 0) { return -1; } #if 0 if (/* check_unused */1) { struct decl *dp; int i; struct decl *darr[] = { static_init_vars, static_uninit_vars, NULL }; for (i = 0; darr[i] != NULL; ++i) { for (dp = darr[i]; dp != NULL; dp = dp->next) { if (dp->dtype->storage != TOK_KEY_EXTERN && dp->references == 0 && !is_basic_agg_type(dp->dtype)) { warningfl(dp->tok, "Unused variable `%s'", dp->dtype->name); } } } } #endif return 0; }