diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-10-10 23:41:40 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-10-10 23:41:40 +0300 |
commit | 27e0842899c6d2a674d95d888e10d0b036e27753 (patch) | |
tree | 6f9519b8b40747aca8c505b8a7af0c3fcae6a0f5 /src | |
parent | 250d9aab8f79ebd7a2f2535de9db60172df51598 (diff) | |
download | cflow-27e0842899c6d2a674d95d888e10d0b036e27753.tar.gz cflow-27e0842899c6d2a674d95d888e10d0b036e27753.tar.bz2 |
Improve parser. Allow users to declare aliases to other symbols.
The latter feature is useful for declaring reserved symbols such
as __restrict or __inline, e.g. --symbol __restrict:=restrict
instructs cflow to treat `__restrict' exactly as `restrict'.
* src/Makefile.am: Minor fix in rule for flowgraph.
* src/c.l (init_tokens): New function, separated from
init_lex.
Install qualifiers.
* src/cflow.h (symbol_alias): New flag.
(symbol)<alias>: New member.
(INSTALL_DEFAULT,INSTALL_OVERWRITE)
(INSTALL_CHECK_LOCAL,INSTALL_UNIT_LOCAL): New defines.
* src/cflow.rc: Rewrite for use with --cpp='gcc -E'
* src/main.c (symbol_override): Extend syntax to allow for defining
aliases to other tokens (--symbol __inline:=inline).
* src/parser.c (print_token): print qualifiers and ops.
(file_error): Change signature. All uses changed.
(save_token): Improve output spacing.
(skip_balanced): Treat LBRACE0 and RBRACE0 as { and }.
(is_function): allow for qualifiers and wrappers before
defintion.
(parse_function_declaration): Remove PARM_WRAPPER case: it
is taken care of by the caller.
(fake_struct): leave when '(' is encountered.
(parse_variable_declaration): Allow for qualifiers before
the identifier.
(skip_struct): Use skip_balanced.
(dcl): Handle wrappers. Leave if a semicolon is encountered.
(dirdcl): Optimize handing of wrapper.
(maybe_parm_list): Handle qualifiers.
(declare): allow for wrappers.
(declare_type): Pass INSTALL_UNIT_LOCAL as a flag to install.
* src/symbol.c (lookup): Argument is const now.
(install): Change semantics of the 2nd argument.
(install_ident): Change the call to install accordingly.
* tests/nfparg.at: Change spacing to reflect changes to
save_token.
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/c.l | 95 | ||||
-rw-r--r-- | src/cflow.h | 16 | ||||
-rw-r--r-- | src/cflow.rc | 20 | ||||
-rw-r--r-- | src/main.c | 45 | ||||
-rw-r--r-- | src/parser.c | 175 | ||||
-rw-r--r-- | src/symbol.c | 30 |
7 files changed, 234 insertions, 156 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 05acd30..f4736d7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -41,14 +41,15 @@ localedir = $(datadir)/locale LDADD=../gnu/libgnu.a @LIBINTL@ AM_CPPFLAGS=-DLOCALEDIR=\"$(localedir)\" AM_LFLAGS=-dvp EXTRA_DIST=cflow.rc +CFLOW=$(abs_builddir)/cflow CFLOW_FLAGS=-i^s --brief cflow_CFLOW_INPUT=$(cflow_OBJECTS:.@OBJEXT@=.c) cflow.cflow: $(cflow_CFLOW_INPUT) cflow.rc Makefile - CFLOWRC=$(top_srcdir)/src/cflow.rc \ - cflow -o$@ $(CFLOW_FLAGS) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) \ + $(AM_V_GEN)CFLOWRC=$(top_srcdir)/src/cflow.rc \ + $(CFLOW) -o$@ --cpp="$(CC) -E" $(CFLOW_FLAGS) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) \ $(cflow_CFLOW_INPUT) @@ -72,46 +72,54 @@ WS [ \t\f\r]* <longline>.*\n { BEGIN(INITIAL); ++line_num; } /* keywords */ auto /* ignored */; extern return EXTERN; static return STATIC; typedef return TYPEDEF; -inline {yylval.str = "inline"; return QUALIFIER; } struct {yylval.str = "struct"; return STRUCT;} union {yylval.str = "union"; return STRUCT;} enum {yylval.str = "enum"; return STRUCT;} \* { yylval.str = "*"; return MODIFIER; } /* Operators * */ -"->" | -"." return MEMBER_OF; -"*=" | -"/=" | -"%=" | -"+=" | -"-=" | -"<<=" | -">>=" | -"&=" | -"|=" | -"^=" | -"||" | -"&&" | -"==" | -"!=" | -">=" | -">" | -"<=" | -"<" | -"<<" | -">>" | -"++" | -"--" return OP; +"->" {yylval.str = "->"; return MEMBER_OF;} +"." {yylval.str = "."; return MEMBER_OF;} +"*=" {yylval.str = "*="; return OP;} +"/=" {yylval.str = "/="; return OP;} +"/" {yylval.str = "/"; return OP;} +"%=" {yylval.str = "%="; return OP;} +"%" {yylval.str = "%"; return OP;} +"+=" {yylval.str = "+="; return OP;} +"+" {yylval.str = "+"; return OP;} +"-=" {yylval.str = "-="; return OP;} +"-" {yylval.str = "-"; return OP;} +"<<=" {yylval.str = "<<="; return OP;} +">>=" {yylval.str = ">>="; return OP;} +"&=" {yylval.str = "&="; return OP;} +"|=" {yylval.str = "|="; return OP;} +"^=" {yylval.str = "^="; return OP;} +"^" {yylval.str = "^"; return OP;} +"||" {yylval.str = "||"; return OP;} +"|" {yylval.str = "|"; return OP;} +"&&" {yylval.str = "&&"; return OP;} +"&" {yylval.str = "&"; return OP;} +"==" {yylval.str = "=="; return OP;} +"=" {yylval.str = "="; return '=';} +"!=" {yylval.str = "!="; return OP;} +"!" {yylval.str = "!"; return OP;} +">=" {yylval.str = ">="; return OP;} +">" {yylval.str = ">"; return OP;} +"<=" {yylval.str = "<="; return OP;} +"<" {yylval.str = "<"; return OP;} +"<<" {yylval.str = "<<"; return OP;} +">>" {yylval.str = ">>"; return OP;} +"++" {yylval.str = "++"; return OP;} +"--" {yylval.str = "--"; return OP;} '.' | '\\.' | '\\[0-7]{2,3}' | '\\[xX][0-9a-fA-F]{1,2}' return STRING; /* Identifiers and constants * @@ -178,56 +186,73 @@ static char *keywords[] = { "switch", "while" }; static char *types[] = { "char", - "const", "double", "float", "int", + "void", +}; + +static char *qualifiers[] = { "long", + "const", "register", "restrict", "short", "signed", "unsigned", - "void", "volatile", + "inline" }; void -init_lex(int debug_level) +init_tokens() { int i; Symbol *sp; - yy_flex_debug = debug_level; - - obstack_init(&string_stk); - for (i = 0; i < NUMITEMS(keywords); i++) { - sp = install(keywords[i], 0); + sp = install(keywords[i], INSTALL_OVERWRITE); sp->type = SymToken; sp->token_type = WORD; } for (i = 0; i < NUMITEMS(types); i++) { - sp = install(types[i], 0); + sp = install(types[i], INSTALL_OVERWRITE); sp->type = SymToken; sp->token_type = TYPE; sp->source = NULL; sp->def_line = -1; sp->ref_line = NULL; } - sp = install("...", 0); + + for (i = 0; i < NUMITEMS(qualifiers); i++) { + sp = install(qualifiers[i], INSTALL_OVERWRITE); + sp->type = SymToken; + sp->token_type = QUALIFIER; + sp->source = NULL; + sp->def_line = -1; + sp->ref_line = NULL; + } + sp = install("...", INSTALL_OVERWRITE); sp->type = SymToken; sp->token_type = IDENTIFIER; sp->source = NULL; sp->def_line = -1; sp->ref_line = NULL; +} + +void +init_lex(int debug_level) +{ + yy_flex_debug = debug_level; + obstack_init(&string_stk); + init_tokens(); } int ident() { /* Do not attempt any symbol table lookup if the previous token was diff --git a/src/cflow.h b/src/cflow.h index 1749ada..07cc8cf 100644 --- a/src/cflow.h +++ b/src/cflow.h @@ -80,26 +80,31 @@ typedef struct { } Ref; enum symbol_flag { symbol_none, symbol_temp, /* Temporary symbol. Must be deleted after processing of the current module */ - symbol_parm /* Parameter */ + symbol_parm, /* Parameter */ + symbol_alias /* Alias to another symbol */ }; typedef struct symbol Symbol; struct symbol { struct table_entry *owner; Symbol *next; /* Next symbol with the same hash */ struct linked_list_entry *entry; enum symtype type; /* Type of the symbol */ char *name; /* Identifier */ enum symbol_flag flag; /* Specific flag */ - + struct symbol *alias; /* Points to the aliased symbol if + type==SymToken and flag==symbol_alias. + In this case, the rest of the structure + is ignored */ + int active; /* Set to 1 when the symbol's subtree is being processed, prevent recursion */ int expand_line; /* Output line when this symbol was first expanded */ int token_type; /* Type of the token */ @@ -162,13 +167,18 @@ extern int omit_symbol_names_option; extern int token_stack_length; extern int token_stack_increase; extern int symbol_count; extern unsigned input_file_count; -Symbol *lookup(char*); +#define INSTALL_DEFAULT 0x00 +#define INSTALL_OVERWRITE 0x01 +#define INSTALL_CHECK_LOCAL 0x02 +#define INSTALL_UNIT_LOCAL 0x04 + +Symbol *lookup(const char*); Symbol *install(char*, int); Symbol *install_ident(char *name, enum storage storage); void ident_change_storage(Symbol *sp, enum storage storage); void delete_autos(int level); void delete_statics(void); void delete_parms(int level); diff --git a/src/cflow.rc b/src/cflow.rc index 8c875f1..e4be309 100644 --- a/src/cflow.rc +++ b/src/cflow.rc @@ -1,6 +1,14 @@ -# Default configuration file for cflow ---symbol __const:type ---symbol __restrict:type --D__extension__= --D__attribute__\\(c\\)= --D__asm__\\(c\\)= +# Default configuration file for cflow. +--symbol __inline:=inline +--symbol __inline__:=inline +--symbol __attribute__:wrapper +--symbol __const__:=const +--symbol __const:=const +--symbol __restrict:=restrict +--symbol __extension__:qualifier +--symbol __asm__:wrapper +--symbol __nonnull:wrapper +--symbol __nothrow__:wrapper +--symbol __pure__:wrapper +--symbol __wur:wrapper + @@ -1,8 +1,8 @@ /* This file is part of GNU cflow - Copyright (C) 1997, 2005, 2007, 2009, 2010 Sergey Poznyakoff + Copyright (C) 1997, 2005, 2007, 2009, 2010, 2011 Sergey Poznyakoff GNU cflow is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. @@ -254,35 +254,50 @@ static struct option_type symbol_optype[] = { * STR is the string of form: NAME:TYPE * NAME means symbol name, TYPE means symbol type (possibly abbreviated) */ static void symbol_override(const char *str) { - int type; const char *ptr; char *name; Symbol *sp; ptr = strchr(str, ':'); if (!ptr) { error(0, 0, _("%s: no symbol type supplied"), str); return; } else { - type = find_option_type(symbol_optype, ptr+1, 0); - if (type == 0) { - error(0, 0, _("unknown symbol type: %s"), ptr+1); - return; + name = strndup(str, ptr - str); + if (ptr[1] == '=') { + Symbol *alias = lookup(ptr+2); + if (!alias) { + alias = install(ptr+2, INSTALL_OVERWRITE); + alias->type = SymToken; + alias->token_type = 0; + alias->source = NULL; + alias->def_line = -1; + alias->ref_line = NULL; + } + sp = install(name, INSTALL_OVERWRITE); + sp->type = SymToken; + sp->alias = alias; + sp->flag = symbol_alias; + } else { + int type = find_option_type(symbol_optype, ptr+1, 0); + if (type == 0) { + error(0, 0, _("unknown symbol type: %s"), ptr+1); + return; + } + sp = install(name, INSTALL_OVERWRITE); + sp->type = SymToken; + sp->token_type = type; } - } - name = strndup(str, ptr - str); - sp = install(name, 0); - sp->type = SymToken; - sp->token_type = type; - sp->source = NULL; - sp->def_line = -1; - sp->ref_line = NULL; + sp->source = NULL; + sp->def_line = -1; + sp->ref_line = NULL; + } } /* Args for --print option */ static struct option_type print_optype[] = { { "xref", 1, PRINT_XREF }, { "cross-ref", 1, PRINT_XREF }, @@ -733,13 +748,13 @@ init() } const char version_etc_copyright[] = /* Do *not* mark this string for translation. %s is a copyright symbol suitable for this locale, and %d is the copyright year. */ - "Copyright %s 2005, 2006, %d Sergey Poznyakoff"; + "Copyright %s 2005, 2006, 2009, 2010, 2011 %d Sergey Poznyakoff"; int main(int argc, char **argv) { int index; diff --git a/src/parser.c b/src/parser.c index 8ba1747..2e4148a 100644 --- a/src/parser.c +++ b/src/parser.c @@ -82,12 +82,14 @@ print_token(TOKSTK *tokptr) case IDENTIFIER: case TYPE: case WORD: case MODIFIER: case STRUCT: case PARM_WRAPPER: + case QUALIFIER: + case OP: fprintf(stderr, "`%s'", tokptr->token); break; case LBRACE0: case LBRACE: fprintf(stderr, "`{'"); break; @@ -101,30 +103,27 @@ print_token(TOKSTK *tokptr) case STATIC: fprintf(stderr, "`static'"); break; case TYPEDEF: fprintf(stderr, "`typedef'"); break; - case OP: - fprintf(stderr, "OP"); /* ouch!!! */ - break; case STRING: fprintf(stderr, "\"%s\"", tokptr->token); break; default: fprintf(stderr, "`%c'", tokptr->type); } } static void -file_error(char *msg, int near) +file_error(char *msg, TOKSTK *tokptr) { fprintf(stderr, "%s:%d: %s", filename, tok.line, msg); - if (near) { + if (tokptr) { fprintf(stderr, _(" near ")); - print_token(&tok); + print_token(tokptr); } fprintf(stderr, "\n"); } void mark(Stackpos pos) @@ -246,24 +245,32 @@ save_token(TOKSTK *tokptr) if (need_space) obstack_1grow(&text_stk, ' '); obstack_1grow(&text_stk, tokptr->type); need_space = 0; break; case ')': + obstack_1grow(&text_stk, tokptr->type); + need_space = 1; + break; case '[': case ']': obstack_1grow(&text_stk, tokptr->type); need_space = 0; break; + case OP: + obstack_1grow(&text_stk, ' '); + obstack_grow(&text_stk, tokptr->token, strlen(tokptr->token)); + need_space = 1; + break; default: if (verbose) - file_error(_("unrecognized definition"), 1); + file_error(_("unrecognized definition"), tokptr); } } -static Stackpos start_pos; /* Start position in stack for saving tokens */ +static Stackpos start_pos; /* Start position in stack for saving tokens *///FIXME: REMOVE static int save_end; /* Stack position up to which the tokens are saved */ void save_stack() { mark(start_pos); @@ -325,18 +332,24 @@ int skip_balanced(int open_tok, int close_tok, int level) { if (level == 0) { if (nexttoken() != open_tok) { return 1; } + level++; } while (nexttoken()) { + if (tok.type == LBRACE0 && open_tok == '{') + tok.type = '{'; + else if (tok.type == RBRACE0 && close_tok == '}') + tok.type = '}'; + if (tok.type == open_tok) level++; else if (tok.type == close_tok) { - if (level-- == 0) { + if (--level == 0) { nexttoken(); return 0; } } } return -1; @@ -381,23 +394,35 @@ static int is_function() { Stackpos sp; int res = 0; mark(sp); -/* if (tok.type == STRUCT) - nexttoken();*/ - while (tok.type == TYPE || - tok.type == IDENTIFIER || - tok.type == MODIFIER || - tok.type == STATIC || - tok.type == EXTERN) - nexttoken(); - - if (tok.type == '(') - res = nexttoken() != MODIFIER; + while (1) { + switch (tok.type) { + case QUALIFIER: + case TYPE: + case IDENTIFIER: + case MODIFIER: + case STATIC: + case EXTERN: + nexttoken(); + continue; + case PARM_WRAPPER: + if (skip_balanced('(', ')', 0) == -1) + file_error(_("unexpected end of file in declaration"), + NULL); + continue; + case '(': + res = nexttoken() != MODIFIER; + break; + default: + break; + } + break; + } restore(sp); return res; } void @@ -432,13 +457,14 @@ expression() case ',': if (parens_lev == 0) return; break; case 0: if (verbose) - file_error(_("unexpected end of file in expression"), 0); + file_error(_("unexpected end of file in expression"), + NULL); return; case IDENTIFIER: name = tok.token; line = tok.line; nexttoken(); @@ -487,36 +513,30 @@ parse_function_declaration(Ident *ident, int parm) /*FALLTHROUGH*/ default: if (error_recovery) nexttoken(); else { if (verbose) - file_error(_("expected `;'"), 1); + file_error(_("expected `;'"), &tok); error_recovery = 1; } goto restart; - - case PARM_WRAPPER: - if (skip_balanced('(', ')', 0) == -1) - file_error(_("unexpected end of file in wrapper"), 0); - goto restart; - case ';': case ',': break; case LBRACE0: case LBRACE: if (ident->name) { caller = lookup(ident->name); func_body(); } break; case 0: if (verbose) - file_error(_("unexpected end of file in declaration"), 0); + file_error(_("unexpected end of file in declaration"), NULL); } } int fake_struct(Ident *ident) { @@ -540,16 +560,16 @@ fake_struct(Ident *ident) token_stack[curs].token = "{ ... }"; tos++; } else { tos = curs + 1; } tokpush(hold.type, hold.line, hold.token); - } else { - if (tok.type != ';') - file_error(_("missing `;' after struct declaration"), 0); - } + } else if (tok.type == '(') + return 0; + else if (tok.type != ';') + file_error(_("missing `;' after struct declaration"), &tok); return 1; } return 0; } void @@ -562,13 +582,13 @@ parse_variable_declaration(Ident *ident, int parm) if (tok.type == STRUCT) { if (nexttoken() == IDENTIFIER) { ident->type_end = tos; } putback(); skip_struct(); - while (tok.type == MODIFIER) + while (tok.type == MODIFIER || tok.type == QUALIFIER) nexttoken(); if (tok.type == IDENTIFIER) { TOKSTK hold = tok; restore(sp); if (ident->type_end == -1) { /* there was no tag. Insert { ... } */ @@ -594,13 +614,13 @@ parse_variable_declaration(Ident *ident, int parm) case ')': if (parm) break; /*FALLTHROUGH*/ default: if (verbose) - file_error(_("expected `;'"), 1); + file_error(_("expected `;'"), &tok); /* FIXME: should putback() here */ /* FALLTHRU */ case ';': break; case ',': if (parm) @@ -619,13 +639,13 @@ parse_variable_declaration(Ident *ident, int parm) case LBRACE0: case LBRACE: func_body(); break; case 0: if (verbose) - file_error(_("unexpected end of file in declaration"), 0); + file_error(_("unexpected end of file in declaration"), NULL); } } void initializer_list() { @@ -641,13 +661,14 @@ initializer_list() if (--lev <= 0) { nexttoken(); return; } break; case 0: - file_error(_("unexpected end of file in initializer list"), 0); + file_error(_("unexpected end of file in initializer list"), + NULL); return; case ',': break; default: expression(); break; @@ -663,40 +684,27 @@ parse_knr_dcl(Ident *ident) parse_dcl(ident, !strict_ansi); } void skip_struct() { - int lev = 0; - if (nexttoken() == IDENTIFIER) { nexttoken(); } else if (tok.type == ';') return; if (tok.type == LBRACE || tok.type == LBRACE0) { - do { - switch (tok.type) { - case 0: - file_error(_("unexpected end of file in struct"), 0); - return; - case LBRACE: - case LBRACE0: - lev++; - break; - case RBRACE: - case RBRACE0: - lev--; - } - nexttoken(); - } while (lev); + if (skip_balanced('{', '}', 1) == -1) { + file_error(_("unexpected end of file in struct"), NULL); + return; + } } while (tok.type == PARM_WRAPPER) { if (skip_balanced('(', ')', 0) == -1) - file_error(_("unexpected end of file in struct"), 0); + file_error(_("unexpected end of file in struct"), NULL); } } void parse_typedef() { @@ -731,28 +739,34 @@ parse_dcl(Ident *ident, int maybe_knr) undo_save_stack(); } int dcl(Ident *idptr) { - int type; - while (nexttoken() != 0 && tok.type != '(') { if (tok.type == MODIFIER) { if (idptr && idptr->type_end == -1) idptr->type_end = curs-1; + } else if (tok.type == PARM_WRAPPER) { + if (skip_balanced('(', ')', 0) == -1) { + file_error(_("unexpected end of file in function declaration"), + NULL); + return 1; + } } else if (tok.type == IDENTIFIER) { + int type; + while (tok.type == IDENTIFIER) nexttoken(); type = tok.type; putback(); if (type == TYPE) continue; else if (type != MODIFIER) break; - } else if (tok.type == ')') { + } else if (tok.type == ')' || tok.type == ';') { return 1; } } if (idptr && idptr->type_end == -1) idptr->type_end = curs-1; return dirdcl(idptr); @@ -764,13 +778,13 @@ dirdcl(Ident *idptr) int wrapper = 0; int *parm_ptr = NULL; if (tok.type == '(') { dcl(idptr); if (tok.type != ')' && verbose) { - file_error(_("expected `)'"), 1); + file_error(_("expected `)'"), &tok); return 1; } } else if (tok.type == IDENTIFIER) { if (idptr) { idptr->name = tok.token; idptr->line = tok.line; @@ -787,40 +801,26 @@ dirdcl(Ident *idptr) while (nexttoken() == '[' || tok.type == '(') { if (tok.type == '[') skip_to(']'); else { maybe_parm_list(parm_ptr); if (tok.type != ')' && verbose) { - file_error(_("expected `)'"), 1); + file_error(_("expected `)'"), &tok); return 1; } } } if (wrapper) nexttoken(); /* read ')' */ - if (tok.type == PARM_WRAPPER) { - if (nexttoken() == '(') { - int level = 0; - while (nexttoken()) { - if (tok.type == 0) { - file_error(_("unexpected end of file in function declaration"), - 0); - return 1; - } else if (tok.type == '(') - level++; - else if (tok.type == ')') { - if (level-- == 0) { - nexttoken(); - break; - } - } - } - } else - putback(); + while (tok.type == PARM_WRAPPER) { + if (skip_balanced('(', ')', 0) == -1) + file_error(_("unexpected end of file in function declaration"), + NULL); } + return 0; } int parmdcl(Ident *idptr) { @@ -860,24 +860,27 @@ maybe_parm_list(int *parm_cnt_return) if (parm_cnt_return) *parm_cnt_return = parmcnt; parm_level--; return; case ',': break; + case QUALIFIER: case IDENTIFIER: + case MODIFIER: /* unsigned * */ case STRUCT: case UNION: case TYPE: parmcnt++; ident.storage = AutoStorage; parse_declaration(&ident, 1); putback(); break; default: if (verbose) - file_error(_("unexpected token in parameter list"), 1); + file_error(_("unexpected token in parameter list"), + &tok); level = 0; do { if (tok.type == '(') level++; else if (tok.type == ')') { if (level-- == 0) @@ -886,13 +889,13 @@ maybe_parm_list(int *parm_cnt_return) } while (nexttoken()); ; putback(); } } if (verbose) - file_error(_("unexpected end of file in parameter list"), 0); + file_error(_("unexpected end of file in parameter list"), NULL); } void func_body() { Ident ident; @@ -924,13 +927,13 @@ func_body() case '{': level++; break; case RBRACE0: if (use_indentation) { if (verbose && level != 1) - file_error(_("forced function body close"), 0); + file_error(_("forced function body close"), NULL); for ( ; level; level--) { delete_autos(level); } break; } /* else: */ @@ -938,13 +941,14 @@ func_body() case '}': delete_autos(level); level--; break; case 0: if (verbose) - file_error(_("unexpected end of file in function body"), 0); + file_error(_("unexpected end of file in function body"), + NULL); caller = NULL; return; } } caller = NULL; } @@ -1018,13 +1022,14 @@ declare(Ident *ident, int maybe_knr) sp->arity = -1; return; } if ((ident->parmcnt >= 0 && (!maybe_knr || get_knr_args(ident) == 0) - && !(tok.type == LBRACE || tok.type == LBRACE0 || tok.type == TYPE)) + && !(tok.type == LBRACE || tok.type == LBRACE0 || tok.type == TYPE + || tok.type == PARM_WRAPPER)) || (ident->parmcnt < 0 && ident->storage == ExplicitExternStorage)) { undo_save_stack(); /* add_external()?? */ return; } @@ -1072,13 +1077,13 @@ declare_type(Ident *ident) undo_save_stack(); sp = lookup(ident->name); for ( ; sp; sp = sp->next) if (sp->type == SymToken && sp->token_type == TYPE) break; if (!sp) - sp = install(ident->name, 1); + sp = install(ident->name, INSTALL_UNIT_LOCAL); sp->type = SymToken; sp->token_type = TYPE; sp->source = filename; sp->def_line = ident->line; sp->ref_line = NULL; if (debug) diff --git a/src/symbol.c b/src/symbol.c index e26e9c5..567e458 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -60,43 +60,50 @@ hash_symbol_compare(void const *data1, void const *data2) struct table_entry const *t1 = data1; struct table_entry const *t2 = data2; return t1->sym && t2->sym && strcmp(t1->sym->name, t2->sym->name) == 0; } Symbol * -lookup(char *name) +lookup(const char *name) { - Symbol s; + Symbol s, *sym; struct table_entry t, *tp; if (!symbol_table) return NULL; - s.name = name; + s.name = (char*) name; t.sym = &s; tp = hash_lookup(symbol_table, &t); - return tp ? tp->sym : NULL; + if (tp) { + sym = tp->sym; + while (sym->type == SymToken && sym->flag == symbol_alias) + sym = sym->alias; + } else + sym = NULL; + return sym; } /* Install a new symbol `NAME'. If UNIT_LOCAL is set, this symbol can be local to the current compilation unit. */ Symbol * -install(char *name, int unit_local) +install(char *name, int flags) { Symbol *sym; struct table_entry *tp, *ret; sym = xmalloc(sizeof(*sym)); memset(sym, 0, sizeof(*sym)); sym->type = SymUndefined; sym->name = name; tp = xmalloc(sizeof(*tp)); tp->sym = sym; - if (unit_local && - canonical_filename && strcmp(filename, canonical_filename)) { + if (((flags & INSTALL_CHECK_LOCAL) && + canonical_filename && strcmp(filename, canonical_filename)) || + (flags & INSTALL_UNIT_LOCAL)) { sym->flag = symbol_temp; append_symbol(&static_symbol_list, sym); } else sym->flag = symbol_none; if (! ((symbol_table @@ -104,12 +111,17 @@ install(char *name, int unit_local) hash_symbol_hasher, hash_symbol_compare, 0))) && (ret = hash_insert (symbol_table, tp)))) xalloc_die (); if (ret != tp) { + if (flags & INSTALL_OVERWRITE) { + free(sym); + free(tp); + return ret->sym; + } if (ret->sym->type != SymUndefined) sym->next = ret->sym; ret->sym = sym; free(tp); } sym->owner = ret; @@ -139,13 +151,15 @@ ident_change_storage(Symbol *sp, enum storage storage) Symbol * install_ident(char *name, enum storage storage) { Symbol *sp; - sp = install(name, storage != AutoStorage); + sp = install(name, + storage != AutoStorage ? + INSTALL_CHECK_LOCAL : INSTALL_DEFAULT); sp->type = SymIdentifier; sp->arity = -1; sp->storage = ExternStorage; sp->decl = NULL; sp->source = NULL; sp->def_line = -1; |