/* * (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,...);void misra_neu(int, int, int, int, ...);int misra_is_reserved(const char*);#endif #include <stdio.h>#include <string.h>#include <stddef.h>#include <limits.h>#include <ctype.h>#include "ucppi.h"#include "mem.h"#include "hash.h"#include "tune.h" /*vb*/extern int nesting;#ifdef HAVE_MISRAextern int misracheck;#endif /* * we store macros in a hash table, and retrieve them using their name * as identifier. */static struct HT *macros = 0; static void del_macro(void *m){ struct macro *n = m; int i; if (n->name) freemem(n->name); for (i = 0; i < n->narg; i ++) freemem(n->arg[i]); if (n->narg > 0) freemem(n->arg);#ifdef LOW_MEM if (n->cval.length) freemem(n->cval.t);#else if (n->val.nt) { for (i = 0; i < n->val.nt; i ++) if (S_TOKEN(n->val.t[i].type)) freemem(n->val.t[i].name); freemem(n->val.t); }#endif freemem(n);} static inline struct macro *new_macro(void){ struct macro *m = getmem(sizeof(struct macro)); m->name = 0; m->narg = -1; m->nest = 0;#ifdef LOW_MEM m->cval.length = 0;#else m->val.nt = m->val.art = 0;#endif m->vaarg = 0; return m;} /* * for special macros, and the "defined" operator */enum { MAC_NONE, MAC_DEFINED, MAC_LINE, MAC_FILE, MAC_DATE, MAC_ADATE, MAC_TIME, MAC_STDC, MAC_PRAGMA};#define MAC_SPECIAL MAC_LINE /* * returns 1 for "defined" * returns x > 1 for a special macro such as __FILE__ * returns 0 otherwise */static inline int check_special_macro(char *name){ if (!strcmp(name, "defined")) return MAC_DEFINED; if (*name != '_') return MAC_NONE; if (*(name + 1) == 'P') { if (!strcmp(name, "_Pragma")) return MAC_PRAGMA; return MAC_NONE; } else if (*(name + 1) != '_') return MAC_NONE; if (no_special_macros) return MAC_NONE; if (!strcmp(name, "__LINE__")) return MAC_LINE; else if (!strcmp(name, "__FILE__")) return MAC_FILE; else if (!strcmp(name, "__DATE__")) return MAC_DATE; else if (!strcmp(name, "__AMIGADATE__")) return MAC_ADATE; else if (!strcmp(name, "__TIME__")) return MAC_TIME; else if (!strcmp(name, "__STDC__")) return MAC_STDC; return MAC_NONE;} int c99_compliant = 1;int c99_hosted = 1; /* * add the special macros to the macro table */static void add_special_macros(void){ struct macro *m; m = new_macro(); m->name = sdup("__LINE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__FILE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__DATE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__AMIGADATE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__TIME__"); putHT(macros, m); m = new_macro(); m->name = sdup("__STDC__"); putHT(macros, m); m = new_macro(); m->name = sdup("_Pragma"); m->narg = 1; m->arg = getmem(sizeof(char *)); m->arg[0] = sdup("foo"); putHT(macros, m); if (c99_compliant) {#ifndef LOW_MEM struct token t;#endif m = new_macro(); m->name = sdup("__STDC_VERSION__");#ifdef LOW_MEM m->cval.t = getmem(9); m->cval.t[0] = NUMBER; mmv(m->cval.t + 1, "199901L", 8); m->cval.length = 9;#else t.type = NUMBER; t.line = 0; t.name = sdup("199901L"); aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);#endif putHT(macros, m); } if (c99_hosted) {#ifndef LOW_MEM struct token t;#endif m = new_macro(); m->name = sdup("__STDC_HOSTED__");#ifdef LOW_MEM m->cval.t = getmem(3); m->cval.t[0] = NUMBER; mmv(m->cval.t + 1, "1", 2); m->cval.length = 3;#else t.type = NUMBER; t.line = 0; t.name = sdup("1"); aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG);#endif putHT(macros, m); }} /* * print the content of a macro, in #define form */static void print_macro(void *vm){ struct macro *m = vm; int x = check_special_macro(m->name); int i; if (x != MAC_NONE) { fprintf(emit_output, "/* #define %s */ /* special */\n", m->name); return; } fprintf(emit_output, "#define %s", m->name); if (m->narg >= 0) { fprintf(emit_output, "("); for (i = 0; i < m->narg; i ++) { fprintf(emit_output, i ? ", %s" : "%s", m->arg[i]); } if (m->vaarg) { fputs(m->narg ? ", ..." : "...", emit_output); } fprintf(emit_output, ")"); }#ifdef LOW_MEM if (m->cval.length == 0) { fputc('\n', emit_output); return; } fputc(' ', emit_output); for (i = 0; i < m->cval.length;) { int tt = m->cval.t[i ++]; if (tt == MACROARG) { if (m->cval.t[i] == m->narg) fputs("__VA_ARGS__", emit_output); else fputs(m->arg[(size_t)(m->cval.t[i])], emit_output); i ++; } else if (S_TOKEN(tt)) { fputs((char *)(m->cval.t + i), emit_output); i += 1 + strlen((char *)(m->cval.t + i)); } else fputs(operators_name[tt], emit_output); }#else if (m->val.nt == 0) { fputc('\n', emit_output); return; } fputc(' ', emit_output); for (i = 0; i < m->val.nt; i ++) { if (m->val.t[i].type == MACROARG) { if (m->val.t[i].line == m->narg) fputs("__VA_ARGS__", emit_output); else fputs(m->arg[(size_t)(m->val.t[i].line)], emit_output); } else fputs(token_name(m->val.t + i), emit_output); }#endif fputc('\n', emit_output);} /* * Send a token to the output (a token_fifo in lexer mode, the output * buffer in stand alone mode). */void print_token(struct lexer_state *ls, struct token *t, long uz_line){ char *x = t->name; if (uz_line && t->line < 0) t->line = uz_line; if (ls->flags & LEXER) { struct token at; at = *t; if (S_TOKEN(t->type)) { at.name = sdup(at.name); throw_away(ls->gf, at.name); } aol(ls->output_fifo->t, ls->output_fifo->nt, at, TOKEN_LIST_MEMG); return; } if (ls->flags & KEEP_OUTPUT) { for (; ls->oline < ls->line;) put_char(ls, '\n'); } if (!S_TOKEN(t->type)) x = operators_name[t->type]; for (; *x; x ++) put_char(ls, *x);} /* * send a reduced whitespace token to the output */#define print_space(ls) do { \ struct token lt; \ lt.type = OPT_NONE; \ lt.line = (ls)->line; \ print_token((ls), <, 0); \ } while (0) /* * We found a #define directive; parse the end of the line, perform * sanity checks, store the new macro into the "macros" hash table. * * In case of a redefinition of a macro: we enforce the rule that a * macro should be redefined identically, including the spelling of * parameters. We emit an error on offending code; dura lex, sed lex. * After all, it is easy to avoid such problems, with a #undef directive. */int handle_define(struct lexer_state *ls){ struct macro *m, *n;#ifdef LOW_MEM struct token_fifo mv;#endif int ltwws = 1, redef = 0; char *mname = 0; int narg; size_t nt; long l = ls->line; /*vb*/#ifdef HAVE_MISRA if(nesting!=0) misra_neu(91,19,5,0);#endif /* find the next non-white token on the line, this should be the macro name */ while (!next_token(ls) && ls->ctok->type != NEWLINE) { if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type == NAME) mname = sdup(ls->ctok->name); break; } if (mname == 0) { error(l, "missing macro name"); return 1; } if (check_special_macro(mname)) { error(l, "trying to redefine the special macro %s", mname); goto warp_error; } /* * If a macro with this name was already defined: the K&R * states that the new macro should be identical to the old one * (with some arcane rule of equivalence of whitespace); otherwise, * redefining the macro is an error. Most preprocessors would * only emit a warning (or nothing at all) on an unidentical * redefinition. * * Since it is easy to avoid this error (with a #undef directive), * we choose to enforce the rule and emit an error. */ #ifdef HAVE_MISRA if (misra_is_reserved(mname)) misra_neu(114,20,1,-1);#endif if ((n = getHT(macros, &mname)) != 0) { /* redefinition of a macro: we must check that we define it identical */ redef = 1;#ifdef LOW_MEM n->cval.rp = 0;#endif freemem(mname); } if (!redef) { m = new_macro(); m->name = mname; m->narg = -1;#ifdef LOW_MEM mv.art = mv.nt = 0;#define mval mv#else#define mval (m->val)#endif } if (next_token(ls)) goto define_end; /* * Check if the token immediately following the macro name is * a left parenthesis; if so, then this is a macro with arguments. * Collect their names and try to match the next parenthesis. */ if (ls->ctok->type == LPAR) { int i, j; int need_comma = 0, saw_mdots = 0; narg = 0; while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) { error(l, "truncated macro definition"); return 1; } if (ls->ctok->type == COMMA) { if (saw_mdots) { error(l, "'...' must end the macro " "argument list"); goto warp_error; } if (!need_comma) { error(l, "void macro argument"); goto warp_error; } need_comma = 0; continue; } else if (ls->ctok->type == NAME) { if (saw_mdots) { error(l, "'...' must end the macro " "argument list"); goto warp_error; } if (need_comma) { error(l, "missing comma in " "macro argument list"); goto warp_error; } if (!redef) { aol(m->arg, narg, sdup(ls->ctok->name), 8); if (narg == 128 && (ls->flags & WARN_STANDARD)) warning(l, "more arguments to " "macro than the ISO " "limit (127)");#ifdef LOW_MEM if (narg == 254) { error(l, "too many arguments " "in macro definition " "(max 253)"); goto warp_error; }#endif } else { /* this is a redefinition of the macro; check equality between old and new definitions */ if (narg >= n->narg) goto redef_error; if (strcmp(ls->ctok->name, n->arg[narg ++])) goto redef_error; } need_comma = 1; continue; } else if ((ls->flags & MACRO_VAARG) && ls->ctok->type == MDOTS) { if (need_comma) { error(l, "missing comma before '...'"); goto warp_error; } if (redef && !n->vaarg) goto redef_error; if (!redef) m->vaarg = 1; saw_mdots = 1; need_comma = 1; continue; } else if (ls->ctok->type == RPAR) { if (narg > 0 && !need_comma) { error(l, "void macro argument"); goto warp_error; } if (redef && n->vaarg && !saw_mdots) goto redef_error; break; } else if (ttMWS(ls->ctok->type)) { continue; } error(l, "invalid macro argument"); goto warp_error; } if (!redef) { for (i = 1; i < narg; i ++) for (j = 0; j < i; j ++) if (!strcmp(m->arg[i], m->arg[j])) { error(l, "duplicate macro " "argument"); goto warp_error; } } if (!redef) m->narg = narg; } else { if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) warning(ls->line, "identifier not followed by " "whitespace in #define"); ls->flags |= READ_AGAIN; narg = 0; } if (redef) nt = 0; /* now, we have the arguments. Let's get the macro contents. */ while (!next_token(ls) && ls->ctok->type != NEWLINE) { struct token t; t.type = ls->ctok->type; if (ltwws && ttMWS(t.type)) continue; t.line = 0; if (t.type == NAME) { int i; if ((ls->flags & MACRO_VAARG) && !strcmp(ls->ctok->name, "__VA_ARGS__")) { if (redef) { if (!n->vaarg) goto redef_error; } else if (!m->vaarg) { error(l, "'__VA_ARGS__' is forbidden " "in macros with a fixed " "number of arguments"); goto warp_error; } t.type = MACROARG; t.line = redef ? n->narg : m->narg;Lines 1–500 of 1870. Load more
/* * (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,...); void misra_neu(int, int, int, int, ...); int misra_is_reserved(const char*); #endif #include <stdio.h> #include <string.h> #include <stddef.h> #include <limits.h> #include <ctype.h> #include "ucppi.h" #include "mem.h" #include "hash.h" #include "tune.h" /*vb*/ extern int nesting; #ifdef HAVE_MISRA extern int misracheck; #endif /* * we store macros in a hash table, and retrieve them using their name * as identifier. */ static struct HT *macros = 0; static void del_macro(void *m) { struct macro *n = m; int i; if (n->name) freemem(n->name); for (i = 0; i < n->narg; i ++) freemem(n->arg[i]); if (n->narg > 0) freemem(n->arg); #ifdef LOW_MEM if (n->cval.length) freemem(n->cval.t); #else if (n->val.nt) { for (i = 0; i < n->val.nt; i ++) if (S_TOKEN(n->val.t[i].type)) freemem(n->val.t[i].name); freemem(n->val.t); } #endif freemem(n); } static inline struct macro *new_macro(void) { struct macro *m = getmem(sizeof(struct macro)); m->name = 0; m->narg = -1; m->nest = 0; #ifdef LOW_MEM m->cval.length = 0; #else m->val.nt = m->val.art = 0; #endif m->vaarg = 0; return m; } /* * for special macros, and the "defined" operator */ enum { MAC_NONE, MAC_DEFINED, MAC_LINE, MAC_FILE, MAC_DATE, MAC_ADATE, MAC_TIME, MAC_STDC, MAC_PRAGMA }; #define MAC_SPECIAL MAC_LINE /* * returns 1 for "defined" * returns x > 1 for a special macro such as __FILE__ * returns 0 otherwise */ static inline int check_special_macro(char *name) { if (!strcmp(name, "defined")) return MAC_DEFINED; if (*name != '_') return MAC_NONE; if (*(name + 1) == 'P') { if (!strcmp(name, "_Pragma")) return MAC_PRAGMA; return MAC_NONE; } else if (*(name + 1) != '_') return MAC_NONE; if (no_special_macros) return MAC_NONE; if (!strcmp(name, "__LINE__")) return MAC_LINE; else if (!strcmp(name, "__FILE__")) return MAC_FILE; else if (!strcmp(name, "__DATE__")) return MAC_DATE; else if (!strcmp(name, "__AMIGADATE__")) return MAC_ADATE; else if (!strcmp(name, "__TIME__")) return MAC_TIME; else if (!strcmp(name, "__STDC__")) return MAC_STDC; return MAC_NONE; } int c99_compliant = 1; int c99_hosted = 1; /* * add the special macros to the macro table */ static void add_special_macros(void) { struct macro *m; m = new_macro(); m->name = sdup("__LINE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__FILE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__DATE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__AMIGADATE__"); putHT(macros, m); m = new_macro(); m->name = sdup("__TIME__"); putHT(macros, m); m = new_macro(); m->name = sdup("__STDC__"); putHT(macros, m); m = new_macro(); m->name = sdup("_Pragma"); m->narg = 1; m->arg = getmem(sizeof(char *)); m->arg[0] = sdup("foo"); putHT(macros, m); if (c99_compliant) { #ifndef LOW_MEM struct token t; #endif m = new_macro(); m->name = sdup("__STDC_VERSION__"); #ifdef LOW_MEM m->cval.t = getmem(9); m->cval.t[0] = NUMBER; mmv(m->cval.t + 1, "199901L", 8); m->cval.length = 9; #else t.type = NUMBER; t.line = 0; t.name = sdup("199901L"); aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG); #endif putHT(macros, m); } if (c99_hosted) { #ifndef LOW_MEM struct token t; #endif m = new_macro(); m->name = sdup("__STDC_HOSTED__"); #ifdef LOW_MEM m->cval.t = getmem(3); m->cval.t[0] = NUMBER; mmv(m->cval.t + 1, "1", 2); m->cval.length = 3; #else t.type = NUMBER; t.line = 0; t.name = sdup("1"); aol(m->val.t, m->val.nt, t, TOKEN_LIST_MEMG); #endif putHT(macros, m); } } /* * print the content of a macro, in #define form */ static void print_macro(void *vm) { struct macro *m = vm; int x = check_special_macro(m->name); int i; if (x != MAC_NONE) { fprintf(emit_output, "/* #define %s */ /* special */\n", m->name); return; } fprintf(emit_output, "#define %s", m->name); if (m->narg >= 0) { fprintf(emit_output, "("); for (i = 0; i < m->narg; i ++) { fprintf(emit_output, i ? ", %s" : "%s", m->arg[i]); } if (m->vaarg) { fputs(m->narg ? ", ..." : "...", emit_output); } fprintf(emit_output, ")"); } #ifdef LOW_MEM if (m->cval.length == 0) { fputc('\n', emit_output); return; } fputc(' ', emit_output); for (i = 0; i < m->cval.length;) { int tt = m->cval.t[i ++]; if (tt == MACROARG) { if (m->cval.t[i] == m->narg) fputs("__VA_ARGS__", emit_output); else fputs(m->arg[(size_t)(m->cval.t[i])], emit_output); i ++; } else if (S_TOKEN(tt)) { fputs((char *)(m->cval.t + i), emit_output); i += 1 + strlen((char *)(m->cval.t + i)); } else fputs(operators_name[tt], emit_output); } #else if (m->val.nt == 0) { fputc('\n', emit_output); return; } fputc(' ', emit_output); for (i = 0; i < m->val.nt; i ++) { if (m->val.t[i].type == MACROARG) { if (m->val.t[i].line == m->narg) fputs("__VA_ARGS__", emit_output); else fputs(m->arg[(size_t)(m->val.t[i].line)], emit_output); } else fputs(token_name(m->val.t + i), emit_output); } #endif fputc('\n', emit_output); } /* * Send a token to the output (a token_fifo in lexer mode, the output * buffer in stand alone mode). */ void print_token(struct lexer_state *ls, struct token *t, long uz_line) { char *x = t->name; if (uz_line && t->line < 0) t->line = uz_line; if (ls->flags & LEXER) { struct token at; at = *t; if (S_TOKEN(t->type)) { at.name = sdup(at.name); throw_away(ls->gf, at.name); } aol(ls->output_fifo->t, ls->output_fifo->nt, at, TOKEN_LIST_MEMG); return; } if (ls->flags & KEEP_OUTPUT) { for (; ls->oline < ls->line;) put_char(ls, '\n'); } if (!S_TOKEN(t->type)) x = operators_name[t->type]; for (; *x; x ++) put_char(ls, *x); } /* * send a reduced whitespace token to the output */ #define print_space(ls) do { \ struct token lt; \ lt.type = OPT_NONE; \ lt.line = (ls)->line; \ print_token((ls), <, 0); \ } while (0) /* * We found a #define directive; parse the end of the line, perform * sanity checks, store the new macro into the "macros" hash table. * * In case of a redefinition of a macro: we enforce the rule that a * macro should be redefined identically, including the spelling of * parameters. We emit an error on offending code; dura lex, sed lex. * After all, it is easy to avoid such problems, with a #undef directive. */ int handle_define(struct lexer_state *ls) { struct macro *m, *n; #ifdef LOW_MEM struct token_fifo mv; #endif int ltwws = 1, redef = 0; char *mname = 0; int narg; size_t nt; long l = ls->line; /*vb*/ #ifdef HAVE_MISRA if(nesting!=0) misra_neu(91,19,5,0); #endif /* find the next non-white token on the line, this should be the macro name */ while (!next_token(ls) && ls->ctok->type != NEWLINE) { if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type == NAME) mname = sdup(ls->ctok->name); break; } if (mname == 0) { error(l, "missing macro name"); return 1; } if (check_special_macro(mname)) { error(l, "trying to redefine the special macro %s", mname); goto warp_error; } /* * If a macro with this name was already defined: the K&R * states that the new macro should be identical to the old one * (with some arcane rule of equivalence of whitespace); otherwise, * redefining the macro is an error. Most preprocessors would * only emit a warning (or nothing at all) on an unidentical * redefinition. * * Since it is easy to avoid this error (with a #undef directive), * we choose to enforce the rule and emit an error. */ #ifdef HAVE_MISRA if (misra_is_reserved(mname)) misra_neu(114,20,1,-1); #endif if ((n = getHT(macros, &mname)) != 0) { /* redefinition of a macro: we must check that we define it identical */ redef = 1; #ifdef LOW_MEM n->cval.rp = 0; #endif freemem(mname); } if (!redef) { m = new_macro(); m->name = mname; m->narg = -1; #ifdef LOW_MEM mv.art = mv.nt = 0; #define mval mv #else #define mval (m->val) #endif } if (next_token(ls)) goto define_end; /* * Check if the token immediately following the macro name is * a left parenthesis; if so, then this is a macro with arguments. * Collect their names and try to match the next parenthesis. */ if (ls->ctok->type == LPAR) { int i, j; int need_comma = 0, saw_mdots = 0; narg = 0; while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) { error(l, "truncated macro definition"); return 1; } if (ls->ctok->type == COMMA) { if (saw_mdots) { error(l, "'...' must end the macro " "argument list"); goto warp_error; } if (!need_comma) { error(l, "void macro argument"); goto warp_error; } need_comma = 0; continue; } else if (ls->ctok->type == NAME) { if (saw_mdots) { error(l, "'...' must end the macro " "argument list"); goto warp_error; } if (need_comma) { error(l, "missing comma in " "macro argument list"); goto warp_error; } if (!redef) { aol(m->arg, narg, sdup(ls->ctok->name), 8); if (narg == 128 && (ls->flags & WARN_STANDARD)) warning(l, "more arguments to " "macro than the ISO " "limit (127)"); #ifdef LOW_MEM if (narg == 254) { error(l, "too many arguments " "in macro definition " "(max 253)"); goto warp_error; } #endif } else { /* this is a redefinition of the macro; check equality between old and new definitions */ if (narg >= n->narg) goto redef_error; if (strcmp(ls->ctok->name, n->arg[narg ++])) goto redef_error; } need_comma = 1; continue; } else if ((ls->flags & MACRO_VAARG) && ls->ctok->type == MDOTS) { if (need_comma) { error(l, "missing comma before '...'"); goto warp_error; } if (redef && !n->vaarg) goto redef_error; if (!redef) m->vaarg = 1; saw_mdots = 1; need_comma = 1; continue; } else if (ls->ctok->type == RPAR) { if (narg > 0 && !need_comma) { error(l, "void macro argument"); goto warp_error; } if (redef && n->vaarg && !saw_mdots) goto redef_error; break; } else if (ttMWS(ls->ctok->type)) { continue; } error(l, "invalid macro argument"); goto warp_error; } if (!redef) { for (i = 1; i < narg; i ++) for (j = 0; j < i; j ++) if (!strcmp(m->arg[i], m->arg[j])) { error(l, "duplicate macro " "argument"); goto warp_error; } } if (!redef) m->narg = narg; } else { if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) warning(ls->line, "identifier not followed by " "whitespace in #define"); ls->flags |= READ_AGAIN; narg = 0; } if (redef) nt = 0; /* now, we have the arguments. Let's get the macro contents. */ while (!next_token(ls) && ls->ctok->type != NEWLINE) { struct token t; t.type = ls->ctok->type; if (ltwws && ttMWS(t.type)) continue; t.line = 0; if (t.type == NAME) { int i; if ((ls->flags & MACRO_VAARG) && !strcmp(ls->ctok->name, "__VA_ARGS__")) { if (redef) { if (!n->vaarg) goto redef_error; } else if (!m->vaarg) { error(l, "'__VA_ARGS__' is forbidden " "in macros with a fixed " "number of arguments"); goto warp_error; } t.type = MACROARG; t.line = redef ? n->narg : m->narg;