summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2014-02-07 14:15:57 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2014-02-07 14:24:20 (GMT)
commit0f28750f5b22c2d4d9d9b7fad49b1f7bdca5e403 (patch) (side-by-side diff)
treeb6aec4fcd4512c9c5c672675ee0f8b6453b0f812 /src
parent24a87761b4398c48d554ae44861b33a98c4c39e4 (diff)
downloadcflow-0f28750f5b22c2d4d9d9b7fad49b1f7bdca5e403.tar.gz
cflow-0f28750f5b22c2d4d9d9b7fad49b1f7bdca5e403.tar.bz2
Correctly handle functions returning struct/union
This fixes bug #31792. * bootstrap (gnulib_extra_files): Remove "missing" * gnulib: Upgrade * gnulib.modules: Add xalloc. * src/Makefile.am: Use AM_CPPFLAGS instead of INCLUDES. * src/parser.c (token_type_str) (dbgtok,debugtoken): New diagnostic functions. (tokdel,tokins): New functions. (nexttoken): Clear yylval.str. Print token stack state. (putback): Copy all data to tok. Print token stack state. (file_error,restore (is_function): Hanlde struct, union and enum: all these can appear in the return type specification. (fake_struct): Don't destroy token stack. Use tokdel and tokins to modify it. (parse_variable_declaration): Likewise. * tests/Makefile.am: Add new testcases. * tests/testsuite.at: Likewise. * tests/struct02.at: New file. * tests/struct03.at: New file. * tests/struct04.at: New file.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am5
-rw-r--r--src/parser.c158
2 files changed, 140 insertions, 23 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index f4736d7..a66f42a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -18,7 +18,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301 USA.
-INCLUDES = -I$(top_srcdir)/gnu -I../ -I../gnu
bin_PROGRAMS = cflow
cflow_SOURCES = \
@@ -40,7 +39,9 @@ cflow_SOURCES = \
localedir = $(datadir)/locale
LDADD=../gnu/libgnu.a @LIBINTL@
-AM_CPPFLAGS=-DLOCALEDIR=\"$(localedir)\"
+AM_CPPFLAGS=\
+ -I$(top_srcdir)/gnu -I../ -I../gnu\
+ -DLOCALEDIR=\"$(localedir)\"
AM_LFLAGS=-dvp
EXTRA_DIST=cflow.rc
diff --git a/src/parser.c b/src/parser.c
index 176d9f2..bdb9e22 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,5 +1,5 @@
/* This file is part of GNU cflow
- Copyright (C) 1997, 2005, 2006, 2007, 2009, 2010, 2011 Sergey Poznyakoff
+ Copyright (C) 1997, 2005, 2006, 2007, 2009, 2010, 2011, 2014 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
@@ -114,6 +114,94 @@ print_token(TOKSTK *tokptr)
}
}
+static char *
+token_type_str(int t)
+{
+ static char buf[80];
+ switch (t) {
+ case 0:
+ return "EOF";
+ case WORD:
+ return "WORD";
+ case LBRACE0:
+ return "'{'";
+ case RBRACE0:
+ return "'}'";
+ case IDENTIFIER:
+ return "IDENTIFIER";
+ case EXTERN:
+ return "EXTERN";
+ case STATIC:
+ return "STATIC";
+ case TYPEDEF:
+ return "TYPEDEF";
+ case STRUCT:
+ return "STRUCT";
+ case MODIFIER:
+ return "MODIFIER";
+ case OP:
+ return "OP";
+ case UNION:
+ return "UNION";
+ case ENUM:
+ return "ENUM";
+ case LBRACE:
+ return "' {'";
+ case RBRACE:
+ return "' }'";
+ case MEMBER_OF:
+ return "MEMBER_OF";
+ case TYPE:
+ return "TYPE";
+ case STRING:
+ return "STRING";
+ case PARM_WRAPPER:
+ return "PARM_WRAPPER";
+ case QUALIFIER:
+ return "QUALIFIER";
+ }
+ if (isprint(t))
+ snprintf(buf, sizeof(buf), "'%c'(%d)", t, t);
+ else
+ snprintf(buf, sizeof(buf), "%d", t);
+ return buf;
+}
+
+static void
+dbgtok(TOKSTK *t, int delim)
+{
+ if (delim)
+ putchar(delim);
+ printf("{ %s ", token_type_str(t->type));
+ if (t->type)
+ printf(", %s, %d ", t->token ? t->token : "NULL", t->line);
+ putchar('}');
+}
+
+static void
+debugtoken(TOKSTK *t, char *fmt, ...)
+{
+ if (debug > 1) {
+ va_list ap;
+ int i;
+
+ if (fmt) {
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+ printf(": ");
+ }
+ if (t) {
+ dbgtok(t, 0);
+ printf("; ");
+ }
+ printf("%d: {", curs);
+ for (i = curs; i < tos; i++)
+ dbgtok(token_stack + i, i == curs ? 0 : ',');
+ printf("}\n");
+ }
+}
+
static void
file_error(char *msg, TOKSTK *tokptr)
{
@@ -129,14 +217,45 @@ void
mark(Stackpos pos)
{
pos[0] = curs;
+ if (debug > 2)
+ printf("marking stack at %d\n", curs);
}
void
restore(Stackpos pos)
{
curs = pos[0];
- if (curs)
+ if (curs) {
tok = token_stack[curs-1];
+ debugtoken(&tok, "restored stack");
+ }
+}
+
+void
+tokdel(int beg, int end)
+{
+ if (end >= beg) {
+ if (end < tos)
+ memmove(token_stack + beg, token_stack + end + 1,
+ (end - beg + 1) * sizeof(token_stack[0]));
+ tos -= (end - beg + 1);
+ }
+}
+
+void
+tokins(int pos, int type, int line, char *token)
+{
+ if (++tos == token_stack_length) {
+ token_stack_length += token_stack_increase;
+ token_stack = xrealloc(token_stack,
+ token_stack_length*sizeof(*token_stack));
+ }
+ memmove(token_stack + pos + 1, token_stack + pos,
+ (tos - pos - 1) * sizeof(token_stack[0]));
+ token_stack[pos].type = type;
+ token_stack[pos].token = token;
+ token_stack[pos].line = line;
+ debugtoken(&token_stack[pos], "insert at %d", pos);
}
void
@@ -178,9 +297,11 @@ nexttoken()
if (curs == tos) {
type = get_token();
tokpush(type, line_num, yylval.str);
+ yylval.str = NULL;
}
tok = token_stack[curs];
curs++;
+ debugtoken(&tok, "next token");
return tok.type;
}
@@ -191,10 +312,10 @@ putback()
error(10, 0, _("INTERNAL ERROR: cannot return token to stream"));
curs--;
if (curs > 0) {
- tok.type = token_stack[curs-1].type;
- tok.token = token_stack[curs-1].token;
+ tok = token_stack[curs-1];
} else
tok.type = 0;
+ debugtoken(&tok, "putback");
return tok.type;
}
@@ -405,6 +526,9 @@ is_function()
case MODIFIER:
case STATIC:
case EXTERN:
+ case STRUCT:
+ case UNION:
+ case ENUM:
nexttoken();
continue;
case PARM_WRAPPER:
@@ -551,18 +675,14 @@ fake_struct(Ident *ident)
putback();
skip_struct();
if (tok.type == IDENTIFIER || tok.type == MODIFIER) {
- TOKSTK hold = tok;
+ int pos = curs-1;
restore(sp);
if (ident->type_end == -1) {
/* there was no tag. Insert { ... } */
- tos = curs;
- token_stack[curs].type = IDENTIFIER;
- token_stack[curs].token = "{ ... }";
- tos++;
- } else {
- tos = curs + 1;
+ tokdel(curs, pos - 1);
+ tokins(curs, IDENTIFIER, tok.line, "{ ... }");
+ debugtoken(&tok, "modified stack");
}
- tokpush(hold.type, hold.line, hold.token);
} else if (tok.type == '(')
return 0;
else if (tok.type != ';')
@@ -579,7 +699,7 @@ parse_variable_declaration(Ident *ident, int parm)
mark(sp);
ident->type_end = -1;
- if (tok.type == STRUCT) {
+ if (tok.type == STRUCT || tok.type == UNION) {
if (nexttoken() == IDENTIFIER) {
ident->type_end = tos;
}
@@ -588,18 +708,14 @@ parse_variable_declaration(Ident *ident, int parm)
while (tok.type == MODIFIER || tok.type == QUALIFIER)
nexttoken();
if (tok.type == IDENTIFIER) {
- TOKSTK hold = tok;
+ int pos = curs-1;
restore(sp);
if (ident->type_end == -1) {
/* there was no tag. Insert { ... } */
- tos = curs;
- token_stack[curs].type = IDENTIFIER;
- token_stack[curs].token = "{ ... }";
- tos++;
- } else {
- tos = curs + 1;
+ tokdel(curs, pos - 1);
+ tokins(curs, IDENTIFIER, tok.line, "{ ... }");
+ debugtoken(&tok, "modified stack");
}
- tokpush(hold.type, hold.line, hold.token);
} else {
if (tok.type == ';')
return;

Return to:

Send suggestions and report system problems to the System administrator.