From b512671643b0d6f801b653ec5c9a08f437800a44 Mon Sep 17 00:00:00 2001 From: Michael Witten Date: Fri, 15 Feb 2008 18:04:14 -0500 Subject: [PATCH] ivlpp: Removed yywrap() to handle EOF more sanely When the lexical analyzer encounters and EOF, the analyzer invokes yywrap() to determine what to do next. The function determines one of two paths of execution: (1) If yywrap() returns 0, then the analyzer assumes that yywrap() has setup a new input source, and so scanning continues. (2) If yywrap() returns non-zero, then the analyzer assumes that yywrap() has not setup a new input source, and so the analyzer proceeds to run the matching EOF action (the default of which invokes yyterminate()). NOTE: The analyzer does not touch the start condition. The old implementation was using yywrap() to destroy the current input source and setup the next one. However, this causes problems when the analyzer is in the middle of parsing some directive: (1) Because yywrap() is called before any EOF action, the include_stack_t structure is destroyed before being used in the EOF action; the result is a segfault. (2) Because yywrap() does not change the start condition, any EOF action would occur completely out of context; however, because of (1), this problem never cropped up. The new implementation simply: (1) Employs "%option noyywrap", which effectively causes the analyzer to act as though yywrap() produces a non-zero. (2) Renames yywrap "load_next_input". (3) Calls load_next_input() explicitly in exhaustive EOF actions, so that control is more fine grained. The added benefit is that the code that finishes parsing EOF terminated directives now works properly; `include and `define directives previously segfaulted in such situations. Signed-off-by: Michael Witten --- ivlpp/lexor.lex | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/ivlpp/lexor.lex b/ivlpp/lexor.lex index 6b6f96a22..92c20e268 100644 --- a/ivlpp/lexor.lex +++ b/ivlpp/lexor.lex @@ -52,8 +52,8 @@ static char*macro_name(); static void include_filename(); static void do_include(); -static int yywrap(); +static int load_next_input(); struct include_stack_t { char* path; @@ -160,6 +160,7 @@ static int ma_parenthesis_level = 0; %option nounput %option noinput %option noyy_top_state +%option noyywrap %x PPINCLUDE %x DEF_NAME @@ -316,6 +317,9 @@ W [ \t\b\f]+ istack->lineno += 1; fputc('\n', yyout); yy_pop_state(); + + if (!load_next_input()) + yyterminate(); } `undef{W}[a-zA-Z_][a-zA-Z0-9_$]*{W}?.* { def_undefine(); } @@ -521,6 +525,8 @@ W [ \t\b\f]+ fputc('\n', yyout); } +<> { if (!load_next_input()) yyterminate(); } + %% /* Defined macros are kept in this table for convenient lookup. As `define directives are matched (and the do_define() function @@ -1130,15 +1136,16 @@ static void do_expand(int use_args) * files that are opened and being processed. The first item on the * stack is the current file being scanned. If I get to an include * statement, + * * open the new file, * save the current buffer context, * create a new buffer context, * and push the new file information. * - * When the file runs out, the yywrap closes the file and deletes the - * buffer. If after popping the current file information there is - * another file on the stack, restore its buffer context and resume - * parsing. + * When the file runs out, it is closed and the buffer is deleted + * If after popping the current file information there is another + * file on the stack, that file's buffer context is restored and + * parsing resumes. */ static void output_init() @@ -1246,12 +1253,7 @@ static void lexor_done() } } -/* - * The lexical analyzer calls this function when the current file - * ends. Here I pop the include stack and resume the previous file. If - * there is no previous file, then the main input is ended. - */ -static int yywrap() +static int load_next_input() { int line_mask_flag = 0; struct include_stack_t*isp = istack; @@ -1284,7 +1286,7 @@ static int yywrap() if (istack == 0) { if (file_queue == 0) { lexor_done(); - return 1; + return 0; } istack = file_queue; @@ -1296,7 +1298,7 @@ static int yywrap() if (istack->file == 0) { perror(istack->path); error_count += 1; - return 1; + return 0; } if (line_direct_flag) @@ -1306,7 +1308,7 @@ static int yywrap() } yyrestart(istack->file); - return 0; + return 1; } @@ -1319,7 +1321,7 @@ static int yywrap() fprintf(yyout, "\n`line %u \"%s\" 2\n", istack->lineno+1, istack->path); - return 0; + return 1; } /* @@ -1438,7 +1440,7 @@ void reset_lexor(FILE*out, char*paths[]) isp->next = 0; /* Now build up a queue of all the remaining file names, so - that yywrap can pull them when needed. */ + that load_next_input() can pull them when needed. */ file_queue = 0; for (idx = 1 ; paths[idx] ; idx += 1) { isp = malloc(sizeof(struct include_stack_t));