diff options
Diffstat (limited to 'src/interfaces/ecpg/preproc/pgc.l')
-rw-r--r-- | src/interfaces/ecpg/preproc/pgc.l | 127 |
1 files changed, 89 insertions, 38 deletions
diff --git a/src/interfaces/ecpg/preproc/pgc.l b/src/interfaces/ecpg/preproc/pgc.l index dcd567e..bed86cc 100644 --- a/src/interfaces/ecpg/preproc/pgc.l +++ b/src/interfaces/ecpg/preproc/pgc.l @@ -69,7 +69,14 @@ char *token_start; static int state_before_str_start; static int state_before_str_stop; -struct _yy_buffer +/* + * State for handling include files and macro expansion. We use a new + * flex input buffer for each level of include or macro, and create a + * struct _yy_buffer to remember the previous level. There is not a struct + * for the currently active input source; that state is kept in the global + * variables YY_CURRENT_BUFFER, yylineno, and input_filename. + */ +static struct _yy_buffer { YY_BUFFER_STATE buffer; long lineno; @@ -77,8 +84,6 @@ struct _yy_buffer struct _yy_buffer *next; } *yy_buffer = NULL; -static char *old; - /* * Vars for handling ifdef/elif/endif constructs. preproc_tos is the current * nesting depth of such constructs, and stacked_if_value[preproc_tos] is the @@ -444,6 +449,8 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ %{ /* code to execute during start of each call of yylex() */ + char *newdefsymbol = NULL; + token_start = NULL; %} @@ -1010,6 +1017,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } {identifier} { + /* First check to see if it's a define symbol to expand */ if (!isdefine()) { int kwvalue; @@ -1198,17 +1206,23 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ yytext[i+1] = '\0'; - for (ptr = defines; ptr != NULL; ptr2 = ptr, ptr = ptr->next) + /* Find and unset any matching define; should be only 1 */ + for (ptr = defines; ptr; ptr2 = ptr, ptr = ptr->next) { - if (strcmp(yytext, ptr->olddef) == 0) + if (strcmp(yytext, ptr->name) == 0) { - if (ptr2 == NULL) - defines = ptr->next; - else - ptr2->next = ptr->next; - free(ptr->newdef); - free(ptr->olddef); - free(ptr); + free(ptr->value); + ptr->value = NULL; + /* We cannot forget it if there's a cmdvalue */ + if (ptr->cmdvalue == NULL) + { + if (ptr2 == NULL) + defines = ptr->next; + else + ptr2->next = ptr->next; + free(ptr->name); + free(ptr); + } break; } } @@ -1413,11 +1427,17 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ ; yytext[i+1] = '\0'; - for (defptr = defines; - defptr != NULL && - strcmp(yytext, defptr->olddef) != 0; - defptr = defptr->next) - /* skip */ ; + /* Does a definition exist? */ + for (defptr = defines; defptr; defptr = defptr->next) + { + if (strcmp(yytext, defptr->name) == 0) + { + /* Found it, but is it currently undefined? */ + if (defptr->value == NULL) + defptr = NULL; /* pretend it's not found */ + break; + } + } this_active = (defptr ? ifcond : !ifcond); stacked_if_value[preproc_tos].active = @@ -1438,7 +1458,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ yyterminate(); } <def_ident>{identifier} { - old = mm_strdup(yytext); + newdefsymbol = mm_strdup(yytext); BEGIN(def); startlit(); } @@ -1447,26 +1467,31 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ yyterminate(); } <def>{space}*";" { - struct _defines *ptr, *this; + struct _defines *ptr; + /* Does it already exist? */ for (ptr = defines; ptr != NULL; ptr = ptr->next) { - if (strcmp(old, ptr->olddef) == 0) - { - free(ptr->newdef); - ptr->newdef = mm_strdup(literalbuf); - } + if (strcmp(newdefsymbol, ptr->name) == 0) + { + free(ptr->value); + ptr->value = mm_strdup(literalbuf); + /* Don't leak newdefsymbol */ + free(newdefsymbol); + break; + } } if (ptr == NULL) { - this = (struct _defines *) mm_alloc(sizeof(struct _defines)); - - /* initial definition */ - this->olddef = old; - this->newdef = mm_strdup(literalbuf); - this->next = defines; - this->used = NULL; - defines = this; + /* Not present, make a new entry */ + ptr = (struct _defines *) mm_alloc(sizeof(struct _defines)); + + ptr->name = newdefsymbol; + ptr->value = mm_strdup(literalbuf); + ptr->cmdvalue = NULL; + ptr->used = NULL; + ptr->next = defines; + defines = ptr; } BEGIN(C); @@ -1483,6 +1508,7 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ <<EOF>> { if (yy_buffer == NULL) { + /* No more input */ if (preproc_tos > 0) { preproc_tos = 0; @@ -1492,16 +1518,20 @@ cppline {space}*#([^i][A-Za-z]*|{if}|{ifdef}|{ifndef}|{import})((\/\*[^*/]*\*+ } else { + /* Revert to previous input source */ struct _yy_buffer *yb = yy_buffer; int i; struct _defines *ptr; + /* Check to see if we are exiting a macro value */ for (ptr = defines; ptr; ptr = ptr->next) + { if (ptr->used == yy_buffer) { ptr->used = NULL; - break; + break; /* there can't be multiple matches */ } + } if (yyin != NULL) fclose(yyin); @@ -1726,15 +1756,24 @@ ecpg_isspace(char ch) return false; } -static bool isdefine(void) +/* + * If yytext matches a define symbol, begin scanning the symbol's value + * and return true + */ +static bool +isdefine(void) { struct _defines *ptr; /* is it a define? */ for (ptr = defines; ptr; ptr = ptr->next) { - if (strcmp(yytext, ptr->olddef) == 0 && ptr->used == NULL) + /* notice we do not match anything being actively expanded */ + if (strcmp(yytext, ptr->name) == 0 && + ptr->value != NULL && + ptr->used == NULL) { + /* Save state associated with the current buffer */ struct _yy_buffer *yb; yb = mm_alloc(sizeof(struct _yy_buffer)); @@ -1743,10 +1782,17 @@ static bool isdefine(void) yb->lineno = yylineno; yb->filename = mm_strdup(input_filename); yb->next = yy_buffer; + yy_buffer = yb; - ptr->used = yy_buffer = yb; + /* Mark symbol as being actively expanded */ + ptr->used = yb; - yy_scan_string(ptr->newdef); + /* + * We use yy_scan_string which will copy the value, so there's + * no need to worry about a possible undef happening while we + * are still scanning it. + */ + yy_scan_string(ptr->value); return true; } } @@ -1754,7 +1800,12 @@ static bool isdefine(void) return false; } -static bool isinformixdefine(void) +/* + * Handle replacement of INFORMIX built-in defines. This works just + * like isdefine() except for the source of the string to scan. + */ +static bool +isinformixdefine(void) { const char *new = NULL; |