/* * C and T preprocessor, and integrated lexer * (c) Thomas Pornin 1999, 2000 * * 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. * 4. The name of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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. * */ /*vb*/#ifdef HAVE_MISRAvoid misra(int,...);#endif #define VERS_MAJ 1#define VERS_MIN 0/* uncomment the following if you cannot set it with a compiler flag *//* #define STAND_ALONE */ #include "tune.h"#ifdef UCPP_MMAP#ifndef _POSIX_SOURCE#define _POSIX_SOURCE 1#endif#endif#include <stdio.h>#include <string.h>#include <stdarg.h>#include <setjmp.h>#include <stddef.h>#include <limits.h>#include <time.h>#include "ucppi.h"#include "mem.h"#include "hash.h"#ifdef UCPP_MMAP#include <unistd.h>#include <sys/types.h>#include <sys/mman.h>#include <fcntl.h>#endif /* * The standard path where includes are looked for. */#ifdef STAND_ALONEstatic char *include_path_std[] = { STD_INCLUDE_PATH, 0 };#endifstatic char **include_path;static size_t include_path_nb = 0; int no_special_macros = 0;int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0;FILE *emit_output; #ifdef STAND_ALONEstatic char *system_macros_def[] = { STD_MACROS, 0 };static char *system_assertions_def[] = { STD_ASSERT, 0 };#endif char *current_filename, *current_long_filename = 0;static int current_incdir = -1; #ifndef NO_UCPP_ERROR_FUNCTIONS/* * "ouch" is the name for an internal ucpp error. If AUDIT is not defined, * no code calling this function will be generated; a "ouch" may still be * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch" * does not use this function. */#endif /* NO_UCPP_ERROR_FUNCTIONS */ /* * Some memory allocations are manually garbage-collected; essentially, * strings duplicated in the process of macro replacement. Each such * string is referenced in the garbage_fifo, which is cleared when all * nested macros have been resolved. */ struct garbage_fifo { char **garbage; size_t ngarb, memgarb;}; /* * throw_away() marks a string to be collected later */void throw_away(struct garbage_fifo *gf, char *n){ wan(gf->garbage, gf->ngarb, n, gf->memgarb);} /* * free marked strings */void garbage_collect(struct garbage_fifo *gf){ size_t i; for (i = 0; i < gf->ngarb; i ++) freemem(gf->garbage[i]); gf->ngarb = 0;} static void init_garbage_fifo(struct garbage_fifo *gf){ gf->garbage = getmem((gf->memgarb = GARBAGE_LIST_MEMG) * sizeof(char *)); gf->ngarb = 0;} /* * order is important: it must match the token-constants declared as an * enum in the header file. */char *operators_name[] = { " ", "\n", " ", "0000", "name", "bunch", "pragma", "context", "\"dummy string\"", "'dummy char'", "/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<", "<<=", ">", ">=", ">>", ">>=", "=", "==",#ifdef CAST_OP "=>",#endif "~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=", "^", "^=", "!", "~=", "{", "}", "[", "]", "(", ")", ",", "?", ";", ":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>", "%:", "%:%:"}; /* the ascii representation of a token */#ifdef SEMPER_FIDELIS#define tname(x) (ttWHI((x).type) ? " " : S_TOKEN((x).type) \ ? (x).name : operators_name[(x).type])#else#define tname(x) (S_TOKEN((x).type) ? (x).name \ : operators_name[(x).type])#endif char *token_name(struct token *t){ return tname(*t);} /* * To speed up deeply nested and repeated inclusions, we: * -- use a hash table to remember where we found each file * -- remember when the file is protected by a #ifndef/#define/#endif * construction; we can then avoid including several times a file * when this is not necessary. * -- remember in which directory, in the include path, the file was found. */struct found_file { char *name; /* first field */ char *long_name; char *protect; int incdir;}; static struct HT *found_files = 0, *found_files_loc = 0; static struct found_file *new_found_file(void){ struct found_file *ff = getmem(sizeof(struct found_file)); ff->protect = 0; ff->incdir = -1; return ff;} static void del_found_file(void *m){ struct found_file *ff = (struct found_file *)m; freemem(ff->name); freemem(ff->long_name); if (ff->protect) freemem(ff->protect);} /* * To keep up with the #ifndef/#define/#endif protection mechanism * detection. */struct protect protect_detect;static struct protect *protect_detect_stack = 0; /* * "current_filename" is used for error reporting, and the __FILE__ macro */static void set_current_filename(char *x){ current_filename = x;} void set_init_filename(char *x, int real_file){ set_current_filename(sdup(x)); current_long_filename = 0; current_incdir = -1; if (real_file) { protect_detect.macro = 0; protect_detect.state = 1; protect_detect.ff = new_found_file(); protect_detect.ff->name = sdup(x); protect_detect.ff->long_name = sdup(x); putHT(found_files_loc, protect_detect.ff); } else { protect_detect.state = 0; }} static void init_found_files(void){ if (found_files) killHT(found_files); found_files = newHT(128, cmp_struct, hash_struct, del_found_file); if (found_files_loc) killHT(found_files_loc); found_files_loc = newHT(128, cmp_struct, hash_struct, del_found_file);} /* * convert a Unix-style path for the host architecture */#if defined(MSDOS) || defined(ATARI)static char *convert_path(char *path){ /* on msdos systems, replace all / by \ */ char *c, *newp = sdup(path); for (c = newp; *c; c ++) if (*c == '/') *c = '\\'; return newp;} #elif defined AMIGAstatic char *convert_path(char *path){ char *newp = getmem(1 + strlen(path)); char *s = path, *d = newp; if (*s == '.') { /* convert "." to "" */ if (*(s+1) == '\0') s++; } while (*s) { if (*s == '.') { if (*(s+1) == '/') { s += 2; /* "./" is discarded */ continue; } else if (*(s+1) == '.') { if (*(s+2) == '/') s += 2; /* "../" is converted to "/" */ } } *d++ = *s++; } *d = '\0'; return newp;} #else /* no conversion */static char *convert_path(char *path){ return sdup(path);}#endif /* * Set the lexer state at the beginning of a file. */static void reinit_lexer_state(struct lexer_state *ls, int wb){#ifndef NO_UCPP_BUF ls->input_buf = wb ? getmem(INPUT_BUF_MEMG) : 0;#ifdef UCPP_MMAP ls->from_mmap = 0;#endif#endif ls->ebuf = ls->pbuf = 0; ls->nlka = 0; ls->macfile = 0; ls->discard = 1; ls->last = 0; /* we suppose '\n' is not 0 */ ls->line = 1; ls->ltwnl = 1; ls->oline = 1; ls->pending_token = 0; ls->cli = 0; ls->copy_line[COPY_LINE_LENGTH - 1] = 0; ls->ifnest = 0; ls->condf[0] = ls->condf[1] = 0;} /* * Initialize the struct lexer_state, with optional input and output buffers. */void init_buf_lexer_state(struct lexer_state *ls, int wb){ reinit_lexer_state(ls, wb);#ifndef NO_UCPP_BUF ls->output_buf = wb ? getmem(OUTPUT_BUF_MEMG) : 0;#endif ls->sbuf = 0; ls->ctok = getmem(sizeof(struct token)); ls->ctok->name = getmem(ls->tknl = TOKEN_NAME_MEMG); ls->pending_token = 0; ls->flags = 0; ls->count_trigraphs = 0; ls->gf = getmem(sizeof(struct garbage_fifo)); init_garbage_fifo(ls->gf); ls->condcomp = 1; ls->condnest = 0;#ifdef INMACRO_FLAG ls->inmacro = 0; ls->macro_count = 0;#endif} /* * Initialize the (complex) struct lexer_state. */void init_lexer_state(struct lexer_state *ls){ init_buf_lexer_state(ls, 1);} /* * Restore what is needed from a lexer_state. This is used for #include. */static void restore_lexer_state(struct lexer_state *ls, struct lexer_state *lsbak){#ifndef NO_UCPP_BUF freemem(ls->input_buf); ls->input_buf = lsbak->input_buf;#ifdef UCPP_MMAP ls->from_mmap = lsbak->from_mmap; ls->input_buf_sav = lsbak->input_buf_sav;#endif#endif ls->input = lsbak->input; ls->ebuf = lsbak->ebuf; ls->pbuf = lsbak->pbuf; ls->nlka = lsbak->nlka; ls->macfile = lsbak->macfile; ls->discard = lsbak->discard; ls->line = lsbak->line; ls->oline = lsbak->oline; ls->ifnest = lsbak->ifnest; ls->condf[0] = lsbak->condf[0]; ls->condf[1] = lsbak->condf[1];} /* * file_context (and the two functions push_ and pop_) are used to save * all that is needed when including a file. */static struct file_context { struct lexer_state ls; char *name, *long_name; int incdir;} *ls_stack;static size_t ls_depth = 0; static void push_file_context(struct lexer_state *ls){ struct file_context fc; if (ls_depth > 1023) error(ls->line - 1, "too many nested includes"); fc.name = current_filename; fc.long_name = current_long_filename; fc.incdir = current_incdir; mmv(&(fc.ls), ls, sizeof(struct lexer_state)); aol(ls_stack, ls_depth, fc, LS_STACK_MEMG); ls_depth --; aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG); protect_detect.macro = 0;} static void pop_file_context(struct lexer_state *ls){#ifdef AUDIT if (ls_depth <= 0) ouch("prepare to meet thy creator");#endif restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls)); if (protect_detect.macro) freemem(protect_detect.macro); protect_detect = protect_detect_stack[ls_depth]; set_current_filename(ls_stack[ls_depth].name); current_long_filename = ls_stack[ls_depth].long_name; current_incdir = ls_stack[ls_depth].incdir;} /* * report_context() returns the list of successive includers of the * current file, ending with a dummy entry with a negative line number. * The caller is responsible for freeing the returned pointer. */struct stack_context *report_context(void){ struct stack_context *sc; size_t i; sc = getmem((ls_depth + 1) * sizeof(struct stack_context)); for (i = 0; i < ls_depth; i ++) { sc[i].name = ls_stack[ls_depth - i - 1].name; sc[i].long_name = ls_stack[ls_depth - i - 1].long_name; sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1; } sc[ls_depth].line = -1; return sc;} /* * init_lexer_mode() is used to end initialization of a struct lexer_state * if it must be used for a lexer */void init_lexer_mode(struct lexer_state *ls){ ls->flags = DEFAULT_LEXER_FLAGS; ls->output_fifo = getmem(sizeof(struct token_fifo)); ls->output_fifo->art = ls->output_fifo->nt = 0; ls->toplevel_of = ls->output_fifo; ls->save_ctok = ls->ctok;} /* * release memory used by a struct lexer_state */void free_lexer_state(struct lexer_state *ls){#ifndef NO_UCPP_BUF if (ls->input_buf) freemem(ls->input_buf); if (ls->output_buf) freemem(ls->output_buf);#endif freemem(ls->ctok->name); freemem(ls->ctok); if (!(ls->flags & LEXER)) garbage_collect(ls->gf); freemem(ls->gf);} /* * Print line information. */static void print_line_info(struct lexer_state *ls, unsigned long flags){ char *fn = current_long_filename ? current_long_filename : current_filename; char *b, *d; b = getmem(50 + strlen(fn)); if (flags & GCC_LINE_NUM) { sprintf(b, "# %ld \"%s\"\n", ls->line, fn); } else { sprintf(b, "#line %ld \"%s\"\n", ls->line, fn); } for (d = b; *d; d ++) put_char(ls, (unsigned char)(*d)); freemem(b);} /* * Enter a file; this implies the possible emission of a #line directive. * The flags used are passed as second parameter instead of being * extracted from the struct lexer_state. * * As a command-line option, gcc-like directives (with only a '#', * without 'line') may be produced. */void enter_file(struct lexer_state *ls, unsigned long flags){ char *fn = current_long_filename ? current_long_filename : current_filename; if (!(flags & LINE_NUM)) return; if ((flags & LEXER) && !(flags & TEXT_OUTPUT)) { struct token t; t.type = CONTEXT;Lines 1–500 of 2261. Load more
/* * C and T preprocessor, and integrated lexer * (c) Thomas Pornin 1999, 2000 * * 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. * 4. The name of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS 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. * */ /*vb*/ #ifdef HAVE_MISRA void misra(int,...); #endif #define VERS_MAJ 1 #define VERS_MIN 0 /* uncomment the following if you cannot set it with a compiler flag */ /* #define STAND_ALONE */ #include "tune.h" #ifdef UCPP_MMAP #ifndef _POSIX_SOURCE #define _POSIX_SOURCE 1 #endif #endif #include <stdio.h> #include <string.h> #include <stdarg.h> #include <setjmp.h> #include <stddef.h> #include <limits.h> #include <time.h> #include "ucppi.h" #include "mem.h" #include "hash.h" #ifdef UCPP_MMAP #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <fcntl.h> #endif /* * The standard path where includes are looked for. */ #ifdef STAND_ALONE static char *include_path_std[] = { STD_INCLUDE_PATH, 0 }; #endif static char **include_path; static size_t include_path_nb = 0; int no_special_macros = 0; int emit_dependencies = 0, emit_defines = 0, emit_assertions = 0; FILE *emit_output; #ifdef STAND_ALONE static char *system_macros_def[] = { STD_MACROS, 0 }; static char *system_assertions_def[] = { STD_ASSERT, 0 }; #endif char *current_filename, *current_long_filename = 0; static int current_incdir = -1; #ifndef NO_UCPP_ERROR_FUNCTIONS /* * "ouch" is the name for an internal ucpp error. If AUDIT is not defined, * no code calling this function will be generated; a "ouch" may still be * emitted by getmem() (in mem.c) if MEM_CHECK is defined, but this "ouch" * does not use this function. */ #endif /* NO_UCPP_ERROR_FUNCTIONS */ /* * Some memory allocations are manually garbage-collected; essentially, * strings duplicated in the process of macro replacement. Each such * string is referenced in the garbage_fifo, which is cleared when all * nested macros have been resolved. */ struct garbage_fifo { char **garbage; size_t ngarb, memgarb; }; /* * throw_away() marks a string to be collected later */ void throw_away(struct garbage_fifo *gf, char *n) { wan(gf->garbage, gf->ngarb, n, gf->memgarb); } /* * free marked strings */ void garbage_collect(struct garbage_fifo *gf) { size_t i; for (i = 0; i < gf->ngarb; i ++) freemem(gf->garbage[i]); gf->ngarb = 0; } static void init_garbage_fifo(struct garbage_fifo *gf) { gf->garbage = getmem((gf->memgarb = GARBAGE_LIST_MEMG) * sizeof(char *)); gf->ngarb = 0; } /* * order is important: it must match the token-constants declared as an * enum in the header file. */ char *operators_name[] = { " ", "\n", " ", "0000", "name", "bunch", "pragma", "context", "\"dummy string\"", "'dummy char'", "/", "/=", "-", "--", "-=", "->", "+", "++", "+=", "<", "<=", "<<", "<<=", ">", ">=", ">>", ">>=", "=", "==", #ifdef CAST_OP "=>", #endif "~", "!=", "&", "&&", "&=", "|", "||", "|=", "%", "%=", "*", "*=", "^", "^=", "!", "~=", "{", "}", "[", "]", "(", ")", ",", "?", ";", ":", ".", "...", "#", "##", " ", "ouch", "<:", ":>", "<%", "%>", "%:", "%:%:" }; /* the ascii representation of a token */ #ifdef SEMPER_FIDELIS #define tname(x) (ttWHI((x).type) ? " " : S_TOKEN((x).type) \ ? (x).name : operators_name[(x).type]) #else #define tname(x) (S_TOKEN((x).type) ? (x).name \ : operators_name[(x).type]) #endif char *token_name(struct token *t) { return tname(*t); } /* * To speed up deeply nested and repeated inclusions, we: * -- use a hash table to remember where we found each file * -- remember when the file is protected by a #ifndef/#define/#endif * construction; we can then avoid including several times a file * when this is not necessary. * -- remember in which directory, in the include path, the file was found. */ struct found_file { char *name; /* first field */ char *long_name; char *protect; int incdir; }; static struct HT *found_files = 0, *found_files_loc = 0; static struct found_file *new_found_file(void) { struct found_file *ff = getmem(sizeof(struct found_file)); ff->protect = 0; ff->incdir = -1; return ff; } static void del_found_file(void *m) { struct found_file *ff = (struct found_file *)m; freemem(ff->name); freemem(ff->long_name); if (ff->protect) freemem(ff->protect); } /* * To keep up with the #ifndef/#define/#endif protection mechanism * detection. */ struct protect protect_detect; static struct protect *protect_detect_stack = 0; /* * "current_filename" is used for error reporting, and the __FILE__ macro */ static void set_current_filename(char *x) { current_filename = x; } void set_init_filename(char *x, int real_file) { set_current_filename(sdup(x)); current_long_filename = 0; current_incdir = -1; if (real_file) { protect_detect.macro = 0; protect_detect.state = 1; protect_detect.ff = new_found_file(); protect_detect.ff->name = sdup(x); protect_detect.ff->long_name = sdup(x); putHT(found_files_loc, protect_detect.ff); } else { protect_detect.state = 0; } } static void init_found_files(void) { if (found_files) killHT(found_files); found_files = newHT(128, cmp_struct, hash_struct, del_found_file); if (found_files_loc) killHT(found_files_loc); found_files_loc = newHT(128, cmp_struct, hash_struct, del_found_file); } /* * convert a Unix-style path for the host architecture */ #if defined(MSDOS) || defined(ATARI) static char *convert_path(char *path) { /* on msdos systems, replace all / by \ */ char *c, *newp = sdup(path); for (c = newp; *c; c ++) if (*c == '/') *c = '\\'; return newp; } #elif defined AMIGA static char *convert_path(char *path) { char *newp = getmem(1 + strlen(path)); char *s = path, *d = newp; if (*s == '.') { /* convert "." to "" */ if (*(s+1) == '\0') s++; } while (*s) { if (*s == '.') { if (*(s+1) == '/') { s += 2; /* "./" is discarded */ continue; } else if (*(s+1) == '.') { if (*(s+2) == '/') s += 2; /* "../" is converted to "/" */ } } *d++ = *s++; } *d = '\0'; return newp; } #else /* no conversion */ static char *convert_path(char *path) { return sdup(path); } #endif /* * Set the lexer state at the beginning of a file. */ static void reinit_lexer_state(struct lexer_state *ls, int wb) { #ifndef NO_UCPP_BUF ls->input_buf = wb ? getmem(INPUT_BUF_MEMG) : 0; #ifdef UCPP_MMAP ls->from_mmap = 0; #endif #endif ls->ebuf = ls->pbuf = 0; ls->nlka = 0; ls->macfile = 0; ls->discard = 1; ls->last = 0; /* we suppose '\n' is not 0 */ ls->line = 1; ls->ltwnl = 1; ls->oline = 1; ls->pending_token = 0; ls->cli = 0; ls->copy_line[COPY_LINE_LENGTH - 1] = 0; ls->ifnest = 0; ls->condf[0] = ls->condf[1] = 0; } /* * Initialize the struct lexer_state, with optional input and output buffers. */ void init_buf_lexer_state(struct lexer_state *ls, int wb) { reinit_lexer_state(ls, wb); #ifndef NO_UCPP_BUF ls->output_buf = wb ? getmem(OUTPUT_BUF_MEMG) : 0; #endif ls->sbuf = 0; ls->ctok = getmem(sizeof(struct token)); ls->ctok->name = getmem(ls->tknl = TOKEN_NAME_MEMG); ls->pending_token = 0; ls->flags = 0; ls->count_trigraphs = 0; ls->gf = getmem(sizeof(struct garbage_fifo)); init_garbage_fifo(ls->gf); ls->condcomp = 1; ls->condnest = 0; #ifdef INMACRO_FLAG ls->inmacro = 0; ls->macro_count = 0; #endif } /* * Initialize the (complex) struct lexer_state. */ void init_lexer_state(struct lexer_state *ls) { init_buf_lexer_state(ls, 1); } /* * Restore what is needed from a lexer_state. This is used for #include. */ static void restore_lexer_state(struct lexer_state *ls, struct lexer_state *lsbak) { #ifndef NO_UCPP_BUF freemem(ls->input_buf); ls->input_buf = lsbak->input_buf; #ifdef UCPP_MMAP ls->from_mmap = lsbak->from_mmap; ls->input_buf_sav = lsbak->input_buf_sav; #endif #endif ls->input = lsbak->input; ls->ebuf = lsbak->ebuf; ls->pbuf = lsbak->pbuf; ls->nlka = lsbak->nlka; ls->macfile = lsbak->macfile; ls->discard = lsbak->discard; ls->line = lsbak->line; ls->oline = lsbak->oline; ls->ifnest = lsbak->ifnest; ls->condf[0] = lsbak->condf[0]; ls->condf[1] = lsbak->condf[1]; } /* * file_context (and the two functions push_ and pop_) are used to save * all that is needed when including a file. */ static struct file_context { struct lexer_state ls; char *name, *long_name; int incdir; } *ls_stack; static size_t ls_depth = 0; static void push_file_context(struct lexer_state *ls) { struct file_context fc; if (ls_depth > 1023) error(ls->line - 1, "too many nested includes"); fc.name = current_filename; fc.long_name = current_long_filename; fc.incdir = current_incdir; mmv(&(fc.ls), ls, sizeof(struct lexer_state)); aol(ls_stack, ls_depth, fc, LS_STACK_MEMG); ls_depth --; aol(protect_detect_stack, ls_depth, protect_detect, LS_STACK_MEMG); protect_detect.macro = 0; } static void pop_file_context(struct lexer_state *ls) { #ifdef AUDIT if (ls_depth <= 0) ouch("prepare to meet thy creator"); #endif restore_lexer_state(ls, &(ls_stack[-- ls_depth].ls)); if (protect_detect.macro) freemem(protect_detect.macro); protect_detect = protect_detect_stack[ls_depth]; set_current_filename(ls_stack[ls_depth].name); current_long_filename = ls_stack[ls_depth].long_name; current_incdir = ls_stack[ls_depth].incdir; } /* * report_context() returns the list of successive includers of the * current file, ending with a dummy entry with a negative line number. * The caller is responsible for freeing the returned pointer. */ struct stack_context *report_context(void) { struct stack_context *sc; size_t i; sc = getmem((ls_depth + 1) * sizeof(struct stack_context)); for (i = 0; i < ls_depth; i ++) { sc[i].name = ls_stack[ls_depth - i - 1].name; sc[i].long_name = ls_stack[ls_depth - i - 1].long_name; sc[i].line = ls_stack[ls_depth - i - 1].ls.line - 1; } sc[ls_depth].line = -1; return sc; } /* * init_lexer_mode() is used to end initialization of a struct lexer_state * if it must be used for a lexer */ void init_lexer_mode(struct lexer_state *ls) { ls->flags = DEFAULT_LEXER_FLAGS; ls->output_fifo = getmem(sizeof(struct token_fifo)); ls->output_fifo->art = ls->output_fifo->nt = 0; ls->toplevel_of = ls->output_fifo; ls->save_ctok = ls->ctok; } /* * release memory used by a struct lexer_state */ void free_lexer_state(struct lexer_state *ls) { #ifndef NO_UCPP_BUF if (ls->input_buf) freemem(ls->input_buf); if (ls->output_buf) freemem(ls->output_buf); #endif freemem(ls->ctok->name); freemem(ls->ctok); if (!(ls->flags & LEXER)) garbage_collect(ls->gf); freemem(ls->gf); } /* * Print line information. */ static void print_line_info(struct lexer_state *ls, unsigned long flags) { char *fn = current_long_filename ? current_long_filename : current_filename; char *b, *d; b = getmem(50 + strlen(fn)); if (flags & GCC_LINE_NUM) { sprintf(b, "# %ld \"%s\"\n", ls->line, fn); } else { sprintf(b, "#line %ld \"%s\"\n", ls->line, fn); } for (d = b; *d; d ++) put_char(ls, (unsigned char)(*d)); freemem(b); } /* * Enter a file; this implies the possible emission of a #line directive. * The flags used are passed as second parameter instead of being * extracted from the struct lexer_state. * * As a command-line option, gcc-like directives (with only a '#', * without 'line') may be produced. */ void enter_file(struct lexer_state *ls, unsigned long flags) { char *fn = current_long_filename ? current_long_filename : current_filename; if (!(flags & LINE_NUM)) return; if ((flags & LEXER) && !(flags & TEXT_OUTPUT)) { struct token t; t.type = CONTEXT;