Annotation of OpenXM_contrib2/windows/mcpp/expand.c, Revision 1.1
1.1 ! ohara 1: /* $OpenXM$ */
! 2: /*-
! 3: * Copyright (c) 1998, 2002-2008 Kiyoshi Matsui <kmatsui@t3.rim.or.jp>
! 4: * All rights reserved.
! 5: *
! 6: * Some parts of this code are derived from the public domain software
! 7: * DECUS cpp (1984,1985) written by Martin Minow.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
! 19: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 20: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 21: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
! 22: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 23: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 24: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 25: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 26: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 27: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 28: * SUCH DAMAGE.
! 29: */
! 30:
! 31: /*
! 32: * E X P A N D . C
! 33: * M a c r o E x p a n s i o n
! 34: *
! 35: * The macro expansion routines are placed here.
! 36: */
! 37:
! 38: #if PREPROCESSED
! 39: #include "mcpp.H"
! 40: #else
! 41: #include "system.H"
! 42: #include "internal.H"
! 43: #endif
! 44:
! 45: #define ARG_ERROR (-255)
! 46: #define CERROR 1
! 47: #define CWARN 2
! 48:
! 49: typedef struct location { /* Where macro or arg locate */
! 50: long start_line; /* Beginning at 1 */
! 51: size_t start_col; /* Beginning at 0 */
! 52: long end_line;
! 53: size_t end_col;
! 54: } LOCATION;
! 55: typedef struct magic_seq { /* Data of a sequence inserted between tokens */
! 56: char * magic_start; /* First MAC_INF sequence */
! 57: char * magic_end; /* End of last MAC_INF seq */
! 58: int space; /* Space succeeds or not */
! 59: } MAGIC_SEQ;
! 60:
! 61: static int compat_mode;
! 62: /* Expand recursive macro more than Standard (for compatibility with GNUC) */
! 63: #if COMPILER == GNUC
! 64: static int ansi; /* __STRICT_ANSI__ flag */
! 65: #endif
! 66:
! 67: static char * expand_std( DEFBUF * defp, char * out, char * out_end
! 68: , LINE_COL line_col, int * pragma_op);
! 69: /* Expand a macro completely (for Standard modes) */
! 70: static char * expand_prestd( DEFBUF * defp, char * out, char * out_end
! 71: , LINE_COL line_col, int * pragma_op);
! 72: /* Expand a macro completely (for pre-Standard modes) */
! 73: static DEFBUF * is_macro_call( DEFBUF * defp, char ** cp, char ** endf
! 74: , MAGIC_SEQ * mgc_seq); /* Is this really a macro call ? */
! 75: static int collect_args( const DEFBUF * defp, char ** arglist, int m_num);
! 76: /* Collect arguments of a macro call*/
! 77: static int get_an_arg( int c, char ** argpp, char * arg_end
! 78: , char ** seqp, int var_arg, int nargs, LOCATION ** locp, int m_num
! 79: , MAGIC_SEQ * mgc_prefix); /* Get an argument */
! 80: static int squeeze_ws( char ** out, char ** endf, MAGIC_SEQ * mgc_seq);
! 81: /* Squeeze white spaces to a space */
! 82: static void skip_macro( void);
! 83: /* Skip the rest of macro call */
! 84: static void diag_macro( int severity, const char * format
! 85: , const char * arg1, long arg2, const char * arg3, const DEFBUF * defp1
! 86: , const DEFBUF * defp2) ;
! 87: /* Supplement diagnostic information*/
! 88: static void dump_args( const char * why, int nargs, const char ** arglist);
! 89: /* Dump arguments list */
! 90:
! 91: static int rescan_level; /* Times of macro rescan */
! 92:
! 93: static const char * const macbuf_overflow
! 94: = "Buffer overflow expanding macro \"%s\" at %.0ld\"%s\""; /* _E_ */
! 95: static const char * const empty_arg
! 96: = "Empty argument in macro call \"%s\""; /* _W2_ */
! 97: static const char * const unterm_macro
! 98: = "Unterminated macro call \"%s\""; /* _E_ */
! 99: static const char * const narg_error
! 100: = "%s than necessary %ld argument(s) in macro call \"%s\""; /* _E_ _W1_ */
! 101: static const char * const only_name
! 102: = "Macro \"%s\" needs arguments"; /* _W8_ */
! 103:
! 104: void expand_init(
! 105: int compat, /* "Compatible" to GNUC expansion of recursive macro*/
! 106: int strict_ansi /* __STRICT_ANSI__ flag for GNUC */
! 107: )
! 108: /* Set expand_macro() function */
! 109: {
! 110: expand_macro = standard ? expand_std : expand_prestd;
! 111: compat_mode = compat;
! 112: #if COMPILER == GNUC
! 113: ansi = strict_ansi;
! 114: #endif
! 115: }
! 116:
! 117: DEFBUF * is_macro(
! 118: char ** cp
! 119: )
! 120: /*
! 121: * The name is already in 'identifier', the next token is not yet read.
! 122: * Return the definition info if the name is a macro call, else return NULL.
! 123: */
! 124: {
! 125: DEFBUF * defp;
! 126:
! 127: if ((defp = look_id( identifier)) != NULL) /* Is a macro name */
! 128: return is_macro_call( defp, cp, NULL, NULL);
! 129: else
! 130: return NULL;
! 131: }
! 132:
! 133: static DEFBUF * is_macro_call(
! 134: DEFBUF * defp,
! 135: char ** cp, /* Pointer to output buffer */
! 136: char ** endf, /* Pointer to indicate end of infile buffer */
! 137: MAGIC_SEQ * mgc_seq /* Infs on MAC_INF sequences and space */
! 138: )
! 139: /*
! 140: * Return DEFBUF if the defp->name is a macro call, else return NULL.
! 141: */
! 142: {
! 143: int c;
! 144:
! 145: if (defp->nargs >= 0 /* Function-like macro */
! 146: || defp->nargs == DEF_PRAGMA) { /* _Pragma() pseudo-macro */
! 147: c = squeeze_ws( cp, endf, mgc_seq); /* See the next char. */
! 148: if (c == CHAR_EOF) /* End of file */
! 149: unget_string( "\n", NULL); /* Restore skipped '\n' */
! 150: else if (! standard || c != RT_END)
! 151: /* Still in the file and rescan boundary ? */
! 152: unget_ch(); /* To see it again */
! 153: if (c != '(') { /* Only the name of function-like macro */
! 154: if (! standard && warn_level & 8)
! 155: cwarn( only_name, defp->name, 0L, NULL);
! 156: return NULL;
! 157: }
! 158: }
! 159: return defp; /* Really a macro call */
! 160: }
! 161:
! 162: /*
! 163: * expand_macro() expands a macro call completely, and writes out the result
! 164: * to the specified output buffer and returns the advanced pointer.
! 165: */
! 166:
! 167:
! 168: /*
! 169: * T h e S T A N D A R D C o n f o r m i n g M o d e
! 170: * o f M a c r o E x p a n s i o n
! 171: *
! 172: * 1998/08 First released. kmatsui
! 173: */
! 174:
! 175: /* For debug of -K option: should be turned off on release version. */
! 176: #define DEBUG_MACRO_ANN FALSE
! 177:
! 178: /* Return value of is_able_repl() */
! 179: #define NO 0 /* "Blue-painted" */
! 180: #define YES 1 /* Not blue-painted */
! 181: #define READ_OVER 2
! 182: /* Still "blue-painted", yet has read over repl-list */
! 183:
! 184: /*
! 185: * Macros related to macro notification mode.
! 186: * The macro notification routines are hacks on the normal processing
! 187: * routines, and very complicated and cumbersome. Be sure to keep symmetry
! 188: * of starting and closing magic sequences. Enable the routines enclosed
! 189: * by #if 0 - #endif for debugging.
! 190: * Any byte in the sequences beginning with MAC_INF can coincide with any
! 191: * other character. Hence, the data stream should be read from the top,
! 192: * not from the tail, in principle.
! 193: */
! 194: /* Length of sequence of MAC_INF, MAC_CALL_START, mac_num-1, mac_num-2 */
! 195: #define MAC_S_LEN 4
! 196: /* Length of sequence of MAC_INF, MAC_ARG_START, mac_num1, mac_num2, arg-num*/
! 197: #define ARG_S_LEN 5
! 198: #define MAC_E_LEN 2 /* Length of MAC_INF, MAC_CALL_END sequence */
! 199: #define ARG_E_LEN MAC_E_LEN /* Lenght of MAC_INF, MAC_ARG_END sequence */
! 200: #define MAC_E_LEN_V 4 /* Length of macro closing sequence in verbose mode */
! 201: /* MAC_INF, MAC_CALL_END, mac_num1, mac_num2 */
! 202: #define ARG_E_LEN_V 5 /* Length of argument closing sequence in verbose */
! 203: /* MAC_INF, MAC_ARG_END, mac_num1, mac_num2, arg_num */
! 204: #define IN_SRC_LEN 3 /* Length of sequence of IN_SRC, num-1, num-2 */
! 205: #define INIT_MAC_INF 0x100 /* Initial num of elements in mac_inf[] */
! 206: #define MAX_MAC_INF 0x1000 /* Maximum num of elements in mac_inf[] */
! 207: #define INIT_IN_SRC_NUM 0x100 /* Initial num of elements in in_src[] */
! 208: #define MAX_IN_SRC_NUM 0x1000 /* Maximum num of elements in in_src[] */
! 209:
! 210: /* Variables for macro notification mode */
! 211: typedef struct macro_inf { /* Informations of a macro */
! 212: const DEFBUF * defp; /* Definition of the macro */
! 213: char * args; /* Arguments, if any */
! 214: int num_args; /* Number of real arguments */
! 215: int recur; /* Recurrence of this macro */
! 216: LOCATION locs; /* Location of macro call */
! 217: LOCATION * loc_args; /* Location of arguments */
! 218: } MACRO_INF;
! 219: static MACRO_INF * mac_inf;
! 220: static int max_mac_num; /* Current num of elements in mac_inf[] */
! 221: static int mac_num; /* Index into mac_inf[] */
! 222: static LOCATION * in_src; /* Location of identifiers in macro arguments */
! 223: static int max_in_src_num; /* Current num of elements in in_src[] */
! 224: static int in_src_num; /* Index into in_src[] */
! 225: static int trace_macro; /* Enable to trace macro infs */
! 226:
! 227: static struct {
! 228: const DEFBUF * def; /* Macro definition */
! 229: int read_over; /* Has read over repl-list */
! 230: /* 'read_over' is never used in POST_STD mode and in compat_mode*/
! 231: } replacing[ RESCAN_LIMIT]; /* Macros currently replacing */
! 232: static int has_pragma = FALSE; /* Flag of _Pragma() operator */
! 233:
! 234: static int print_macro_inf( int c, char ** cpp, char ** opp);
! 235: /* Embed macro infs into comments */
! 236: static char * print_macro_arg( char *out, MACRO_INF * m_inf, int argn
! 237: , int real_arg, int start);
! 238: /* Embed macro arg inf into comments*/
! 239: static char * chk_magic_balance( char * buf, char * buf_end, int move
! 240: , int diag); /* Check imbalance of magics */
! 241: static char * replace( DEFBUF * defp, char * out, char * out_end
! 242: , const DEFBUF * outer, FILEINFO * rt_file, LINE_COL line_col
! 243: , int in_src_n);
! 244: /* Replace a macro recursively */
! 245: static char * close_macro_inf( char * out_p, int m_num, int in_src_n);
! 246: /* Put closing mark for a macro call*/
! 247: static DEFBUF * def_special( DEFBUF * defp);
! 248: /* Re-define __LINE__, __FILE__ */
! 249: static int prescan( const DEFBUF * defp, const char ** arglist
! 250: , char * out, char * out_end);
! 251: /* Process #, ## operator */
! 252: static char * catenate( const DEFBUF * defp, const char ** arglist
! 253: , char * out, char * out_end, char ** token_p);
! 254: /* Catenate tokens */
! 255: static const char * remove_magics( const char * argp, int from_last);
! 256: /* Remove pair of magic characters */
! 257: #if DEBUG_MACRO_ANN
! 258: static void chk_symmetry( char * start_id, char * end_id, size_t len);
! 259: /* Check if a pair of magics are symmetrical */
! 260: #endif
! 261: static char * stringize( const DEFBUF * defp, const char * argp, char * out);
! 262: /* Stringize an argument */
! 263: static char * substitute( const DEFBUF * defp, const char ** arglist
! 264: , const char * in, char * out, char * out_end);
! 265: /* Substitute parms with arguments */
! 266: static char * rescan( const DEFBUF * outer, const char * in, char * out
! 267: , char * out_end);
! 268: /* Rescan once replaced sequences */
! 269: static int disable_repl( const DEFBUF * defp);
! 270: /* Disable the macro once replaced */
! 271: static void enable_repl( const DEFBUF * defp, int done);
! 272: /* Enable the macro for later use */
! 273: static int is_able_repl( const DEFBUF * defp);
! 274: /* Is the macro allowed to replace? */
! 275: static char * insert_to_bptr( char * ins, size_t len);
! 276: /* Insert a sequence into infile->bptr */
! 277:
! 278: static char * expand_std(
! 279: DEFBUF * defp, /* Macro definition */
! 280: char * out, /* Output buffer */
! 281: char * out_end, /* End of output buffer */
! 282: LINE_COL line_col, /* Location of macro */
! 283: int * pragma_op /* _Pragma() is found ? */
! 284: )
! 285: /*
! 286: * Expand a macro call completely, write the results to the specified buffer
! 287: * and return the advanced output pointer.
! 288: */
! 289: {
! 290: char macrobuf[ NMACWORK + IDMAX]; /* Buffer for replace() */
! 291: char * out_p = out;
! 292: size_t len;
! 293: int c, c1;
! 294: char * cp;
! 295:
! 296: has_pragma = FALSE; /* Have to re-initialize*/
! 297: macro_line = src_line; /* Line number for diag */
! 298: macro_name = defp->name;
! 299: rescan_level = 0;
! 300: trace_macro = (mcpp_mode == STD) && (mcpp_debug & MACRO_CALL)
! 301: && ! in_directive;
! 302: if (trace_macro) {
! 303: max_mac_num = INIT_MAC_INF;
! 304: mac_inf = (MACRO_INF *) xmalloc( sizeof (MACRO_INF) * max_mac_num);
! 305: memset( mac_inf, 0, sizeof (MACRO_INF) * max_mac_num);
! 306: max_in_src_num = INIT_IN_SRC_NUM;
! 307: in_src = (LOCATION *) xmalloc( sizeof (LOCATION) * max_in_src_num);
! 308: memset( in_src, 0, sizeof (LOCATION) * max_in_src_num);
! 309: mac_num = in_src_num = 0; /* Initialize */
! 310: }
! 311: if (replace( defp, macrobuf, macrobuf + NMACWORK, NULL, infile, line_col
! 312: , 0) == NULL) { /* Illegal macro call */
! 313: skip_macro();
! 314: macro_line = MACRO_ERROR;
! 315: goto exp_end;
! 316: }
! 317: len = (size_t) (out_end - out);
! 318: if (strlen( macrobuf) > len) {
! 319: cerror( macbuf_overflow, macro_name, 0, macrobuf);
! 320: memcpy( out, macrobuf, len);
! 321: out_p = out + len;
! 322: macro_line = MACRO_ERROR;
! 323: goto exp_end;
! 324: }
! 325:
! 326: #if DEBUG_MACRO_ANN
! 327: chk_magic_balance( macrobuf, macrobuf + strlen( macrobuf), FALSE, TRUE);
! 328: #endif
! 329: cp = macrobuf;
! 330: c1 = '\0'; /* The char previous to 'c' */
! 331: while ((c = *cp++) != EOS) {
! 332: if (c == DEF_MAGIC)
! 333: continue; /* Skip DEF_MAGIC */
! 334: if (mcpp_mode == STD) {
! 335: if (c == IN_SRC) { /* Skip IN_SRC */
! 336: if (trace_macro)
! 337: cp += 2; /* Skip also the number (coded in 2 bytes) */
! 338: continue;
! 339: } else if (c == TOK_SEP) {
! 340: /* Remove redundant token separator */
! 341: if ((char_type[ c1 & UCHARMAX] & HSP)
! 342: || (char_type[ *cp & UCHARMAX] & HSP)
! 343: || in_include || option_flags.lang_asm
! 344: || (*cp == MAC_INF && *(cp + 1) == MAC_CALL_END)
! 345: || (!option_flags.v && c1 == MAC_CALL_END)
! 346: || (option_flags.v
! 347: && *(cp - MAC_E_LEN_V - 1) == MAC_INF
! 348: && *(cp - MAC_E_LEN_V) == MAC_CALL_END))
! 349: continue;
! 350: /* Skip separator just after ' ', '\t' */
! 351: /* and just after MAC_CALL_END. */
! 352: /* Also skip this in lang_asm mode, #include */
! 353: /* Skip just before another TOK_SEP, ' ', '\t' */
! 354: /* Skip just before MAC_INF,MAC_CALL_END seq too*/
! 355: else
! 356: c = ' '; /* Else convert to ' ' */
! 357: } else if (trace_macro && (c == MAC_INF)) {
! 358: /* Embed macro expansion informations into comments */
! 359: c = *cp++;
! 360: c1 = print_macro_inf( c, &cp, &out_p);
! 361: if (out_end <= out_p) {
! 362: cerror( macbuf_overflow, macro_name, 0, out);
! 363: macro_line = MACRO_ERROR;
! 364: goto exp_end;
! 365: }
! 366: continue;
! 367: }
! 368: }
! 369: *out_p++ = c1 = c;
! 370: }
! 371:
! 372: macro_line = 0;
! 373: exp_end:
! 374: *out_p = EOS;
! 375: if (mcpp_debug & EXPAND)
! 376: dump_string( "expand_std exit", out);
! 377: macro_name = NULL;
! 378: clear_exp_mac(); /* Clear the information for diagnostic */
! 379: if (trace_macro) { /* Clear macro informations */
! 380: int num;
! 381: for (num = 1; num < mac_num; num++) { /* 'num' start at 1 */
! 382: if (mac_inf[ num].num_args >= 0) { /* Macro with args */
! 383: free( mac_inf[ num].args); /* Saved arguments */
! 384: free( mac_inf[ num].loc_args); /* Location of args */
! 385: }
! 386: }
! 387: free( mac_inf);
! 388: free( in_src);
! 389: }
! 390: *pragma_op = has_pragma;
! 391:
! 392: return out_p;
! 393: }
! 394:
! 395: static int print_macro_inf(
! 396: int c,
! 397: char ** cpp, /* Magic character sequence */
! 398: char ** opp /* Output for macro information */
! 399: )
! 400: /*
! 401: * Embed macro expansion information into comments.
! 402: * Enabled by '#pragma MCPP debug macro_call' or -K option in STD mode.
! 403: */
! 404: {
! 405: MACRO_INF * m_inf;
! 406: int num;
! 407: int num_args; /* Number of actual args (maybe less than expected) */
! 408: int i;
! 409:
! 410: if (*((*opp) - 1) == '/' && *((*opp) - 2) != '*')
! 411: /* Immediately preceding token is '/' (not '*' and '/') */
! 412: *((*opp)++) = ' ';
! 413: /* Insert a space to separate with following '/' and '*' */
! 414: if (option_flags.v || c == MAC_CALL_START || c == MAC_ARG_START) {
! 415: num = ((*(*cpp)++ & UCHARMAX) - 1) * UCHARMAX;
! 416: num += (*(*cpp)++ & UCHARMAX) - 1;
! 417: m_inf = & mac_inf[ num]; /* Saved information */
! 418: }
! 419: switch (c) {
! 420: case MAC_CALL_START : /* Start of a macro expansion */
! 421: *opp += sprintf( *opp, "/*<%s", m_inf->defp->name); /* Macro name */
! 422: if (m_inf->locs.start_line) {
! 423: /* Location of the macro call in source file */
! 424: *opp += sprintf( *opp, " %ld:%d-%ld:%d"
! 425: , m_inf->locs.start_line, (int) m_inf->locs.start_col
! 426: , m_inf->locs.end_line, (int) m_inf->locs.end_col);
! 427: }
! 428: *opp = stpcpy( *opp, "*/");
! 429: if ((num_args = m_inf->num_args) >= 1) {
! 430: /* The macro has arguments. Show the locations. */
! 431: for (i = 0; i < num_args; i++) /* Arg num begins at 0 */
! 432: *opp = print_macro_arg( *opp, m_inf, i, TRUE, TRUE);
! 433: }
! 434: break;
! 435: case MAC_ARG_START : /* Start of an argument */
! 436: i = (*(*cpp)++ & UCHARMAX) - 1; /* Argument number */
! 437: *opp = print_macro_arg( *opp, m_inf, i, FALSE, TRUE);
! 438: break;
! 439: case MAC_CALL_END : /* End of a macro expansion */
! 440: if (option_flags.v) { /* Verbose mode */
! 441: *opp += sprintf( *opp, "/*%s>*/", m_inf->defp->name);
! 442: break;
! 443: }
! 444: /* Else fall through */
! 445: case MAC_ARG_END : /* End of an argument */
! 446: if (option_flags.v) {
! 447: i = (*(*cpp)++ & UCHARMAX) - 1;
! 448: /* Output verbose infs symmetrical to start of the arg infs */
! 449: *opp = print_macro_arg( *opp, m_inf, i, FALSE, FALSE);
! 450: } else {
! 451: *opp = stpcpy( *opp, "/*>*/");
! 452: }
! 453: break;
! 454: }
! 455:
! 456: return **cpp & UCHARMAX;
! 457: }
! 458:
! 459: static char * print_macro_arg(
! 460: char * out, /* Output buffer */
! 461: MACRO_INF * m_inf, /* &mac_inf[ m_num] */
! 462: int argn, /* Argument number */
! 463: int real_arg, /* Real argument or expanded argument ? */
! 464: int start /* Start of an argument or end ? */
! 465: )
! 466: /*
! 467: * Embed an argument information into a comment.
! 468: * This routine is only called from above print_macro_inf().
! 469: */
! 470: {
! 471: LOCATION * loc = m_inf->loc_args + argn;
! 472:
! 473: out += sprintf( out, "/*%s%s:%d-%d", real_arg ? "!" : (start ? "<" : "")
! 474: , m_inf->defp->name, m_inf->recur, argn);
! 475:
! 476: if (real_arg && m_inf->loc_args && loc->start_line) {
! 477: /* Location of the argument in source file */
! 478: out += sprintf( out, " %ld:%d-%ld:%d", loc->start_line
! 479: , (int) loc->start_col, loc->end_line, (int) loc->end_col);
! 480: }
! 481: if (! start) /* End of an argument in verbose mode */
! 482: out = stpcpy( out, ">");
! 483: out = stpcpy( out, "*/");
! 484:
! 485: return out;
! 486: }
! 487:
! 488: static char * chk_magic_balance(
! 489: char * buf, /* Sequence to check */
! 490: char * buf_end, /* End of the sequence */
! 491: int move, /* Move a straying magic ? */
! 492: int diag /* Output a diagnostic? */
! 493: )
! 494: /*
! 495: * Check imbalance of macro information magics and warn it.
! 496: * get_an_arg() calls this routine setting 'move' argument on, hence a stray
! 497: * magic is moved to an edge if found.
! 498: * This routine does not do token parsing. Yet it will do fine practically.
! 499: */
! 500: {
! 501: #define MAX_NEST_MAGICS 255
! 502: char mac_id[ MAX_NEST_MAGICS][ MAC_E_LEN_V - 2];
! 503: char arg_id[ MAX_NEST_MAGICS][ ARG_E_LEN_V - 2];
! 504: char * mac_loc[ MAX_NEST_MAGICS];
! 505: char * arg_loc[ MAX_NEST_MAGICS];
! 506: char * mesg = "%s %ld %s-closing-comment(s) in tracing macro";
! 507: int mac, arg;
! 508: int mac_s_n, mac_e_n, arg_s_n, arg_e_n;
! 509: char * buf_p = buf; /* Save 'buf' for debugging purpose */
! 510:
! 511: mac = arg = 0;
! 512:
! 513: while (buf_p < buf_end) {
! 514: if (*buf_p++ != MAC_INF)
! 515: continue;
! 516: switch (*buf_p++) {
! 517: case MAC_CALL_START :
! 518: if (option_flags.v) {
! 519: mac_loc[ mac] = buf_p - 2;
! 520: memcpy( mac_id[ mac], buf_p, MAC_S_LEN - 2);
! 521: }
! 522: mac++;
! 523: buf_p += MAC_S_LEN - 2;
! 524: break;
! 525: case MAC_ARG_START :
! 526: if (option_flags.v) {
! 527: arg_loc[ arg] = buf_p - 2;
! 528: memcpy( arg_id[ arg], buf_p, ARG_S_LEN - 2);
! 529: }
! 530: arg++;
! 531: buf_p += ARG_S_LEN - 2;
! 532: break;
! 533: case MAC_ARG_END :
! 534: arg--;
! 535: if (option_flags.v) {
! 536: if (arg < 0) { /* Perhaps moved magic */
! 537: if (diag)
! 538: cwarn( mesg, "Redundant", (long) -arg, "argument");
! 539: } else if (memcmp( arg_id[ arg], buf_p, ARG_E_LEN_V - 2) != 0)
! 540: {
! 541: char * to_be_edge = NULL;
! 542: char * cur_edge;
! 543:
! 544: if (arg >= 1 && memcmp( arg_id[ 0], buf_p, ARG_E_LEN_V - 2)
! 545: == 0) {
! 546: to_be_edge = arg_loc[ arg];
! 547: /* To be moved to top */
! 548: cur_edge = arg_loc[ 0]; /* Current top */
! 549: } else if (arg == 0) {
! 550: char arg_end_magic[ 2] = { MAC_INF, MAC_ARG_END};
! 551: cur_edge = buf_end - ARG_E_LEN_V;
! 552: /* Search the last magic */
! 553: /* Sequence from get_an_arg() is always */
! 554: /* surrounded by starting of an arg magic */
! 555: /* and its corresponding closing magic. */
! 556: while (buf_p + (ARG_E_LEN_V - 2) <= cur_edge
! 557: && memcmp( cur_edge, arg_end_magic, 2) != 0)
! 558: cur_edge--;
! 559: if (buf_p + (ARG_E_LEN_V - 2) <= cur_edge
! 560: && memcmp( arg_id[ 0], cur_edge + 2
! 561: , ARG_E_LEN_V - 2) == 0) {
! 562: to_be_edge = buf_p - 2; /* To be moved to end */
! 563: }
! 564: }
! 565: if (to_be_edge) { /* Appropriate place found */
! 566: if (diag) {
! 567: mac_s_n = ((to_be_edge[ 2] & UCHARMAX) - 1)
! 568: * UCHARMAX;
! 569: mac_s_n += (to_be_edge[ 3] & UCHARMAX) - 1;
! 570: arg_s_n = (to_be_edge[ 4] & UCHARMAX) - 1;
! 571: mcpp_fprintf( ERR,
! 572: "Stray arg inf of macro: %d:%d at line:%d\n"
! 573: , mac_s_n, arg_s_n, src_line);
! 574: }
! 575: if (move) {
! 576: /* Move a stray magic to outside of sequences */
! 577: char magic[ ARG_E_LEN_V];
! 578: size_t len = ARG_E_LEN_V;
! 579: memcpy( magic, cur_edge, len);
! 580: /* Save current edge */
! 581: if (to_be_edge == arg_loc[ arg])
! 582: /* Shift followings to cur_edge */
! 583: memmove( cur_edge, cur_edge + len
! 584: , to_be_edge - cur_edge);
! 585: else /* Shift precedents to cur_edge */
! 586: memmove( to_be_edge + len, to_be_edge
! 587: , cur_edge - to_be_edge);
! 588: memcpy( to_be_edge, magic, len);
! 589: /* Restore old 'cur_edge' into old 'to_be_edge' */
! 590: }
! 591: } else { /* Serious imbalance, just warn */
! 592: char * arg_p = arg_id[ arg];
! 593: arg_s_n = ((arg_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
! 594: arg_s_n += (arg_p[ 1] & UCHARMAX) - 1;
! 595: arg_e_n = ((buf_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
! 596: arg_e_n += (buf_p[ 1] & UCHARMAX) - 1;
! 597: mcpp_fprintf( ERR,
! 598: "Asymmetry of arg inf found: start %d, end %d at line:%d\n"
! 599: , arg_s_n, arg_e_n, src_line);
! 600: }
! 601: }
! 602: buf_p += ARG_E_LEN_V - 2;
! 603: }
! 604: break;
! 605: case MAC_CALL_END :
! 606: mac--;
! 607: if (option_flags.v) {
! 608: if (mac < 0) {
! 609: if (diag)
! 610: cwarn( mesg, "Redundant", (long) -mac, "macro");
! 611: } else if (memcmp( mac_id[ mac], buf_p, MAC_E_LEN_V - 2) != 0)
! 612: {
! 613: char * mac_p = mac_id[ mac];
! 614: mac_s_n = ((mac_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
! 615: mac_s_n += (mac_p[ 1] & UCHARMAX) - 1;
! 616: mac_e_n = ((buf_p[ 0] & UCHARMAX) - 1) * UCHARMAX;
! 617: mac_e_n += (buf_p[ 1] & UCHARMAX) - 1;
! 618: mcpp_fprintf( ERR,
! 619: "Asymmetry of macro inf found: start %d, end %d at line:%d\n"
! 620: , mac_s_n, mac_e_n, src_line);
! 621: }
! 622: buf_p += MAC_E_LEN_V - 2;
! 623: }
! 624: break;
! 625: default : /* Not a MAC_INF sequence */
! 626: break; /* Continue */
! 627: }
! 628: }
! 629:
! 630: if (diag && (warn_level & 1)) {
! 631: if (mac > 0)
! 632: cwarn( mesg, "Lacking", (long) mac, "macro");
! 633: if (arg > 0)
! 634: cwarn( mesg, "Lacking", (long) arg, "argument");
! 635: if ((mac || arg) && (mcpp_debug & EXPAND))
! 636: mcpp_fputs(
! 637: "Imbalance of magics occurred (perhaps a moved magic), see <expand_std exit> and diagnostics.\n"
! 638: , DBG);
! 639: }
! 640:
! 641: return buf;
! 642: }
! 643:
! 644: static char * replace(
! 645: DEFBUF * defp, /* Macro to be replaced */
! 646: char * out, /* Output Buffer */
! 647: char * out_end, /* End of output buffer */
! 648: const DEFBUF * outer, /* Outer macro replacing*/
! 649: FILEINFO * rt_file, /* Repl-text "file" */
! 650: LINE_COL line_col, /* Location of macro */
! 651: int in_src_n /* Index into in_src[] */
! 652: )
! 653: /*
! 654: * Replace a possibly nested macro recursively.
! 655: * replace() and rescan() call each other recursively.
! 656: * Return the advanced output pointer or NULL on error.
! 657: */
! 658: {
! 659: char ** arglist = NULL; /* Pointers to arguments*/
! 660: int nargs; /* Number of arguments expected */
! 661: char * catbuf; /* Buffer for prescan() */
! 662: char * expbuf; /* Buffer for substitute() */
! 663: char * out_p; /* Output pointer */
! 664: char * cur_out = out; /* One more output pointer */
! 665: int num_args;
! 666: /* Number of actual arguments (maybe less than expected) */
! 667: int enable_trace_macro; /* To exclude _Pragma() pseudo macro */
! 668: int m_num = 0; /* 'mac_num' of current macro */
! 669: MACRO_INF * m_inf; /* Pointer into mac_inf[] */
! 670:
! 671: if (mcpp_debug & EXPAND) {
! 672: dump_a_def( "replace entry", defp, FALSE, TRUE, fp_debug);
! 673: dump_unget( "replace entry");
! 674: }
! 675: if ((mcpp_debug & MACRO_CALL) && in_if)
! 676: mcpp_fprintf( OUT, "/*%s*/", defp->name);
! 677:
! 678: enable_trace_macro = trace_macro && defp->nargs != DEF_PRAGMA;
! 679: if (enable_trace_macro) {
! 680: int num;
! 681: int recurs;
! 682:
! 683: if (mac_num >= MAX_MAC_INF - 1) {
! 684: cerror( "Too many nested macros in tracing %s" /* _E_ */
! 685: , defp->name, 0L, NULL);
! 686: return NULL;
! 687: } else if (mac_num >= max_mac_num - 1) {
! 688: size_t len = sizeof (MACRO_INF) * max_mac_num;
! 689: /* Enlarge the array */
! 690: mac_inf = (MACRO_INF *) xrealloc( (char *) mac_inf, len * 2);
! 691: memset( mac_inf + max_mac_num, 0, len);
! 692: /* Clear the latter half */
! 693: max_mac_num *= 2;
! 694: }
! 695: m_num = ++mac_num; /* Remember this number */
! 696: /* Note 'mac_num' starts at 1 */
! 697: *cur_out++ = MAC_INF; /* Embed a magic char */
! 698: *cur_out++ = MAC_CALL_START; /* A macro call */
! 699: /* Its index number, can be greater than UCHARMAX */
! 700: /* We represent the number by 2 bytes where each byte is not '\0' */
! 701: *cur_out++ = (m_num / UCHARMAX) + 1;
! 702: *cur_out++ = (m_num % UCHARMAX) + 1;
! 703: *cur_out = EOS;
! 704: m_inf = & mac_inf[ m_num];
! 705: m_inf->defp = defp; /* The macro definition */
! 706: m_inf->num_args = 0; /* Default num of args */
! 707: if (line_col.line) {
! 708: get_src_location( & line_col);
! 709: m_inf->locs.start_line = line_col.line;
! 710: m_inf->locs.start_col = line_col.col;
! 711: } else {
! 712: m_inf->locs.start_col = m_inf->locs.start_line = 0L;
! 713: }
! 714: m_inf->args = m_inf->loc_args = NULL; /* Default args */
! 715: for (num = 1, recurs = 0; num < m_num; num++)
! 716: if (mac_inf[ num].defp == defp)
! 717: recurs++; /* Recursively nested macro */
! 718: m_inf->recur = recurs;
! 719: }
! 720:
! 721: nargs = (defp->nargs == DEF_PRAGMA) ? 1 : (defp->nargs & ~AVA_ARGS);
! 722:
! 723: if (nargs < DEF_NOARGS_DYNAMIC) { /* __FILE__, __LINE__ */
! 724: defp = def_special( defp); /* These are redefined dynamically */
! 725: if (mcpp_mode == STD) {
! 726: /* Wrap repl-text with token separators to prevent token merging */
! 727: *cur_out++ = TOK_SEP;
! 728: cur_out = stpcpy( cur_out, defp->repl);
! 729: *cur_out++ = TOK_SEP;
! 730: *cur_out = EOS;
! 731: } else {
! 732: cur_out = stpcpy( cur_out, defp->repl);
! 733: }
! 734: if (enable_trace_macro) {
! 735: m_inf->defp = defp; /* Redefined dynamically*/
! 736: cur_out = close_macro_inf( cur_out, m_num, in_src_n);
! 737: }
! 738: return cur_out;
! 739: } else if (nargs == DEF_NOARGS_PREDEF_OLD && standard
! 740: && (warn_level & 1)) { /* Some macros on GCC */
! 741: cwarn( "Old style predefined macro \"%s\" is used", /* _W2_ */
! 742: defp->name, 0L, NULL);
! 743: } else if (nargs >= 0) { /* Function-like macro */
! 744: squeeze_ws( NULL, NULL, NULL); /* Skip to '(' */
! 745: /* Magic sequences are already read over by is_macro_call() */
! 746: arglist = (char **) xmalloc( (nargs + 1) * sizeof (char *));
! 747: arglist[ 0] = xmalloc( (size_t) (NMACWORK + IDMAX * 2));
! 748: /* Note: arglist[ n] may be reallocated */
! 749: /* and re-written by collect_args() */
! 750: if ((num_args = collect_args( defp, arglist, m_num)) == ARG_ERROR) {
! 751: free( arglist[ 0]); /* Syntax error */
! 752: free( arglist);
! 753: return NULL;
! 754: }
! 755: if (enable_trace_macro) {
! 756: /* Save the arglist for later informations */
! 757: m_inf->args = arglist[ 0];
! 758: m_inf->num_args = num_args; /* Number of actual args*/
! 759: }
! 760: if (mcpp_mode == STD && outer && rt_file != infile) {
! 761: /* Has read over replacement-text */
! 762: if (compat_mode) {
! 763: enable_repl( outer, FALSE); /* Enable re-expansion */
! 764: if (mcpp_debug & EXPAND)
! 765: dump_string( "enabled re-expansion"
! 766: , outer ? outer->name : "<arg>");
! 767: } else {
! 768: replacing[ rescan_level-1].read_over = READ_OVER;
! 769: }
! 770: }
! 771: }
! 772:
! 773: catbuf = xmalloc( (size_t) (NMACWORK + IDMAX));
! 774: if (mcpp_debug & EXPAND) {
! 775: mcpp_fprintf( DBG, "(%s)", defp->name);
! 776: dump_string( "prescan entry", defp->repl);
! 777: }
! 778: if (prescan( defp, (const char **) arglist, catbuf, catbuf + NMACWORK)
! 779: == FALSE) { /* Process #, ## operators */
! 780: diag_macro( CERROR, macbuf_overflow, defp->name, 0L, catbuf, defp
! 781: , NULL);
! 782: if (nargs >= 0) {
! 783: if (! enable_trace_macro)
! 784: /* arglist[0] is needed for macro infs */
! 785: free( arglist[ 0]);
! 786: free( arglist);
! 787: }
! 788: free( catbuf);
! 789: return NULL;
! 790: }
! 791: catbuf = xrealloc( catbuf, strlen( catbuf) + 1);
! 792: /* Use memory sparingly */
! 793: if (mcpp_debug & EXPAND) {
! 794: mcpp_fprintf( DBG, "(%s)", defp->name);
! 795: dump_string( "prescan exit", catbuf);
! 796: }
! 797:
! 798: if (nargs > 0) { /* Function-like macro with any argument */
! 799: expbuf = xmalloc( (size_t) (NMACWORK + IDMAX));
! 800: if (mcpp_debug & EXPAND) {
! 801: mcpp_fprintf( DBG, "(%s)", defp->name);
! 802: dump_string( "substitute entry", catbuf);
! 803: }
! 804: out_p = substitute( defp, (const char **) arglist, catbuf, expbuf
! 805: , expbuf + NMACWORK); /* Expand each arguments */
! 806: if (! enable_trace_macro)
! 807: free( arglist[ 0]);
! 808: free( arglist);
! 809: free( catbuf);
! 810: expbuf = xrealloc( expbuf, strlen( expbuf) + 1);
! 811: /* Use memory sparingly */
! 812: if (mcpp_debug & EXPAND) {
! 813: mcpp_fprintf( DBG, "(%s)", defp->name);
! 814: dump_string( "substitute exit", expbuf);
! 815: }
! 816: } else { /* Object-like macro or */
! 817: if (nargs == 0 && ! enable_trace_macro)
! 818: /* Function-like macro with no argument */
! 819: free( arglist[ 0]);
! 820: free( arglist);
! 821: out_p = expbuf = catbuf;
! 822: }
! 823:
! 824: if (out_p)
! 825: out_p = rescan( defp, expbuf, cur_out, out_end);
! 826: if (out_p && defp->nargs == DEF_PRAGMA)
! 827: has_pragma = TRUE;
! 828: /* Inform mcpp_main() that _Pragma() was found */
! 829: free( expbuf);
! 830: if (enable_trace_macro && out_p)
! 831: out_p = close_macro_inf( out_p, m_num, in_src_n);
! 832: if (mcpp_debug & EXPAND)
! 833: dump_string( "replace exit", out);
! 834:
! 835: if (trace_macro && defp->nargs == DEF_PRAGMA) {
! 836: /* Remove intervening magics if the macro is _Pragma pseudo-macro */
! 837: /* These magics have been inserted by macros in _Pragma()'s args */
! 838: int c;
! 839: cur_out = out_p = out;
! 840: while ((c = *cur_out++) != EOS) {
! 841: if (c == MAC_INF) {
! 842: if (! option_flags.v) {
! 843: switch (*cur_out) {
! 844: case MAC_ARG_START :
! 845: cur_out++;
! 846: /* Fall through */
! 847: case MAC_CALL_START :
! 848: cur_out++;
! 849: cur_out++;
! 850: /* Fall through */
! 851: default:
! 852: cur_out++;
! 853: break;
! 854: }
! 855: } else {
! 856: switch (*cur_out) {
! 857: case MAC_ARG_START :
! 858: case MAC_ARG_END :
! 859: cur_out++;
! 860: /* Fall through */
! 861: default:
! 862: cur_out += 3;
! 863: break;
! 864: }
! 865: }
! 866: } else {
! 867: *out_p++ = c;
! 868: }
! 869: }
! 870: *out_p = EOS;
! 871: }
! 872:
! 873: return out_p;
! 874: }
! 875:
! 876: static char * close_macro_inf(
! 877: char * out_p, /* Current output pointer */
! 878: int m_num, /* 'mac_num' of this macro */
! 879: int in_src_n /* Location of macro in arg */
! 880: )
! 881: /*
! 882: * Mark up closing of a macro expansion.
! 883: * Note that 'm_num' argument is necessary rather than 'm_inf' from replace(),
! 884: * because mac_inf[] may have been reallocated while rescanning.
! 885: */
! 886: {
! 887: MACRO_INF * m_inf;
! 888: LINE_COL e_line_col;
! 889:
! 890: m_inf = & mac_inf[ m_num];
! 891: *out_p++ = MAC_INF; /* Magic for end of macro expansion */
! 892: *out_p++ = MAC_CALL_END;
! 893: if (option_flags.v) {
! 894: *out_p++ = (m_num / UCHARMAX) + 1;
! 895: *out_p++ = (m_num % UCHARMAX) + 1;
! 896: }
! 897: *out_p = EOS;
! 898: get_ch(); /* Clear the garbage */
! 899: unget_ch();
! 900: if (infile->fp || in_src_n) {
! 901: if (infile->fp) { /* Macro call on source file */
! 902: e_line_col.line = src_line;
! 903: e_line_col.col = infile->bptr - infile->buffer;
! 904: } else { /* Macro in argument of parent macro and from source */
! 905: e_line_col.line = in_src[ in_src_n].end_line;
! 906: e_line_col.col = in_src[ in_src_n].end_col;
! 907: }
! 908: /* Get the location before line splicing by <backslash><newline> */
! 909: /* or by a line-crossing comment */
! 910: get_src_location( & e_line_col);
! 911: m_inf->locs.end_line = e_line_col.line;
! 912: m_inf->locs.end_col = e_line_col.col;
! 913: } else {
! 914: m_inf->locs.end_col = m_inf->locs.end_line = 0L;
! 915: }
! 916:
! 917: return out_p;
! 918: }
! 919:
! 920: static DEFBUF * def_special(
! 921: DEFBUF * defp /* Macro definition */
! 922: )
! 923: /*
! 924: * Re-define __LINE__, __FILE__.
! 925: * Return the new definition.
! 926: */
! 927: {
! 928: const FILEINFO * file;
! 929: DEFBUF ** prevp;
! 930: int cmp;
! 931:
! 932: switch (defp->nargs) {
! 933: case DEF_NOARGS_DYNAMIC - 1: /* __LINE__ */
! 934: if ((src_line > std_limits.line_num || src_line <= 0)
! 935: && (warn_level & 1))
! 936: diag_macro( CWARN
! 937: , "Line number %.0s\"%ld\" is out of range" /* _W1_ */
! 938: , NULL, src_line, NULL, defp, NULL);
! 939: sprintf( defp->repl, "%ld", src_line); /* Re-define */
! 940: break;
! 941: case DEF_NOARGS_DYNAMIC - 2: /* __FILE__ */
! 942: for (file = infile; file != NULL; file = file->parent) {
! 943: if (file->fp != NULL) {
! 944: sprintf( work_buf, "\"%s\"", file->filename);
! 945: if (str_eq( work_buf, defp->repl))
! 946: break; /* No change */
! 947: defp->nargs = DEF_NOARGS; /* Enable to redefine */
! 948: prevp = look_prev( defp->name, &cmp);
! 949: defp = install_macro( "__FILE__", DEF_NOARGS_DYNAMIC - 2, ""
! 950: , work_buf, prevp, cmp, 0); /* Re-define */
! 951: break;
! 952: }
! 953: }
! 954: break;
! 955: }
! 956: return defp;
! 957: }
! 958:
! 959: static int prescan(
! 960: const DEFBUF * defp, /* Definition of the macro */
! 961: const char ** arglist, /* Pointers to actual arguments */
! 962: char * out, /* Output buffer */
! 963: char * out_end /* End of output buffer */
! 964: )
! 965: /*
! 966: * Concatenate the tokens surounding ## by catenate(), and stringize the
! 967: * argument following # by stringize().
! 968: */
! 969: {
! 970: FILEINFO * file;
! 971: char * prev_token = NULL; /* Preceding token */
! 972: char * horiz_space = NULL; /* Horizontal white space */
! 973: int c; /* Value of a character */
! 974: /*
! 975: * The replacement lists are --
! 976: * stuff1<SEP>stuff2
! 977: * or stuff1<SEP>stuff2<SEP>stuff3...
! 978: * where <SEP> is CAT, maybe with preceding space and following space,
! 979: * stuff might be
! 980: * ordinary-token
! 981: * MAC_PARM<n>
! 982: * or <QUO>MAC_PARM<n>
! 983: * where <QUO> is ST_QUO, possibly with following space.
! 984: *
! 985: * DEF_MAGIC may has been inserted sometimes.
! 986: * In other than POST_STD modes, TOK_SEP and IN_SRC may have been
! 987: * inserted, and TOK_SEPs are inserted also in this routine.
! 988: * In trace_macro mode, many magic character sequences may have been
! 989: * inserted here and there.
! 990: */
! 991:
! 992: if (mcpp_mode == POST_STD) {
! 993: file = unget_string( defp->repl, defp->name);
! 994: } else {
! 995: *out++ = TOK_SEP; /* Wrap replacement */
! 996: workp = work_buf; /* text with token */
! 997: workp = stpcpy( workp, defp->repl); /* separators to */
! 998: *workp++ = TOK_SEP; /* prevent unintended*/
! 999: *workp = EOS; /* token merging. */
! 1000: file = unget_string( work_buf, defp->name);
! 1001: }
! 1002:
! 1003: while (c = get_ch(), file == infile) { /* To the end of repl */
! 1004:
! 1005: switch (c) {
! 1006: case ST_QUOTE:
! 1007: skip_ws(); /* Skip spaces and the returned MAC_PARM*/
! 1008: c = get_ch() - 1; /* Parameter number */
! 1009: prev_token = out; /* Remember the token */
! 1010: out = stringize( defp, arglist[ c], out);
! 1011: /* Stringize without expansion */
! 1012: horiz_space = NULL;
! 1013: break;
! 1014: case CAT:
! 1015: if (*prev_token == DEF_MAGIC || *prev_token == IN_SRC) {
! 1016: /* Rare case yet possible after catenate() */
! 1017: size_t len = 1;
! 1018: /* Remove trailing white space prior to removing DEF_MAGIC */
! 1019: if (horiz_space == out - 1) {
! 1020: *--out = EOS;
! 1021: horiz_space = NULL;
! 1022: }
! 1023: if (*prev_token == IN_SRC && trace_macro)
! 1024: len = IN_SRC_LEN;
! 1025: memmove( prev_token, prev_token + len
! 1026: , strlen( prev_token + len));
! 1027: out -= len;
! 1028: *out = EOS; /* Remove DEF_MAGIC, IN_SRC */
! 1029: }
! 1030: #if COMPILER == GNUC
! 1031: if (*prev_token == ',')
! 1032: break; /* ', ##' sequence (peculiar to GCC) */
! 1033: #endif
! 1034: if (horiz_space == out - 1) {
! 1035: *--out = EOS; /* Remove trailing white space */
! 1036: horiz_space = NULL;
! 1037: }
! 1038: out = catenate( defp, arglist, out, out_end, &prev_token);
! 1039: if (char_type[ *(out - 1) & UCHARMAX] & HSP)
! 1040: horiz_space = out - 1; /* TOK_SEP has been appended */
! 1041: break;
! 1042: case MAC_PARM:
! 1043: prev_token = out;
! 1044: *out++ = MAC_PARM;
! 1045: *out++ = get_ch(); /* Parameter number */
! 1046: break;
! 1047: case TOK_SEP:
! 1048: case ' ':
! 1049: case '\t' :
! 1050: if (out - 1 == horiz_space)
! 1051: continue; /* Squeeze white spaces */
! 1052: horiz_space = out;
! 1053: *out++ = c;
! 1054: break;
! 1055: default:
! 1056: prev_token = out;
! 1057: scan_token( c, &out, out_end); /* Ordinary token */
! 1058: break;
! 1059: }
! 1060:
! 1061: *out = EOS; /* Ensure termination */
! 1062: if (out_end <= out) /* Buffer overflow */
! 1063: return FALSE;
! 1064: }
! 1065:
! 1066: *out = EOS; /* Ensure terminatation in case of no token */
! 1067: unget_ch();
! 1068: return TRUE;
! 1069: }
! 1070:
! 1071: static char * catenate(
! 1072: const DEFBUF * defp, /* The macro definition */
! 1073: const char ** arglist, /* Pointers to actual arguments */
! 1074: char * out, /* Output buffer */
! 1075: char * out_end, /* End of output buffer */
! 1076: char ** token_p /* Address of preceding token pointer */
! 1077: )
! 1078: /*
! 1079: * Concatenate the previous and the following tokens.
! 1080: * Note: The parameter codes may coincide with white spaces or any
! 1081: * other characters.
! 1082: */
! 1083: {
! 1084: FILEINFO * file;
! 1085: char * prev_prev_token = NULL;
! 1086: const char * invalid_token
! 1087: = "Not a valid preprocessing token \"%s\""; /* _E_ _W2_ */
! 1088: const char * argp; /* Pointer to an actual argument*/
! 1089: char * prev_token = *token_p; /* Preceding token */
! 1090: int in_arg = FALSE;
! 1091: int c; /* Value of a character */
! 1092:
! 1093: /* Get the previous token */
! 1094: if (*prev_token == MAC_PARM) { /* Formal parameter */
! 1095: c = (*(prev_token + 1) & UCHARMAX) - 1; /* Parm number */
! 1096: argp = arglist[ c]; /* Actual argument */
! 1097: out = prev_token; /* To overwrite */
! 1098: if (trace_macro)
! 1099: argp = remove_magics( argp, TRUE); /* Remove pair of magics */
! 1100: if ((mcpp_mode == POST_STD && *argp == EOS)
! 1101: || (mcpp_mode == STD && *argp == RT_END)) {
! 1102: *out = EOS; /* An empty argument */
! 1103: } else {
! 1104: if (mcpp_mode == POST_STD) {
! 1105: file = unget_string( argp, NULL);
! 1106: while (c = get_ch(), file == infile) {
! 1107: prev_token = out; /* Remember the last token */
! 1108: scan_token( c, &out, out_end);
! 1109: } /* Copy actual argument without expansion */
! 1110: unget_ch();
! 1111: } else {
! 1112: unget_string( argp, NULL);
! 1113: if (trace_macro)
! 1114: free( (char *) argp);
! 1115: /* malloc()ed in remove_magics() */
! 1116: while ((c = get_ch()) != RT_END) {
! 1117: prev_prev_token = prev_token;
! 1118: prev_token = out; /* Remember the last token */
! 1119: scan_token( c, &out, out_end);
! 1120: } /* Copy actual argument without expansion */
! 1121: if (*prev_token == TOK_SEP) {
! 1122: out = prev_token;
! 1123: prev_token = prev_prev_token; /* Skip separator */
! 1124: }
! 1125: }
! 1126: if (*prev_token == DEF_MAGIC
! 1127: || (mcpp_mode == STD && *prev_token == IN_SRC)) {
! 1128: size_t len = 1;
! 1129: if (trace_macro && *prev_token == IN_SRC)
! 1130: len = IN_SRC_LEN;
! 1131: memmove( prev_token, prev_token + len
! 1132: , (size_t) ((out -= len) - prev_token));
! 1133: /* Remove DEF_MAGIC enabling the name to replace later */
! 1134: }
! 1135: }
! 1136: } /* Else the previous token is an ordinary token, not an argument */
! 1137:
! 1138: c = skip_ws();
! 1139:
! 1140: /* Catenate */
! 1141: switch (c) {
! 1142: case ST_QUOTE: /* First stringize and then catenate */
! 1143: skip_ws(); /* Skip MAC_PARM, ST_QUOTE */
! 1144: c = get_ch() - 1;
! 1145: out = stringize( defp, arglist[ c], out);
! 1146: break;
! 1147: case MAC_PARM:
! 1148: c = get_ch() - 1; /* Parameter number */
! 1149: argp = arglist[ c]; /* Actual argument */
! 1150: if (trace_macro)
! 1151: argp = remove_magics( argp, FALSE); /* Remove pair of magics */
! 1152: if ((mcpp_mode == POST_STD && *argp == EOS)
! 1153: || (mcpp_mode == STD && *argp == RT_END)) {
! 1154: *out = EOS; /* An empty argument */
! 1155: } else {
! 1156: unget_string( argp, NULL);
! 1157: if (trace_macro)
! 1158: free( (char *) argp);
! 1159: if ((c = get_ch()) == DEF_MAGIC) { /* Remove DEF_MAGIC */
! 1160: c = get_ch(); /* enabling to replace */
! 1161: } else if (c == IN_SRC) { /* Remove IN_SRC */
! 1162: if (trace_macro) {
! 1163: get_ch(); /* Also its number */
! 1164: get_ch();
! 1165: }
! 1166: c = get_ch();
! 1167: }
! 1168: scan_token( c, &out, out_end); /* The first token */
! 1169: if (*infile->bptr) /* There are more tokens*/
! 1170: in_arg = TRUE;
! 1171: }
! 1172: break;
! 1173: case IN_SRC:
! 1174: if (trace_macro) {
! 1175: get_ch();
! 1176: get_ch();
! 1177: }
! 1178: /* Fall through */
! 1179: case DEF_MAGIC:
! 1180: c = get_ch(); /* Skip DEF_MAGIC, IN_SRC */
! 1181: /* Fall through */
! 1182: default:
! 1183: scan_token( c, &out, out_end); /* Copy the token */
! 1184: break;
! 1185: }
! 1186:
! 1187: /* The generated sequence is a valid preprocessing-token ? */
! 1188: if (*prev_token) { /* There is any token */
! 1189: unget_string( prev_token, NULL); /* Scan once more */
! 1190: c = get_ch(); /* This line should be before the next line. */
! 1191: infile->fp = (FILE *)-1; /* To check token length*/
! 1192: if (mcpp_debug & EXPAND)
! 1193: dump_string( "checking generated token", infile->buffer);
! 1194: scan_token( c, (workp = work_buf, &workp), work_end);
! 1195: infile->fp = NULL;
! 1196: if (*infile->bptr != EOS) { /* More than a token */
! 1197: if (option_flags.lang_asm) { /* Assembler source */
! 1198: if (warn_level & 2)
! 1199: diag_macro( CWARN, invalid_token, prev_token, 0L, NULL
! 1200: , defp, NULL);
! 1201: } else {
! 1202: diag_macro( CERROR, invalid_token, prev_token, 0L, NULL, defp
! 1203: , NULL);
! 1204: }
! 1205: infile->bptr += strlen( infile->bptr);
! 1206: }
! 1207: get_ch(); /* To the parent "file" */
! 1208: unget_ch();
! 1209: }
! 1210:
! 1211: if (mcpp_mode == STD && ! option_flags.lang_asm) {
! 1212: *out++ = TOK_SEP; /* Prevent token merging*/
! 1213: *out = EOS;
! 1214: }
! 1215: if (in_arg) { /* There are more tokens after the generated one */
! 1216: if (mcpp_mode == POST_STD) {
! 1217: file = infile;
! 1218: while (c = get_ch(), file == infile) {
! 1219: prev_token = out; /* Remember the last token */
! 1220: scan_token( c, &out, out_end);
! 1221: } /* Copy rest of argument without expansion */
! 1222: unget_ch();
! 1223: } else {
! 1224: while ((c = get_ch()) != RT_END) {
! 1225: if (c == TOK_SEP)
! 1226: continue; /* Skip separator */
! 1227: prev_token = out; /* Remember the last token */
! 1228: scan_token( c, &out, out_end);
! 1229: } /* Copy rest of argument without expansion */
! 1230: }
! 1231: }
! 1232: *token_p = prev_token; /* Report back the last token */
! 1233:
! 1234: return out;
! 1235: }
! 1236:
! 1237: static const char * remove_magics(
! 1238: const char * argp, /* The argument list */
! 1239: int from_last /* token is the last or first? */
! 1240: )
! 1241: /*
! 1242: * Remove pair of magic character sequences in an argument in order to catenate
! 1243: * the last or first token to another.
! 1244: * Or remove pair of magic character sequences surrounding an argument in order
! 1245: * to keep symmetry of magics.
! 1246: */
! 1247: {
! 1248: #define INIT_MAGICS 128
! 1249:
! 1250: char (* mac_id)[ MAC_S_LEN];
! 1251: char (* arg_id)[ ARG_S_LEN];
! 1252: char ** mac_loc;
! 1253: char ** arg_loc;
! 1254: char * mgc_index;
! 1255: size_t max_magics;
! 1256: int mac_n, arg_n, ind, n;
! 1257: char * first = NULL;
! 1258: char * last = NULL;
! 1259: char * token;
! 1260: char * arg_p;
! 1261: char * ap;
! 1262: char * ep;
! 1263: char * tp;
! 1264: char * space = NULL;
! 1265: int with_rtend;
! 1266: int c;
! 1267: FILEINFO * file;
! 1268:
! 1269: mac_id = (char (*)[ MAC_S_LEN]) xmalloc( MAC_S_LEN * INIT_MAGICS);
! 1270: arg_id = (char (*)[ ARG_S_LEN]) xmalloc( ARG_S_LEN * INIT_MAGICS * 2);
! 1271: mac_loc = (char **) xmalloc( sizeof (char *) * INIT_MAGICS);
! 1272: arg_loc = (char **) xmalloc( sizeof (char *) * INIT_MAGICS * 2);
! 1273: mgc_index = xmalloc( INIT_MAGICS * 3);
! 1274: max_magics = INIT_MAGICS;
! 1275:
! 1276: mac_n = arg_n = ind = 0;
! 1277: ap = arg_p = xmalloc( strlen( argp) + 1);
! 1278: strcpy( arg_p, argp);
! 1279: ep = arg_p + strlen( arg_p);
! 1280: if (*(ep - 1) == RT_END) {
! 1281: with_rtend = TRUE;
! 1282: ep--; /* Point to RT_END */
! 1283: } else {
! 1284: with_rtend = FALSE;
! 1285: }
! 1286: file = unget_string( arg_p, NULL); /* Stack to "file" for token parsing*/
! 1287:
! 1288: /* Search all the magics in argument, as well as first and last token */
! 1289: /* Read stacked arg_p and write it to arg_p as a dummy buffer */
! 1290: while ((*ap++ = c = get_ch()) != RT_END && file == infile) {
! 1291: if (c == MAC_INF) {
! 1292: if (mac_n >= max_magics || arg_n >= max_magics * 2) {
! 1293: max_magics *= 2;
! 1294: mac_id = (char (*)[ MAC_S_LEN]) xrealloc( (void *) mac_id
! 1295: , MAC_S_LEN * max_magics);
! 1296: arg_id = (char (*)[ ARG_S_LEN]) xrealloc( (void *) arg_id
! 1297: , ARG_S_LEN * max_magics * 2);
! 1298: mac_loc = (char **) xrealloc( (void *) mac_loc
! 1299: , sizeof (char *) * max_magics);
! 1300: arg_loc = (char **) xrealloc( (void *) arg_loc
! 1301: , sizeof (char *) * max_magics * 2);
! 1302: mgc_index = xrealloc( mgc_index, max_magics * 3);
! 1303: }
! 1304: *ap++ = c = get_ch();
! 1305: switch (c) {
! 1306: case MAC_CALL_START :
! 1307: *ap++ = get_ch();
! 1308: *ap++ = get_ch();
! 1309: mac_loc[ mac_n] = ap - MAC_S_LEN; /* Location of the seq */
! 1310: memcpy( mac_id[ mac_n], ap - (MAC_S_LEN - 1), MAC_S_LEN - 1);
! 1311: /* Copy the sequence from its second byte */
! 1312: mac_id[ mac_n++][ MAC_S_LEN - 1] = FALSE;
! 1313: /* Mark of to-be-removed or not */
! 1314: break;
! 1315: case MAC_ARG_START :
! 1316: *ap++ = get_ch();
! 1317: *ap++ = get_ch();
! 1318: *ap++ = get_ch();
! 1319: arg_loc[ arg_n] = ap - ARG_S_LEN;
! 1320: memcpy( arg_id[ arg_n], ap - (ARG_S_LEN - 1), ARG_S_LEN - 1);
! 1321: arg_id[ arg_n++][ ARG_S_LEN - 1] = FALSE;
! 1322: break;
! 1323: case MAC_CALL_END :
! 1324: mac_loc[ mac_n] = ap - MAC_E_LEN;
! 1325: mac_id[ mac_n][ 0] = c;
! 1326: mac_id[ mac_n++][ MAC_E_LEN_V - 1] = FALSE;
! 1327: break;
! 1328: case MAC_ARG_END :
! 1329: arg_loc[ arg_n] = ap - ARG_E_LEN;
! 1330: arg_id[ arg_n][ 0] = c;
! 1331: arg_id[ arg_n++][ ARG_E_LEN_V - 1] = FALSE;
! 1332: break;
! 1333: }
! 1334: if (option_flags.v) {
! 1335: switch (c) {
! 1336: case MAC_CALL_END :
! 1337: mac_id[ mac_n - 1][ 1] = *ap++ = get_ch();
! 1338: mac_id[ mac_n - 1][ 2] = *ap++ = get_ch();
! 1339: break;
! 1340: case MAC_ARG_END :
! 1341: arg_id[ arg_n - 1][ 1] = *ap++ = get_ch();
! 1342: arg_id[ arg_n - 1][ 2] = *ap++ = get_ch();
! 1343: arg_id[ arg_n - 1][ 3] = *ap++ = get_ch();
! 1344: break;
! 1345: }
! 1346: }
! 1347: mgc_index[ ind++] = c; /* Index to mac_id[] and arg_id[] */
! 1348: continue;
! 1349: } else if (char_type[ c & UCHARMAX] & HSP) {
! 1350: if (! first) {
! 1351: ap--; /* Skip white space on top of the argument */
! 1352: ep--;
! 1353: }
! 1354: continue;
! 1355: }
! 1356: last = --ap;
! 1357: if (! first)
! 1358: first = ap;
! 1359: if (char_type[ c & UCHARMAX] & HSP)
! 1360: space = ap; /* Remember the last white space */
! 1361: scan_token( c, &ap, ep);
! 1362: }
! 1363: if (file == infile)
! 1364: get_ch(); /* Clear the "file" */
! 1365: unget_ch();
! 1366: if (space == ep - 1)
! 1367: ep--; /* Remove trailing white space */
! 1368: if (with_rtend)
! 1369: *ep++ = RT_END;
! 1370: *ep = EOS;
! 1371: if ((from_last && !last) || (!from_last && !first))
! 1372: return arg_p;
! 1373: if (mac_n == 0 && arg_n == 0) /* No magic sequence */
! 1374: return arg_p;
! 1375: token = from_last ? last : first;
! 1376:
! 1377: /* Remove pair of magics surrounding the last (or first) token */
! 1378: if (mac_n) {
! 1379: /* Remove pair of macro magics surrounding the token */
! 1380: int magic, mac_s, mac_e;
! 1381: int nest_s, nest_e;
! 1382:
! 1383: nest_s = 0;
! 1384: for (mac_s = 0; mac_loc[ mac_s] < token; mac_s++) {
! 1385: magic = mac_id[ mac_s][ 0];
! 1386: if (magic == MAC_CALL_START) { /* Starting magic */
! 1387: nest_e = ++nest_s;
! 1388: /* Search the corresponding closing magic */
! 1389: for (mac_e = mac_s + 1; mac_e < mac_n; mac_e++) {
! 1390: magic = mac_id[ mac_e][ 0];
! 1391: if (magic == MAC_CALL_START) {
! 1392: nest_e++;
! 1393: } else { /* MAC_CALL_END: Closing magic */
! 1394: nest_e--;
! 1395: /* Search after the token */
! 1396: if (token < mac_loc[ mac_e] && nest_e == nest_s - 1) {
! 1397: #if DEBUG_MACRO_ANN
! 1398: if (option_flags.v)
! 1399: chk_symmetry( mac_id[ mac_s], mac_id[ mac_e]
! 1400: , MAC_E_LEN - 2);
! 1401: #endif
! 1402: mac_id[ mac_e][ MAC_S_LEN - 1] = TRUE;
! 1403: /* To be removed */
! 1404: break; /* Done for this mac_s */
! 1405: }
! 1406: }
! 1407: }
! 1408: if (mac_e < mac_n) /* Found corresponding magic */
! 1409: mac_id[ mac_s][ MAC_S_LEN - 1] = TRUE; /* To be removed*/
! 1410: else /* Not found */
! 1411: break;
! 1412: } else {
! 1413: nest_s--; /* MAC_CALL_END: Closing magic */
! 1414: }
! 1415: }
! 1416: }
! 1417: if (arg_n) {
! 1418: /* Remove pair of arg magics surrounding the token */
! 1419: int magic, arg_s, arg_e;
! 1420: int nest_s, nest_e;
! 1421:
! 1422: nest_s = 0;
! 1423: for (arg_s = 0; arg_loc[ arg_s] < token; arg_s++) {
! 1424: magic = arg_id[ arg_s][ 0];
! 1425: if (magic == MAC_ARG_START) {
! 1426: nest_e = ++nest_s;
! 1427: for (arg_e = arg_s + 1; arg_e < arg_n; arg_e++) {
! 1428: magic = arg_id[ arg_e][ 0];
! 1429: if (magic == MAC_ARG_START) {
! 1430: nest_e++;
! 1431: } else {
! 1432: nest_e--;
! 1433: if (token < arg_loc[ arg_e] && nest_e == nest_s - 1) {
! 1434: #if DEBUG_MACRO_ANN
! 1435: if (option_flags.v)
! 1436: chk_symmetry( arg_id[ arg_s], arg_id[ arg_e]
! 1437: , ARG_E_LEN_V - 2);
! 1438: #endif
! 1439: arg_id[ arg_e][ ARG_S_LEN - 1] = TRUE;
! 1440: break;
! 1441: }
! 1442: }
! 1443: }
! 1444: if (arg_e < arg_n)
! 1445: arg_id[ arg_s][ ARG_S_LEN - 1] = TRUE;
! 1446: else
! 1447: break;
! 1448: } else {
! 1449: nest_s--;
! 1450: }
! 1451: }
! 1452: }
! 1453:
! 1454: /* Copy the sequences skipping the to-be-removed magic seqs */
! 1455: file = unget_string( arg_p, NULL); /* Stack to "file" for token parsing*/
! 1456: tp = arg_p;
! 1457: ep = arg_p + strlen( arg_p);
! 1458: mac_n = arg_n = n = 0;
! 1459:
! 1460: while ((*tp++ = c = get_ch()) != RT_END && file == infile) {
! 1461: char ** loc_tab;
! 1462: int num, mark, rm, magic;
! 1463: size_t len;
! 1464:
! 1465: if (c != MAC_INF) {
! 1466: scan_token( c, (--tp, &tp), ep);
! 1467: continue;
! 1468: }
! 1469: unget_ch(); /* Pushback MAC_INF */
! 1470: tp--;
! 1471:
! 1472: switch (magic = mgc_index[ n++]) {
! 1473: case MAC_CALL_START :
! 1474: len = MAC_S_LEN;
! 1475: mark = MAC_S_LEN - 1;
! 1476: break;
! 1477: case MAC_CALL_END :
! 1478: len = option_flags.v ? MAC_E_LEN_V : MAC_E_LEN;
! 1479: mark = MAC_E_LEN_V - 1;
! 1480: break;
! 1481: case MAC_ARG_START :
! 1482: len = ARG_S_LEN;
! 1483: mark = ARG_S_LEN - 1;
! 1484: break;
! 1485: case MAC_ARG_END :
! 1486: len = option_flags.v ? ARG_E_LEN_V : ARG_E_LEN;
! 1487: mark = ARG_E_LEN_V - 1;
! 1488: break;
! 1489: }
! 1490: switch (magic) {
! 1491: case MAC_CALL_START :
! 1492: case MAC_CALL_END :
! 1493: loc_tab = mac_loc;
! 1494: num = mac_n;
! 1495: rm = mac_id[ mac_n++][ mark];
! 1496: break;
! 1497: case MAC_ARG_START :
! 1498: case MAC_ARG_END :
! 1499: loc_tab = arg_loc;
! 1500: num = arg_n;
! 1501: rm = arg_id[ arg_n++][ mark];
! 1502: break;
! 1503: }
! 1504: if (rm == FALSE) { /* Not to be removed */
! 1505: memmove( tp, loc_tab[ num], len);
! 1506: /* Copy it (from arg_p buffer for convenience) */
! 1507: tp += len;
! 1508: }
! 1509: infile->bptr += len;
! 1510: }
! 1511: if (! with_rtend)
! 1512: tp--;
! 1513: *tp = EOS;
! 1514: if (file == infile)
! 1515: get_ch(); /* Clear the "file" */
! 1516: unget_ch();
! 1517:
! 1518: return arg_p;
! 1519: }
! 1520:
! 1521: #if DEBUG_MACRO_ANN
! 1522: static void chk_symmetry(
! 1523: char * start_id, /* Sequence of macro (or arg) starting inf */
! 1524: char * end_id, /* Sequence of macro (or arg) closing inf */
! 1525: size_t len /* Length of the sequence */
! 1526: )
! 1527: /*
! 1528: * Check whether starting sequence and corresponding closing sequence is the
! 1529: * same.
! 1530: */
! 1531: {
! 1532: int s_id, e_id, arg_s_n, arg_e_n;
! 1533:
! 1534: if (memcmp( start_id + 1, end_id + 1, len) == 0)
! 1535: return; /* The sequences are the same */
! 1536: s_id = ((start_id[ 1] & UCHARMAX) - 1) * UCHARMAX;
! 1537: s_id += (start_id[ 2] & UCHARMAX) - 1;
! 1538: e_id = ((end_id[ 1] & UCHARMAX) - 1) * UCHARMAX;
! 1539: e_id += (end_id[ 2] & UCHARMAX) - 1;
! 1540: if (len >= 3) {
! 1541: arg_s_n = (start_id[ 3] & UCHARMAX) - 1;
! 1542: arg_e_n = (end_id[ 3] & UCHARMAX) - 1;
! 1543: mcpp_fprintf( ERR,
! 1544: "Asymmetry of arg inf found removing magics: start %d:%d, end: %d:%d at line:%d\n"
! 1545: , s_id, arg_s_n, e_id, arg_e_n, src_line);
! 1546: } else {
! 1547: mcpp_fprintf( ERR,
! 1548: "Asymmetry of macro inf found removing magics: start %d, end: %d at line:%d\n"
! 1549: , s_id, e_id, src_line);
! 1550: }
! 1551: }
! 1552: #endif
! 1553:
! 1554: static char * stringize(
! 1555: const DEFBUF * defp, /* The macro definition */
! 1556: const char * argp, /* Pointer to argument */
! 1557: char * out /* Output buffer */
! 1558: )
! 1559: /*
! 1560: * Make a string literal from an argument.
! 1561: */
! 1562: {
! 1563: char arg_end_inf[ 8][ ARG_E_LEN_V - 1];
! 1564: /* Verbose information of macro arguments */
! 1565: FILEINFO * file;
! 1566: int stray_bsl = FALSE; /* '\\' not in literal */
! 1567: char * out_p = out;
! 1568: int token_type;
! 1569: int num_arg_magic = 0;
! 1570: size_t len;
! 1571: size_t arg_e_len = option_flags.v ? ARG_E_LEN_V : ARG_E_LEN;
! 1572: int c;
! 1573:
! 1574: if (trace_macro) {
! 1575: while ((*argp == MAC_INF && *(argp + 1) == MAC_ARG_START)
! 1576: /* Argument is prefixed with macro tracing magics */
! 1577: || (char_type[ *argp & UCHARMAX] & HSP)) {
! 1578: if (*argp == MAC_INF) { /* Move magics to outside of string */
! 1579: memcpy( out_p, argp, ARG_S_LEN);
! 1580: out_p += ARG_S_LEN;
! 1581: argp += ARG_S_LEN;
! 1582: num_arg_magic++;
! 1583: } else { /* Skip white spaces */
! 1584: argp++;
! 1585: }
! 1586: }
! 1587: }
! 1588:
! 1589: file = unget_string( argp, NULL);
! 1590: len = strlen( infile->buffer); /* Sequence ends with RT_END */
! 1591: if (trace_macro) { /* Remove suffixed argument closing magics */
! 1592: /* There are 0 or more argument closing magic sequences and */
! 1593: /* 0 or more TOK_SEPs and no space at the end of argp. */
! 1594: /* This is assured by get_an_arg(). */
! 1595: int nmagic = 0;
! 1596: while (len > arg_e_len
! 1597: && (((*(infile->buffer + len - arg_e_len - 1) == MAC_INF
! 1598: && *(infile->buffer + len - arg_e_len) == MAC_ARG_END)
! 1599: || *(infile->buffer + len - 2) == TOK_SEP))) {
! 1600: if (*(infile->buffer + len - arg_e_len - 1) == MAC_INF
! 1601: && *(infile->buffer + len - arg_e_len) == MAC_ARG_END) {
! 1602: if (option_flags.v) {
! 1603: memcpy( arg_end_inf[ nmagic]
! 1604: , infile->buffer + len - arg_e_len + 1
! 1605: , arg_e_len - 2);
! 1606: arg_end_inf[ nmagic][ arg_e_len - 2] = EOS;
! 1607: }
! 1608: nmagic++;
! 1609: len -= arg_e_len;
! 1610: *(infile->buffer + len - 1) = RT_END;
! 1611: *(infile->buffer + len) = EOS;
! 1612: } else if (*(infile->buffer + len - 2) == TOK_SEP) {
! 1613: len--;
! 1614: *(infile->buffer + len - 1) = RT_END;
! 1615: *(infile->buffer + len) = EOS;
! 1616: }
! 1617: }
! 1618: if (nmagic != num_arg_magic) { /* There are some imbalances */
! 1619: /* Some surrounding magics correspond to intervening ones. */
! 1620: /* So, unmatched surrounding magics should be removed. */
! 1621: if (num_arg_magic > nmagic) {
! 1622: num_arg_magic = nmagic; /* Ignore the surplus */
! 1623: out_p = out + ARG_S_LEN * num_arg_magic;
! 1624: } /* Else simply ignore the surplus nmagic */
! 1625: }
! 1626: }
! 1627: *out_p++ = '"'; /* Starting quote */
! 1628:
! 1629: while ((c = get_ch()), ((mcpp_mode == POST_STD && file == infile)
! 1630: || (mcpp_mode == STD && c != RT_END))) {
! 1631: if (c == ' ' || c == '\t') {
! 1632: *out_p++ = c;
! 1633: continue;
! 1634: } else if (c == TOK_SEP) {
! 1635: continue; /* Skip inserted separator */
! 1636: } else if (c == IN_SRC) { /* Skip magics */
! 1637: if (trace_macro) {
! 1638: get_ch();
! 1639: get_ch();
! 1640: }
! 1641: continue;
! 1642: } else if (c == '\\') {
! 1643: stray_bsl = TRUE; /* May cause a trouble */
! 1644: } else if (c == MAC_INF) { /* Remove intervening magics */
! 1645: switch (c = get_ch()) {
! 1646: case MAC_ARG_START :
! 1647: get_ch();
! 1648: /* Fall through */
! 1649: case MAC_CALL_START :
! 1650: get_ch();
! 1651: get_ch();
! 1652: break;
! 1653: }
! 1654: if (option_flags.v) {
! 1655: switch (c) {
! 1656: case MAC_ARG_END :
! 1657: get_ch();
! 1658: /* Fall through */
! 1659: case MAC_CALL_END :
! 1660: get_ch();
! 1661: get_ch();
! 1662: break;
! 1663: }
! 1664: }
! 1665: continue;
! 1666: }
! 1667: token_type = scan_token( c, (workp = work_buf, &workp), work_end);
! 1668:
! 1669: switch (token_type) {
! 1670: case WSTR:
! 1671: case WCHR:
! 1672: case STR:
! 1673: case CHR:
! 1674: workp = work_buf;
! 1675: while ((c = *workp++ & UCHARMAX) != EOS) {
! 1676: if (char_type[ c] & mbchk) { /* Multi-byte character */
! 1677: mb_read( c, &workp, (*out_p++ = c, &out_p));
! 1678: /* Copy as it is */
! 1679: continue;
! 1680: } else if (c == '"') {
! 1681: *out_p++ = '\\'; /* Insert '\\' */
! 1682: } else if (c == '\\') {
! 1683: #if OK_UCN
! 1684: if (mcpp_mode == POST_STD || ! stdc3
! 1685: || (*workp != 'u' && *workp != 'U'))
! 1686: /* Not UCN */
! 1687: #endif
! 1688: *out_p++ = '\\';
! 1689: }
! 1690: *out_p++ = c;
! 1691: }
! 1692: *out_p = EOS;
! 1693: break;
! 1694: default:
! 1695: out_p = stpcpy( out_p, work_buf);
! 1696: break;
! 1697: }
! 1698: }
! 1699:
! 1700: if (mcpp_mode == POST_STD)
! 1701: unget_ch();
! 1702: *out_p++ = '"'; /* Closing quote */
! 1703: if (trace_macro) {
! 1704: while (num_arg_magic--) {
! 1705: *out_p++ = MAC_INF; /* Restore removed magic*/
! 1706: *out_p++ = MAC_ARG_END;
! 1707: if (option_flags.v)
! 1708: out_p = stpcpy( out_p, arg_end_inf[ num_arg_magic]);
! 1709: }
! 1710: }
! 1711: *out_p = EOS;
! 1712:
! 1713: if (stray_bsl) { /* '\\' outside of quotation has been found */
! 1714: int invalid = FALSE;
! 1715: unget_string( out, defp->name);
! 1716: if (mcpp_debug & EXPAND)
! 1717: dump_string( "checking generated token", infile->buffer);
! 1718: scan_quote( get_ch(), work_buf, work_end, TRUE);
! 1719: /* Unterminated or too long string will be diagnosed */
! 1720: if (*infile->bptr != EOS) /* More than a token */
! 1721: invalid = TRUE; /* Diagnose after clearing the "file" */
! 1722: infile->bptr += strlen( infile->bptr);
! 1723: get_ch(); /* Clear the "file" */
! 1724: unget_ch();
! 1725: if (invalid)
! 1726: diag_macro( CERROR
! 1727: , "Not a valid string literal %s" /* _E_ */
! 1728: , out, 0L, NULL, defp, NULL);
! 1729: }
! 1730: #if NWORK-2 > SLEN90MIN
! 1731: else if ((warn_level & 4) && out_p - out > std_limits.str_len)
! 1732: diag_macro( CWARN
! 1733: , "String literal longer than %.0s%ld bytes %s" /* _W4_ */
! 1734: , NULL , (long) std_limits.str_len, out, defp, NULL);
! 1735: #endif
! 1736: return out_p;
! 1737: }
! 1738:
! 1739: static char * substitute(
! 1740: const DEFBUF * defp, /* The macro getting arguments */
! 1741: const char ** arglist, /* Pointers to actual arguments */
! 1742: const char * in, /* Replacement text */
! 1743: char * out, /* Output buffer */
! 1744: char * out_end /* End of output buffer */
! 1745: )
! 1746: /*
! 1747: * Replace completely each actual arguments of the macro, and substitute for
! 1748: * the formal parameters in the replacement list.
! 1749: */
! 1750: {
! 1751: char * out_start = out;
! 1752: const char * arg;
! 1753: int c;
! 1754: int gvar_arg; /* gvar_arg'th argument is GCC variable argument */
! 1755:
! 1756: gvar_arg = (defp->nargs & GVA_ARGS) ? (defp->nargs & ~AVA_ARGS) : 0;
! 1757: *out = EOS; /* Ensure to termanate */
! 1758:
! 1759: while ((c = *in++) != EOS) {
! 1760: if (c == MAC_PARM) { /* Formal parameter */
! 1761: c = *in++ & UCHARMAX; /* Parameter number */
! 1762: if (mcpp_debug & EXPAND) {
! 1763: mcpp_fprintf( DBG, " (expanding arg[%d])", c);
! 1764: dump_string( NULL, arglist[ c - 1]);
! 1765: }
! 1766: #if COMPILER == GNUC || COMPILER == MSC
! 1767: arg = arglist[ c - 1];
! 1768: if (trace_macro) {
! 1769: if (*arg == MAC_INF) {
! 1770: if (*++arg == MAC_ARG_START)
! 1771: arg += ARG_S_LEN - 1; /* Next to magic chars */
! 1772: }
! 1773: }
! 1774: #if COMPILER == GNUC
! 1775: if (c == gvar_arg && *arg == RT_END && ! ansi) {
! 1776: /*
! 1777: * GCC variadic macro and its variable argument is absent.
! 1778: * Note that in its "strict-ansi" mode GCC does not remove
! 1779: * ',', nevertheless it ignores '##' (inconsistent
! 1780: * behavior). Though GCC2 changes behavior depending the
! 1781: * ',' is preceded by space or not, we only count on the
! 1782: * "strict-ansi" flag.
! 1783: */
! 1784: #else
! 1785: if ((defp->nargs & VA_ARGS) && c == (defp->nargs & ~VA_ARGS)
! 1786: && *arg == RT_END && mcpp_mode == STD) {
! 1787: /* Visual C 2005 also removes ',' immediately preceding */
! 1788: /* absent variable arguments. It does not use '##' though. */
! 1789: #endif
! 1790: char * tmp;
! 1791: tmp = out - 1;
! 1792: while (char_type[ *tmp & UCHARMAX] & HSP)
! 1793: tmp--;
! 1794: if (*tmp == ',') {
! 1795: out = tmp; /* Remove the immediately preceding ',' */
! 1796: if (warn_level & 1) {
! 1797: *out = EOS;
! 1798: diag_macro( CWARN,
! 1799: "Removed ',' preceding the absent variable argument: %s" /* _W1_ */
! 1800: , out_start, 0L, NULL, defp, NULL);
! 1801: }
! 1802: }
! 1803: } else
! 1804: #endif
! 1805: if ((out = rescan( NULL, arglist[ c - 1], out, out_end))
! 1806: == NULL) { /* Replace completely */
! 1807: return NULL; /* Error */
! 1808: }
! 1809: } else {
! 1810: *out++ = c; /* Copy the character */
! 1811: }
! 1812: }
! 1813: *out = EOS;
! 1814: return out;
! 1815: }
! 1816:
! 1817: static char * rescan(
! 1818: const DEFBUF * outer, /* Outer macro just replacing */
! 1819: const char * in, /* Sequences to be rescanned */
! 1820: char * out, /* Output buffer */
! 1821: char * out_end /* End of output buffer */
! 1822: )
! 1823: /*
! 1824: * Re-scan the once replaced sequences to replace the remaining macros
! 1825: * completely.
! 1826: * rescan() and replace() call each other recursively.
! 1827: *
! 1828: * Note: POST_STD mode does not use IN_SRC nor TOK_SEP and seldom uses RT_END.
! 1829: * Checking of those are unnecessary overhead for POST_STD mode. To integrate
! 1830: * the code for POST_STD with STD mode, however, we use these checkings
! 1831: * commonly.
! 1832: * Also compat_mode does not use IN_SRC unless in trace_macro mode.
! 1833: * STD mode has macro notification mode (trace_macro mode), too. Its routines
! 1834: * are complicated and not easy to understand.
! 1835: */
! 1836: {
! 1837: char * cur_cp = NULL;
! 1838: char * tp = NULL; /* Temporary pointer into buffer*/
! 1839: char * out_p = out; /* Current output pointer */
! 1840: FILEINFO * file; /* Input sequences stacked on a "file" */
! 1841: DEFBUF * inner; /* Inner macro to replace */
! 1842: int c; /* First character of token */
! 1843: int token_type;
! 1844: char * mac_arg_start = NULL;
! 1845: #if COMPILER == GNUC
! 1846: int within_defined = FALSE;
! 1847: int within_defined_arg_depth = 0;
! 1848: #endif
! 1849:
! 1850: if (mcpp_debug & EXPAND) {
! 1851: mcpp_fprintf( DBG, "rescan_level--%d (%s) "
! 1852: , rescan_level + 1, outer ? outer->name : "<arg>");
! 1853: dump_string( "rescan entry", in);
! 1854: }
! 1855: if (! disable_repl( outer)) /* Don't re-replace replacing macro */
! 1856: return NULL; /* Too deeply nested macro call */
! 1857: if (mcpp_mode == STD) {
! 1858: get_ch(); /* Clear empty "file"s */
! 1859: unget_ch(); /* for diagnostic */
! 1860: cur_cp = infile->bptr; /* Remember current location */
! 1861: }
! 1862: file = unget_string( in, outer ? outer->name : NULL);
! 1863: /* Stack input on a "file" */
! 1864:
! 1865: while ((c = get_ch()), file == infile
! 1866: /* Rescanning is limited to the "file" */
! 1867: && c != RT_END) {
! 1868: /*
! 1869: * This is the trick of STD mode. collect_args() via replace()
! 1870: * may read over to file->parent (provided the "file" is macro)
! 1871: * unless stopped by RT_END.
! 1872: */
! 1873: size_t len = 0;
! 1874:
! 1875: if (char_type[ c] & HSP) {
! 1876: *out_p++ = c;
! 1877: continue;
! 1878: } else if (c == MAC_INF) { /* Only in STD mode */
! 1879: *out_p++ = c;
! 1880: *out_p++ = c = get_ch();
! 1881: switch (c) {
! 1882: case MAC_ARG_START :
! 1883: mac_arg_start = out_p - 2; /* Remember the position */
! 1884: *out_p++ = get_ch();
! 1885: /* Fall through */
! 1886: case MAC_CALL_START :
! 1887: *out_p++ = get_ch();
! 1888: *out_p++ = get_ch();
! 1889: break;
! 1890: case MAC_ARG_END :
! 1891: if (! option_flags.v)
! 1892: break;
! 1893: else
! 1894: *out_p++ = get_ch();
! 1895: /* Fall through */
! 1896: case MAC_CALL_END :
! 1897: if (option_flags.v) {
! 1898: *out_p++ = get_ch();
! 1899: *out_p++ = get_ch();
! 1900: }
! 1901: break;
! 1902: } /* Pass these characters as they are */
! 1903: continue;
! 1904: }
! 1905: token_type = scan_token( c, (tp = out_p, &out_p), out_end);
! 1906: #if COMPILER == GNUC
! 1907: if (mcpp_mode == STD) {
! 1908: /* Pass stuff within defined() as they are, if in_directive */
! 1909: if ((within_defined || within_defined_arg_depth)) {
! 1910: if (c == '(') {
! 1911: within_defined_arg_depth++;
! 1912: within_defined = FALSE;
! 1913: } else if (within_defined_arg_depth && c == ')') {
! 1914: within_defined_arg_depth--;
! 1915: } /* Else should be a name (possibly macro) */
! 1916: continue;
! 1917: } else if (token_type == NAM && in_directive
! 1918: && str_eq(identifier, "defined")) {
! 1919: within_defined = TRUE;
! 1920: /* 'defined' token in directive line */
! 1921: continue;
! 1922: }
! 1923: }
! 1924: #endif
! 1925: if (mcpp_mode == STD && c == IN_SRC)
! 1926: len = trace_macro ? IN_SRC_LEN : 1;
! 1927: if (token_type == NAM && c != DEF_MAGIC
! 1928: && (inner = look_id( tp + len)) != NULL) { /* A macro name */
! 1929: int is_able; /* Macro is not "blue-painted" */
! 1930: char * endf = NULL; /* Output stream at end of infile */
! 1931: MAGIC_SEQ mgc_seq; /* Magics between macro name and '(' */
! 1932:
! 1933: if (trace_macro)
! 1934: memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
! 1935: if (is_macro_call( inner, &out_p, &endf
! 1936: , trace_macro ? &mgc_seq : NULL)
! 1937: && ((mcpp_mode == POST_STD && is_able_repl( inner))
! 1938: || (mcpp_mode == STD
! 1939: && (((is_able = is_able_repl( inner)) == YES)
! 1940: || (is_able == READ_OVER
! 1941: && (c == IN_SRC || compat_mode)))))) {
! 1942: /* Really a macro call */
! 1943: LINE_COL in_src_line_col = { 0L, 0};
! 1944: int in_src_n = 0;
! 1945:
! 1946: if (trace_macro) {
! 1947: if (c == IN_SRC) { /* Macro in argument from source */
! 1948: /* Get the location in source */
! 1949: in_src_n = ((*(tp + 1) & UCHARMAX) - 1) * UCHARMAX;
! 1950: in_src_n += (*(tp + 2) & UCHARMAX) - 1;
! 1951: in_src_line_col.line = in_src[ in_src_n].start_line;
! 1952: in_src_line_col.col = in_src[ in_src_n].start_col;
! 1953: }
! 1954: if (inner->nargs >= 0 && mgc_seq.magic_start) {
! 1955: /* Magic sequence is found between macro */
! 1956: /* name and '('. This is a nuisance. */
! 1957: char * mgc_cleared;
! 1958: size_t seq_len;
! 1959: size_t arg_elen = option_flags.v ? ARG_E_LEN_V
! 1960: : ARG_E_LEN;
! 1961: if ((tp - ARG_S_LEN) == mac_arg_start
! 1962: && *mgc_seq.magic_start == MAC_INF
! 1963: && *(mgc_seq.magic_start + 1) == MAC_ARG_END) {
! 1964: /* Name of function-like macro is surrounded by */
! 1965: /* magics, which were inserted by outer macro. */
! 1966: /* Remove the starting magic. (The closing magic*/
! 1967: /* has already been removed by is_macro_call(). */
! 1968: tp -= ARG_S_LEN;
! 1969: mgc_seq.magic_start += arg_elen; /* Next seq */
! 1970: }
! 1971: /* Restore once skipped magic sequences, */
! 1972: /* then remove "pair"s of sequences. */
! 1973: seq_len = mgc_seq.magic_end - mgc_seq.magic_start;
! 1974: if (seq_len) {
! 1975: insert_to_bptr( mgc_seq.magic_start, seq_len);
! 1976: mgc_cleared = remove_magics(
! 1977: (const char *) infile->bptr, FALSE);
! 1978: /* Remove pair of magics */
! 1979: strcpy( infile->bptr, mgc_cleared);
! 1980: free( mgc_cleared);
! 1981: }
! 1982: }
! 1983: }
! 1984: if ((out_p = replace( inner, tp, out_end, outer, file
! 1985: , in_src_line_col, in_src_n)) == NULL)
! 1986: break; /* Error of macro call */
! 1987: } else {
! 1988: if (endf && strlen( endf)) {
! 1989: /* Has read over to parent file: another nuisance. */
! 1990: /* Restore the read-over sequence into current buffer. */
! 1991: /* Don't use unget_string() here. */
! 1992: insert_to_bptr( endf, out_p - endf);
! 1993: out_p = endf;
! 1994: *out_p = EOS;
! 1995: }
! 1996: if ((is_able = is_able_repl( inner)) == NO
! 1997: || (mcpp_mode == STD && is_able == READ_OVER
! 1998: && c != IN_SRC && ! compat_mode)) {
! 1999: if (mcpp_mode == POST_STD || c != IN_SRC)
! 2000: memmove( tp + 1, tp, (size_t) (out_p++ - tp));
! 2001: *tp = DEF_MAGIC; /* Mark not to replace */
! 2002: } /* Else not a macro call*/
! 2003: }
! 2004: }
! 2005: if (out_end <= out_p) {
! 2006: *out_p = EOS;
! 2007: diag_macro( CERROR, macbuf_overflow, outer ? outer->name : in, 0L
! 2008: , out, outer, inner);
! 2009: out_p = NULL;
! 2010: break;
! 2011: }
! 2012: }
! 2013:
! 2014: if (out_p) {
! 2015: *out_p = EOS;
! 2016: if (mcpp_mode == STD) {
! 2017: if (c != RT_END) {
! 2018: unget_ch();
! 2019: if (outer != NULL) { /* outer isn't a macro in argument */
! 2020: if (infile && infile->bptr != cur_cp
! 2021: /* Have overrun replacement list*/
! 2022: && !(tp && *tp == DEF_MAGIC)
! 2023: /* Macro is enabled */
! 2024: && ((!compat_mode && (warn_level & 1))
! 2025: || (compat_mode && (warn_level & 8)))) {
! 2026: diag_macro( CWARN,
! 2027: "Replacement text \"%s\" of macro %.0ld\"%s\" involved subsequent text" /* _W1_ */
! 2028: , in, 0L, outer->name, outer, inner);
! 2029: }
! 2030: }
! 2031: } /* Else remove RT_END */
! 2032: } else {
! 2033: unget_ch();
! 2034: }
! 2035: }
! 2036: enable_repl( outer, TRUE); /* Enable macro for later text */
! 2037: if (mcpp_debug & EXPAND) {
! 2038: mcpp_fprintf( DBG, "rescan_level--%d (%s) "
! 2039: , rescan_level + 1, outer ? outer->name : "<arg>");
! 2040: dump_string( "rescan exit", out);
! 2041: }
! 2042: return out_p;
! 2043: }
! 2044:
! 2045: static int disable_repl(
! 2046: const DEFBUF * defp
! 2047: )
! 2048: /*
! 2049: * Register the macro name currently replacing.
! 2050: */
! 2051: {
! 2052: if (defp == NULL)
! 2053: return TRUE;
! 2054: if (rescan_level >= RESCAN_LIMIT) {
! 2055: diag_macro( CERROR,
! 2056: "Rescanning macro \"%s\" more than %ld times at \"%s\"" /* _E_ */
! 2057: , macro_name, (long) RESCAN_LIMIT, defp->name, defp, NULL);
! 2058: return FALSE;
! 2059: }
! 2060: replacing[ rescan_level].def = defp;
! 2061: replacing[ rescan_level++].read_over = NO;
! 2062: return TRUE;
! 2063: }
! 2064:
! 2065: static void enable_repl(
! 2066: const DEFBUF * defp,
! 2067: int done
! 2068: )
! 2069: /*
! 2070: * Un-register the macro name just replaced for later text.
! 2071: */
! 2072: {
! 2073: if (defp == NULL)
! 2074: return;
! 2075: replacing[ rescan_level - 1].def = NULL;
! 2076: if (done && rescan_level)
! 2077: rescan_level--;
! 2078: }
! 2079:
! 2080: static int is_able_repl(
! 2081: const DEFBUF * defp
! 2082: )
! 2083: /*
! 2084: * The macro is permitted to replace ?
! 2085: */
! 2086: {
! 2087: int i;
! 2088:
! 2089: if (defp == NULL)
! 2090: return YES;
! 2091: for (i = rescan_level-1; i >= 0; i--) {
! 2092: if (defp == replacing[ i].def)
! 2093: return replacing[ i].read_over;
! 2094: }
! 2095: return YES;
! 2096: }
! 2097:
! 2098: static char * insert_to_bptr(
! 2099: char * ins, /* Sequence to be inserted */
! 2100: size_t len /* Byte to be inserted */
! 2101: )
! 2102: /*
! 2103: * Insert a sequence into infile->bptr.
! 2104: * infile->buffer is reallocated to ensure buffer size.
! 2105: * This routine changes absolute address of infile->bptr, hence rescan() emits
! 2106: * a "Replacement text ... involved subsequent text" warning. Anyway,
! 2107: * a macro which needs this routine deserves that warning.
! 2108: */
! 2109: {
! 2110: size_t bptr_offset = infile->bptr - infile->buffer;
! 2111:
! 2112: if (infile->fp == NULL) { /* Not source file */
! 2113: infile->buffer = xrealloc( infile->buffer
! 2114: , strlen( infile->buffer) + len + 1);
! 2115: infile->bptr = infile->buffer + bptr_offset;
! 2116: }
! 2117: memmove( infile->bptr + len, infile->bptr, strlen( infile->bptr) + 1);
! 2118: memcpy( infile->bptr, ins, len);
! 2119:
! 2120: return infile->buffer;
! 2121: }
! 2122:
! 2123: /*
! 2124: * M a c r o E x p a n s i o n i n P R E - S T A N D A R D M o d e
! 2125: */
! 2126:
! 2127: #include "setjmp.h"
! 2128:
! 2129: static jmp_buf jump;
! 2130:
! 2131: static char * arglist_pre[ NMACPARS]; /* Pointers to args */
! 2132:
! 2133: static int rescan_pre( int c, char * mp, char * mac_end);
! 2134: /* Replace a macro repeatedly */
! 2135: static int replace_pre( DEFBUF * defp);
! 2136: /* Replace a macro once */
! 2137: static void substitute_pre( DEFBUF * defp);
! 2138: /* Substitute parms with args */
! 2139:
! 2140: static char * expand_prestd(
! 2141: DEFBUF * defp, /* Macro definition */
! 2142: char * out, /* Output buffer */
! 2143: char * out_end, /* End of output buffer */
! 2144: LINE_COL line_col, /* Location of macro (not used in prestd) */
! 2145: int * pragma_op /* Flag of _Pragma (not used in prestd) */
! 2146: )
! 2147: /*
! 2148: * Expand a macro call completely, write the results to the specified buffer
! 2149: * and return the advanced pointer.
! 2150: */
! 2151: {
! 2152: char macrobuf[ NMACWORK + IDMAX]; /* Buffer for rescan_pre() */
! 2153: char * mac_end = ¯obuf[ NMACWORK]; /* End of macrobuf[] */
! 2154: char * out_p; /* Pointer into out[] */
! 2155: char * mp = macrobuf; /* Pointer into macrobuf*/
! 2156: int len; /* Length of a token */
! 2157: int token_type; /* Type of token */
! 2158: int c;
! 2159:
! 2160: macro_line = src_line; /* Line number for diag.*/
! 2161: unget_string( identifier, identifier); /* To re-read */
! 2162: macro_name = defp->name;
! 2163: rescan_level = 0;
! 2164: if (setjmp( jump) == 1) {
! 2165: skip_macro();
! 2166: mp = macrobuf;
! 2167: *mp = EOS;
! 2168: macro_line = MACRO_ERROR;
! 2169: goto err_end;
! 2170: }
! 2171:
! 2172: while ((c = get_ch()) != CHAR_EOF && infile->fp == NULL) {
! 2173: /* While the input stream is a macro */
! 2174: while (c == ' ' || c == '\t') { /* Output the spaces */
! 2175: *mp++ = c;
! 2176: c = get_ch();
! 2177: if (infile == NULL || infile->fp != NULL)
! 2178: goto exp_end;
! 2179: }
! 2180: token_type = rescan_pre( c, mp, mac_end); /* Scan token */
! 2181: /* and expand. Result of expansion is written at mp. */
! 2182:
! 2183: switch (token_type) {
! 2184: case STR: /* String literal */
! 2185: case CHR: /* Character constant */
! 2186: case NUM: /* Number token */
! 2187: case OPE: /* Operator or punct. */
! 2188: case NAM: /* Identifier */
! 2189: len = strlen( mp);
! 2190: mp += len;
! 2191: break;
! 2192: case SEP: /* Special character */
! 2193: switch( *mp) {
! 2194: case COM_SEP:
! 2195: if (mcpp_mode == OLD_PREP)
! 2196: break; /* Zero-length comment is removed now */
! 2197: /* Else fall through */
! 2198: default: /* Who knows ? */
! 2199: mp++; /* Copy the character */
! 2200: break;
! 2201: }
! 2202: break;
! 2203: case NO_TOKEN: break; /* End of file */
! 2204: default: /* Unkown token char. */
! 2205: mp++; /* Copy the character */
! 2206: break;
! 2207: }
! 2208:
! 2209: if (mac_end <= mp) {
! 2210: *mp = EOS;
! 2211: cerror( macbuf_overflow, macro_name, 0L, macrobuf);
! 2212: longjmp( jump, 1);
! 2213: }
! 2214: if (mcpp_debug & GETC) {
! 2215: *mp = EOS;
! 2216: dump_string( "macrobuf", macrobuf);
! 2217: }
! 2218: }
! 2219:
! 2220: exp_end:
! 2221: unget_ch();
! 2222: while (macrobuf < mp && (*(mp - 1) == ' ' || *(mp - 1) == '\t'))
! 2223: mp--; /* Remove trailing blank */
! 2224: macro_line = 0;
! 2225: *mp = EOS;
! 2226: if (mp - macrobuf > out_end - out) {
! 2227: cerror( macbuf_overflow, macro_name, 0L, macrobuf);
! 2228: macro_line = MACRO_ERROR;
! 2229: }
! 2230: err_end:
! 2231: out_p = stpcpy( out, macrobuf);
! 2232: if (mcpp_debug & EXPAND) {
! 2233: dump_string( "expand_prestd exit", out);
! 2234: }
! 2235: macro_name = NULL;
! 2236: clear_exp_mac();
! 2237: *pragma_op = FALSE;
! 2238: return out_p;
! 2239: }
! 2240:
! 2241: static int rescan_pre(
! 2242: int c, /* First character of token */
! 2243: char * mp, /* Output buffer */
! 2244: char * mac_end /* End of output buffer */
! 2245: )
! 2246: /*
! 2247: * If the token is a macro name, replace the macro repeatedly until the first
! 2248: * token becomes a non-macro and return the type of token after expansion.
! 2249: */
! 2250: {
! 2251: int token_type; /* Type of token */
! 2252: char * cp = mp; /* Value of mp should not be changed */
! 2253: DEFBUF * defp;
! 2254: FILEINFO * file;
! 2255:
! 2256: while ((token_type = scan_token( c, &cp, mac_end)) == NAM
! 2257: && (defp = look_id( identifier)) != NULL) { /* Macro */
! 2258: if (replace_pre( defp) == FALSE)
! 2259: break; /* Macro name with no argument */
! 2260: file = infile;
! 2261: c = get_ch();
! 2262: if (file != infile) { /* Replaced to 0 token */
! 2263: unget_ch();
! 2264: token_type = NO_TOKEN;
! 2265: break;
! 2266: }
! 2267: cp = mp; /* Overwrite on the macro call */
! 2268: } /* The macro call is replaced */
! 2269: return token_type;
! 2270: }
! 2271:
! 2272: static int replace_pre(
! 2273: DEFBUF * defp /* Definition of the macro */
! 2274: )
! 2275: /*
! 2276: * Replace a macro one level. Called from expand_prestd() (via rescan_pre())
! 2277: * when an identifier is found in the macro table. It calls collect_args()
! 2278: * to parse actual arguments, checking for the correct number. It then
! 2279: * creates a "file" containing single line containing the replacement text
! 2280: * with the actual arguments inserted appropriately. This is "pushed back"
! 2281: * onto the input stream. (When get_ch() routine runs off the end of the macro
! 2282: * line, it will dismiss the macro itself.)
! 2283: */
! 2284: {
! 2285: int arg_len;
! 2286: int c;
! 2287:
! 2288: if (mcpp_debug & EXPAND) {
! 2289: dump_a_def( "replace_pre entry", defp, FALSE, TRUE, fp_debug);
! 2290: dump_unget( "replace_pre entry");
! 2291: }
! 2292: if (++rescan_level >= PRESTD_RESCAN_LIMIT) {
! 2293: diag_macro( CERROR
! 2294: , "Recursive macro definition of \"%s\"" /* _E_ */
! 2295: , defp->name, 0L, NULL, defp, NULL);
! 2296: longjmp( jump, 1);
! 2297: }
! 2298:
! 2299: /*
! 2300: * Here's a macro to replace.
! 2301: */
! 2302: switch (defp->nargs) {
! 2303: case DEF_NOARGS: /* No argument just stuffs */
! 2304: case DEF_NOARGS_PREDEF_OLD: /* Compiler-specific predef without '_' */
! 2305: case DEF_NOARGS_PREDEF: /* Compiler-specific predef */
! 2306: break;
! 2307: default: /* defp->nargs >= 0 */
! 2308: c = squeeze_ws( NULL, NULL, NULL); /* Look for and skip '('*/
! 2309: if (c != '(') { /* Macro name without following '(' */
! 2310: unget_ch();
! 2311: if (warn_level & 8)
! 2312: diag_macro( CWARN, only_name, defp->name, 0L, NULL, defp, NULL);
! 2313: return FALSE;
! 2314: } else {
! 2315: arglist_pre[ 0] = xmalloc( (size_t) (NMACWORK + IDMAX * 2));
! 2316: arg_len = collect_args( defp, arglist_pre, 0);
! 2317: /* Collect arguments */
! 2318: if (arg_len == ARG_ERROR) { /* End of input */
! 2319: free( arglist_pre[ 0]);
! 2320: longjmp( jump, 1);
! 2321: }
! 2322: }
! 2323: break;
! 2324: }
! 2325:
! 2326: if (defp->nargs > 0)
! 2327: substitute_pre( defp); /* Do actual arguments */
! 2328: else
! 2329: unget_string( defp->repl, defp->name);
! 2330:
! 2331: if (mcpp_debug & EXPAND)
! 2332: dump_unget( "replace_pre exit");
! 2333: if (defp->nargs >= 0)
! 2334: free( arglist_pre[ 0]);
! 2335: return TRUE;
! 2336: }
! 2337:
! 2338: static void substitute_pre(
! 2339: DEFBUF * defp /* Current macro being replaced */
! 2340: )
! 2341: /*
! 2342: * Stuff the macro body, substituting formal parameters with actual arguments.
! 2343: */
! 2344: {
! 2345: int c; /* Current character */
! 2346: FILEINFO * file; /* Funny #include */
! 2347: char * out_end; /* -> output buffer end */
! 2348: char * in_p; /* -> replacement text */
! 2349: char * out_p; /* -> macro output buff */
! 2350:
! 2351: file = get_file( defp->name, NULL, NULL, (size_t) (NMACWORK + 1), FALSE);
! 2352: /* file == infile */
! 2353: in_p = defp->repl; /* -> macro replacement */
! 2354: out_p = file->buffer; /* -> output buffer */
! 2355: out_end = file->buffer + NMACWORK; /* -> buffer end */
! 2356:
! 2357: while ((c = *in_p++) != EOS) {
! 2358: if (c == MAC_PARM) {
! 2359: c = (*in_p++ & UCHARMAX) - 1; /* Parm number */
! 2360: /*
! 2361: * Substitute formal parameter with actual argument.
! 2362: */
! 2363: if (out_end <= (out_p + strlen( arglist_pre[ c])))
! 2364: goto nospace;
! 2365: out_p = stpcpy( out_p, arglist_pre[ c]);
! 2366: } else {
! 2367: *out_p++ = c;
! 2368: }
! 2369: if (out_end <= out_p)
! 2370: goto nospace;
! 2371: }
! 2372:
! 2373: *out_p = EOS;
! 2374: file->buffer = xrealloc( file->buffer, strlen( file->buffer) + 1);
! 2375: file->bptr = file->buffer; /* Truncate buffer */
! 2376: if (mcpp_debug & EXPAND)
! 2377: dump_string( "substitute_pre macroline", file->buffer);
! 2378: return;
! 2379:
! 2380: nospace:
! 2381: *out_p = EOS;
! 2382: diag_macro( CERROR, macbuf_overflow, defp->name, 0L, file->buffer, defp
! 2383: , NULL);
! 2384: longjmp( jump, 1);
! 2385: }
! 2386:
! 2387:
! 2388: /*
! 2389: * C O M M O N R O U T I N E S
! 2390: * f o r S T A N D A R D a n d p r e - S T A N D A R D M o d e s
! 2391: */
! 2392:
! 2393: static int collect_args(
! 2394: const DEFBUF * defp, /* Definition of the macro */
! 2395: char ** arglist, /* Pointers to actual arguments */
! 2396: int m_num /* Index into mac_inf[] */
! 2397: )
! 2398: /*
! 2399: * Collect the actual arguments for the macro, checking for correct number
! 2400: * of arguments.
! 2401: * Variable arguments (on Standard modes) are read as a merged argument.
! 2402: * Return number of real arguments, or ARG_ERROR on error of unterminated
! 2403: * macro.
! 2404: * collect_args() may read over to the next line unless 'in_directive' is
! 2405: * set to TRUE.
! 2406: * collect_args() may read over into file->parent to complete a macro call
! 2407: * unless stopped by RT_END (provided the "file" is macro). This is a key
! 2408: * trick of STD mode macro expansion. Meanwhile, POST_STD mode limits the
! 2409: * arguments in the "file" (macro or not).
! 2410: * Note: arglist[ n] may be reallocated by collect_args().
! 2411: */
! 2412: {
! 2413: const char * name = defp->name;
! 2414: char * argp = arglist[ 0]; /* Pointer to an argument */
! 2415: char * arg_end; /* End of arguments buffer */
! 2416: char * valid_argp = NULL; /* End of valid arguments */
! 2417: char * sequence; /* Token sequence for diagnostics */
! 2418: char * seq; /* Current pointer into 'sequence' */
! 2419: char * seq_end; /* Limit of buffer */
! 2420: int args; /* Number of arguments expected */
! 2421: int nargs = 0; /* Number of collected args */
! 2422: int var_arg = defp->nargs & VA_ARGS; /* Variable args */
! 2423: int more_to_come = FALSE; /* Next argument is expected*/
! 2424: LOCATION * locs; /* Location of args in source file */
! 2425: LOCATION * loc; /* Current locs */
! 2426: MAGIC_SEQ mgc_prefix; /* MAC_INF seqs and spaces preceding an arg */
! 2427: int c;
! 2428:
! 2429: if (mcpp_debug & EXPAND)
! 2430: dump_unget( "collect_args entry");
! 2431: args = (defp->nargs == DEF_PRAGMA) ? 1 : (defp->nargs & ~AVA_ARGS);
! 2432: if (args == 0) /* Need no argument */
! 2433: valid_argp = argp;
! 2434: *argp = EOS; /* Make sure termination */
! 2435: arg_end = argp + NMACWORK/2;
! 2436: seq = sequence = arg_end + IDMAX; /* Use latter half of argp */
! 2437: seq_end = seq + NMACWORK/2;
! 2438: seq = stpcpy( seq, name);
! 2439: *seq++ = '(';
! 2440: if (mcpp_mode == STD) {
! 2441: /*
! 2442: * in_getarg is set TRUE while getting macro arguments, for the sake
! 2443: * of diagnostic's convenience. in_getarg is used only in STD mode.
! 2444: */
! 2445: in_getarg = TRUE;
! 2446: if (trace_macro && m_num) {
! 2447: /* #pragma MCPP debug macro_call, and the macro is on source */
! 2448: mac_inf[ m_num].loc_args = loc = locs
! 2449: = (LOCATION *) xmalloc( (sizeof (LOCATION)) * UCHARMAX);
! 2450: memset( loc, 0, (sizeof (LOCATION)) * UCHARMAX);
! 2451: /* 0-clear for default values, including empty argument */
! 2452: }
! 2453: }
! 2454:
! 2455: while (1) {
! 2456: memset( &mgc_prefix, 0, sizeof (MAGIC_SEQ));
! 2457: c = squeeze_ws( &seq, NULL
! 2458: , (trace_macro && m_num) ? &mgc_prefix : NULL);
! 2459: /* Skip MAC_INF seqs and white spaces, still remember */
! 2460: /* the sequence in buffer, if necessary. */
! 2461: if (c == ')' || c == ',')
! 2462: scan_token( c, &seq, seq_end); /* Ensure token parsing */
! 2463: else
! 2464: *seq = EOS;
! 2465:
! 2466: switch (c) { /* First character of token */
! 2467: case ')':
! 2468: if (! more_to_come) { /* Zero argument */
! 2469: if (trace_macro && m_num)
! 2470: loc++;
! 2471: break;
! 2472: } /* Else fall through */
! 2473: case ',': /* Empty argument */
! 2474: if (trace_macro && m_num)
! 2475: loc++; /* Advance pointer to infs */
! 2476: if (warn_level & 2)
! 2477: diag_macro( CWARN, empty_arg, sequence, 0L, NULL, defp, NULL);
! 2478: if (standard && var_arg && nargs == args - 1) {
! 2479: /* Variable arguments begin with an empty argument */
! 2480: c = get_an_arg( c, &argp, arg_end, &seq, 1, nargs, &loc
! 2481: , m_num, (trace_macro && m_num) ? &mgc_prefix : NULL);
! 2482: } else {
! 2483: if (mcpp_mode == STD)
! 2484: *argp++ = RT_END;
! 2485: *argp++ = EOS;
! 2486: }
! 2487: if (++nargs == args)
! 2488: valid_argp = argp;
! 2489: if (c == ',') {
! 2490: more_to_come = TRUE;
! 2491: continue;
! 2492: } else { /* ')' */
! 2493: break;
! 2494: }
! 2495: case '\n': /* Unterminated macro call in directive line*/
! 2496: unget_ch(); /* Fall through */
! 2497: case RT_END: /* Error of missing ')' */
! 2498: diag_macro( CERROR, unterm_macro, sequence, 0L, NULL, defp, NULL);
! 2499: /* Fall through */
! 2500: case CHAR_EOF: /* End of file in macro call*/
! 2501: nargs = ARG_ERROR;
! 2502: goto arg_ret; /* Diagnosed by at_eof() */
! 2503: default: /* Nomal argument */
! 2504: break;
! 2505: }
! 2506:
! 2507: if (c == ')') /* At end of all args */
! 2508: break;
! 2509:
! 2510: c = get_an_arg( c, &argp, arg_end, &seq
! 2511: , (var_arg && nargs == args - 1) ? 1 : 0, nargs, &loc
! 2512: , m_num, (trace_macro && m_num) ? &mgc_prefix : NULL);
! 2513:
! 2514: if (++nargs == args)
! 2515: valid_argp = argp; /* End of valid arguments */
! 2516: if (c == ')')
! 2517: break;
! 2518: if (c == 0) { /* End of file */
! 2519: nargs = ARG_ERROR;
! 2520: goto arg_ret; /* Diagnosed by at_eof() */
! 2521: }
! 2522: if (c == -1) { /* Untermanated macro call */
! 2523: diag_macro( CERROR, unterm_macro, sequence, 0L, NULL, defp, NULL);
! 2524: nargs = ARG_ERROR;
! 2525: goto arg_ret;
! 2526: }
! 2527: more_to_come = (c == ',');
! 2528: } /* Collected all arguments */
! 2529:
! 2530: if (nargs == 0 && args == 1) { /* Only and empty argument */
! 2531: if (warn_level & 2)
! 2532: diag_macro( CWARN, empty_arg, sequence, 0L, NULL, defp, NULL);
! 2533: } else if (nargs != args) { /* Wrong number of arguments*/
! 2534: if (mcpp_mode != OLD_PREP || (warn_level & 1)) {
! 2535: if ((standard && var_arg && (nargs == args - 1))
! 2536: /* Absence of variable arguments */
! 2537: || (mcpp_mode == OLD_PREP)) {
! 2538: if (warn_level & 1)
! 2539: diag_macro( CWARN, narg_error, nargs < args ? "Less"
! 2540: : "More", (long) args, sequence, defp, NULL);
! 2541: } else {
! 2542: diag_macro( CERROR, narg_error, nargs < args ? "Less" : "More"
! 2543: , (long) args, sequence, defp, NULL);
! 2544: }
! 2545: }
! 2546: }
! 2547: if (args < nargs) {
! 2548: argp = valid_argp; /* Truncate excess arguments*/
! 2549: } else {
! 2550: for (c = nargs; c < args; c++) {
! 2551: if (mcpp_mode == STD)
! 2552: *argp++ = RT_END; /* For rescan() */
! 2553: *argp++ = EOS; /* Missing arguments */
! 2554: }
! 2555: if (c == 0)
! 2556: argp++; /* Ensure positive length */
! 2557: }
! 2558: arglist[ 0] = argp
! 2559: = xrealloc( arglist[ 0], (size_t) (argp - arglist[ 0]));
! 2560: /* Use memory sparingly */
! 2561: for (c = 1; c < args; c++)
! 2562: arglist[ c] = argp += strlen( argp) + 1;
! 2563: if (trace_macro && m_num)
! 2564: mac_inf[ m_num].loc_args /* Truncate excess memory */
! 2565: = (LOCATION *) xrealloc( (char *) locs
! 2566: , (loc - locs) * sizeof (LOCATION));
! 2567:
! 2568: if (mcpp_debug & EXPAND) {
! 2569: if (nargs > 0) {
! 2570: if (nargs > args)
! 2571: nargs = args;
! 2572: dump_args( "collect_args exit", nargs, (const char **) arglist);
! 2573: }
! 2574: dump_unget( "collect_args exit");
! 2575: }
! 2576: arg_ret:
! 2577: if (mcpp_mode == STD)
! 2578: in_getarg = FALSE;
! 2579: /* Return number of found arguments for function-like macro at most */
! 2580: /* defp->nargs, or return defp->nargs for object-like macro. */
! 2581: return defp->nargs <= DEF_NOARGS ? defp->nargs : nargs;
! 2582: }
! 2583:
! 2584: static int get_an_arg(
! 2585: int c,
! 2586: char ** argpp, /* Address of pointer into argument list */
! 2587: char * arg_end, /* End of argument list buffer */
! 2588: char ** seqp, /* Buffer for diagnostics */
! 2589: int var_arg, /* 1 on __VA_ARGS__, 0 on others*/
! 2590: int nargs, /* Argument number */
! 2591: LOCATION ** locp, /* Where to save location infs */
! 2592: int m_num, /* Macro number to trace */
! 2593: MAGIC_SEQ * mgc_prefix /* White space and magics leading to argument */
! 2594: )
! 2595: /*
! 2596: * Get an argument of macro into '*argpp', return the next punctuator.
! 2597: * Variable arguments are read as a merged argument.
! 2598: * Note: nargs, locp and m_num are used only in macro trace mode of
! 2599: * '#pragma MCPP debug macro_call' or -K option.
! 2600: */
! 2601: {
! 2602: struct {
! 2603: int n_par;
! 2604: int n_in_src;
! 2605: } n_paren[ 16];
! 2606: int num_paren = 0;
! 2607: int end_an_arg = FALSE; /* End-of-an-arg flag */
! 2608: int paren = var_arg; /* For embedded ()'s */
! 2609: int token_type;
! 2610: char * prevp;
! 2611: char * argp = *argpp;
! 2612: int trace_arg = 0; /* Enable tracing arg */
! 2613: LINE_COL s_line_col, e_line_col; /* Location of macro in an argument */
! 2614: MAGIC_SEQ mgc_seq; /* Magic seqs and spaces succeeding an arg */
! 2615: size_t len;
! 2616:
! 2617: if (trace_macro) {
! 2618: trace_arg = m_num && infile->fp;
! 2619: if (m_num) {
! 2620: if (trace_arg) { /* The macro call is in source */
! 2621: s_line_col.line = src_line;
! 2622: s_line_col.col = infile->bptr - infile->buffer - 1;
! 2623: /* '-1': bptr is one byte passed beginning of the token */
! 2624: get_src_location( & s_line_col);
! 2625: (*locp)->start_line = s_line_col.line;
! 2626: (*locp)->start_col = s_line_col.col;
! 2627: e_line_col = s_line_col;
! 2628: /* Save the location, */
! 2629: /* also for end of arg in case of empty arg*/
! 2630: memset( n_paren, 0, sizeof (n_paren));
! 2631: }
! 2632: *argp++ = MAC_INF;
! 2633: *argp++ = MAC_ARG_START;
! 2634: *argp++ = (m_num / UCHARMAX) + 1;
! 2635: *argp++ = (m_num % UCHARMAX) + 1;
! 2636: *argp++ = nargs + 1;
! 2637: /* Argument number internally starts at 1 */
! 2638: if (mgc_prefix->magic_start) {
! 2639: /* Copy the preceding magics, if any */
! 2640: len = mgc_prefix->magic_end - mgc_prefix->magic_start;
! 2641: memcpy( argp, mgc_prefix->magic_start, len);
! 2642: argp += len;
! 2643: }
! 2644: }
! 2645: memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
! 2646: }
! 2647:
! 2648: while (1) {
! 2649: if (c == '\n' /* In control line */
! 2650: || c == RT_END) { /* Boundary of rescan (in STD mode) */
! 2651: if (c == '\n')
! 2652: unget_ch();
! 2653: break;
! 2654: }
! 2655: if (trace_arg) { /* Save the location */
! 2656: s_line_col.line = src_line; /* of the token */
! 2657: s_line_col.col = infile->bptr - infile->buffer - 1;
! 2658: }
! 2659: token_type = scan_token( c, (prevp = argp, &argp), arg_end);
! 2660: /* Scan the next token */
! 2661: switch (c) {
! 2662: case '(': /* Worry about balance */
! 2663: paren++; /* To know about commas */
! 2664: break;
! 2665: case ')': /* Other side too */
! 2666: if (paren-- == var_arg) /* At the end? */
! 2667: end_an_arg = TRUE; /* Else more to come */
! 2668: if (trace_arg) {
! 2669: if (num_paren && paren == n_paren[ num_paren].n_par) {
! 2670: /* Maybe corresponding parentheses for the macro in arg */
! 2671: int src_n;
! 2672: src_n = n_paren[ num_paren].n_in_src;
! 2673: in_src[ src_n].end_line = s_line_col.line;
! 2674: in_src[ src_n].end_col = s_line_col.col + 1;
! 2675: num_paren--;
! 2676: }
! 2677: }
! 2678: break;
! 2679: case ',':
! 2680: if (paren == 0) /* Comma delimits arg */
! 2681: end_an_arg = TRUE;
! 2682: break;
! 2683: case MAC_INF : /* Copy magics as they are */
! 2684: switch (*argp++ = get_ch()) {
! 2685: case MAC_ARG_START :
! 2686: *argp++ = get_ch();
! 2687: /* Fall through */
! 2688: case MAC_CALL_START :
! 2689: *argp++ = get_ch();
! 2690: *argp++ = get_ch();
! 2691: break;
! 2692: case MAC_ARG_END :
! 2693: if (! option_flags.v)
! 2694: break;
! 2695: else
! 2696: *argp++ = get_ch();
! 2697: /* Fall through */
! 2698: case MAC_CALL_END :
! 2699: if (option_flags.v) {
! 2700: *argp++ = get_ch();
! 2701: *argp++ = get_ch();
! 2702: }
! 2703: break;
! 2704: }
! 2705: break;
! 2706: case CHAR_EOF : /* Unexpected EOF */
! 2707: return 0;
! 2708: default : /* Any token */
! 2709: if (mcpp_mode == STD && token_type == NAM
! 2710: && c != IN_SRC && c != DEF_MAGIC && infile->fp) {
! 2711: len = trace_arg ? IN_SRC_LEN : 1;
! 2712: memmove( prevp + len, prevp, (size_t) (argp - prevp));
! 2713: argp += len;
! 2714: *prevp = IN_SRC;
! 2715: /* Mark that the name is read from source file */
! 2716: if (trace_arg) {
! 2717: DEFBUF * defp;
! 2718:
! 2719: defp = look_id( prevp + IN_SRC_LEN);
! 2720: if (in_src_num >= MAX_IN_SRC_NUM - 1) {
! 2721: cerror(
! 2722: "Too many names in arguments tracing %s" /* _E_ */
! 2723: , defp ? defp->name : null, 0L, NULL);
! 2724: return 0;
! 2725: } else if (++in_src_num > max_in_src_num) {
! 2726: size_t old_len;
! 2727: old_len = sizeof (LOCATION) * max_in_src_num;
! 2728: /* Enlarge the array */
! 2729: in_src = (LOCATION *) xrealloc( (char *) in_src
! 2730: , old_len * 2);
! 2731: /* Have to initialize the enlarged area */
! 2732: memset( in_src + max_in_src_num, 0, old_len);
! 2733: max_in_src_num *= 2;
! 2734: }
! 2735: /* Insert the identifier number in 2-bytes-encoding */
! 2736: *(prevp + 1) = (in_src_num / UCHARMAX) + 1;
! 2737: *(prevp + 2) = (in_src_num % UCHARMAX) + 1;
! 2738: if (defp) { /* Macro name in arg */
! 2739: in_src[ in_src_num].start_line = s_line_col.line;
! 2740: in_src[ in_src_num].start_col = s_line_col.col;
! 2741: /* For object-like macro, also for function-like */
! 2742: /* macro in case of parens are not found. */
! 2743: in_src[ in_src_num].end_line = s_line_col.line;
! 2744: in_src[ in_src_num].end_col
! 2745: = infile->bptr - infile->buffer;
! 2746: if (defp->nargs >= 0) {
! 2747: /* Function-like macro: search parentheses */
! 2748: n_paren[ ++num_paren].n_par = paren;
! 2749: n_paren[ num_paren].n_in_src = in_src_num;
! 2750: }
! 2751: } /* Else in_src[ in_src_num].* are 0L */
! 2752: }
! 2753: }
! 2754: break;
! 2755: } /* End of switch */
! 2756:
! 2757: if (end_an_arg) /* End of an argument */
! 2758: break;
! 2759: if (trace_arg) { /* Save the location */
! 2760: e_line_col.line = src_line; /* before spaces */
! 2761: e_line_col.col = infile->bptr - infile->buffer;
! 2762: }
! 2763: memset( &mgc_seq, 0, sizeof (MAGIC_SEQ));
! 2764: c = squeeze_ws( &argp, NULL, &mgc_seq);
! 2765: /* To the next token */
! 2766: } /* Collected an argument*/
! 2767:
! 2768: *argp = EOS;
! 2769: *seqp = stpcpy( *seqp, *argpp); /* Save the sequence */
! 2770: if (c == '\n' || c == RT_END)
! 2771: return -1; /* Unterminated macro */
! 2772: argp--; /* Remove the punctuator*/
! 2773: if (mgc_seq.space)
! 2774: --argp; /* Remove trailing space */
! 2775: if (mcpp_mode == STD) {
! 2776: if (trace_macro && m_num) {
! 2777: if (trace_arg) { /* Location of end of an arg */
! 2778: get_src_location( & e_line_col);
! 2779: (*locp)->end_line = e_line_col.line;
! 2780: (*locp)->end_col = e_line_col.col;
! 2781: }
! 2782: (*locp)++; /* Advance pointer even if !trace_arg */
! 2783: *argp++ = MAC_INF;
! 2784: *argp++ = MAC_ARG_END;
! 2785: if (option_flags.v) {
! 2786: *argp++ = (m_num / UCHARMAX) + 1;
! 2787: *argp++ = (m_num % UCHARMAX) + 1;
! 2788: *argp++ = nargs + 1;
! 2789: *argp = EOS;
! 2790: *argpp = chk_magic_balance( *argpp, argp, TRUE, FALSE);
! 2791: /* Check a stray magic caused by abnormal macro */
! 2792: /* and move it to an edge if found. */
! 2793: }
! 2794: }
! 2795: *argp++ = RT_END; /* For rescan() */
! 2796: }
! 2797: *argp++ = EOS; /* Terminate an argument*/
! 2798: *argpp = argp;
! 2799: return c;
! 2800: }
! 2801:
! 2802: static int squeeze_ws(
! 2803: char ** out, /* Pointer to output pointer */
! 2804: char ** endf, /* Pointer to end of infile data*/
! 2805: MAGIC_SEQ * mgc_seq /* Sequence of MAC_INFs and space */
! 2806: /* mgc_seq should be initialized in the calling routine */
! 2807: )
! 2808: /*
! 2809: * Squeeze white spaces to one space.
! 2810: * White spaces are ' ' (and possibly '\t', when keep_spaces == TRUE. Note
! 2811: * that '\r', '\v', '\f' have been already converted to ' ' by get_ch()),
! 2812: * and '\n' unless in_directive is set.
! 2813: * COM_SEP is skipped. TOK_SEPs are squeezed to one TOK_SEP.
! 2814: * Copy MAC_INF and its sequences as they are.
! 2815: * If white spaces are found and 'out' is not NULL, write a space to *out and
! 2816: * increment *out.
! 2817: * Record start and end of MAC_INF sequences and whether space is found or
! 2818: * not for a convenience of get_an_arg().
! 2819: * Return the next character.
! 2820: */
! 2821: {
! 2822: int c;
! 2823: int space = 0;
! 2824: int tsep = 0;
! 2825: FILEINFO * file = infile;
! 2826: FILE * fp = infile->fp;
! 2827: int end_of_file = (out && endf) ? FALSE : TRUE;
! 2828:
! 2829: while (((char_type[ c = get_ch()] & SPA) && (! standard
! 2830: || (mcpp_mode == POST_STD && file == infile)
! 2831: || (mcpp_mode == STD
! 2832: && ((macro_line != 0 && macro_line != MACRO_ERROR)
! 2833: || file == infile))))
! 2834: || c == MAC_INF) {
! 2835: if (! end_of_file && file != infile) { /* Infile has been read over*/
! 2836: *endf = *out; /* Remember the location */
! 2837: end_of_file = TRUE;
! 2838: }
! 2839: if (c == '\n' && in_directive) /* If scanning control line */
! 2840: break; /* do not skip newline. */
! 2841: switch (c) {
! 2842: case '\n':
! 2843: space++;
! 2844: wrong_line = TRUE;
! 2845: break;
! 2846: case TOK_SEP:
! 2847: if (mcpp_mode == STD)
! 2848: tsep++;
! 2849: continue; /* Skip COM_SEP in OLD_PREP mode */
! 2850: case MAC_INF : /* Copy magics as they are, or skip */
! 2851: if (mgc_seq && ! mgc_seq->magic_start)
! 2852: mgc_seq->magic_start = *out;
! 2853: /* First occurence of magic seq */
! 2854: if (out)
! 2855: *(*out)++ = c;
! 2856: c = get_ch();
! 2857: if (out)
! 2858: *(*out)++ = c;
! 2859: switch (c) {
! 2860: case MAC_ARG_START :
! 2861: c = get_ch();
! 2862: if (out)
! 2863: *(*out)++ = c;
! 2864: /* Fall through */
! 2865: case MAC_CALL_START :
! 2866: c = get_ch();
! 2867: if (out)
! 2868: *(*out)++ = c;
! 2869: c = get_ch();
! 2870: if (out)
! 2871: *(*out)++ = c;
! 2872: break;
! 2873: case MAC_ARG_END :
! 2874: if (! option_flags.v) {
! 2875: break;
! 2876: } else {
! 2877: c = get_ch();
! 2878: if (out)
! 2879: *(*out)++ = c;
! 2880: /* Fall through */
! 2881: }
! 2882: case MAC_CALL_END :
! 2883: if (option_flags.v) {
! 2884: c = get_ch();
! 2885: if (out)
! 2886: *(*out)++ = c;
! 2887: c = get_ch();
! 2888: if (out)
! 2889: *(*out)++ = c;
! 2890: }
! 2891: break;
! 2892: }
! 2893: if (mgc_seq) /* Remember end of last magic seq */
! 2894: mgc_seq->magic_end = *out;
! 2895: break;
! 2896: default:
! 2897: space++;
! 2898: break;
! 2899: }
! 2900: }
! 2901:
! 2902: if (out) {
! 2903: if (space) { /* Write a space to output pointer */
! 2904: *(*out)++ = ' '; /* and increment the pointer. */
! 2905: if (mgc_seq)
! 2906: mgc_seq->space = TRUE;
! 2907: }
! 2908: if (tsep && !space) /* Needs to preserve token separator*/
! 2909: *(*out)++ = TOK_SEP;
! 2910: **out = EOS;
! 2911: }
! 2912: if (mcpp_mode == POST_STD && file != infile) {
! 2913: unget_ch(); /* Arguments cannot cross "file"s */
! 2914: c = fp ? CHAR_EOF : RT_END; /* EOF is diagnosed by at_eof() */
! 2915: } else if (mcpp_mode == STD && macro_line == MACRO_ERROR
! 2916: && file != infile) { /* EOF */
! 2917: unget_ch(); /* diagnosed by at_eof() or only */
! 2918: c = CHAR_EOF; /* name of a function-like macro. */
! 2919: } /* at_eof() resets macro_line on error */
! 2920: return c; /* Return the next character */
! 2921: }
! 2922:
! 2923: static void skip_macro( void)
! 2924: /*
! 2925: * Clear the stacked (i.e. half-expanded) macro, called on macro error.
! 2926: */
! 2927: {
! 2928: if (infile == NULL) /* End of input */
! 2929: return;
! 2930: if (infile->fp) /* Source file */
! 2931: return;
! 2932: while (infile->fp == NULL) { /* Stacked stuff */
! 2933: infile->bptr += strlen( infile->bptr);
! 2934: get_ch(); /* To the parent "file" */
! 2935: }
! 2936: unget_ch();
! 2937: }
! 2938:
! 2939: static void diag_macro(
! 2940: int severity, /* Error or warning */
! 2941: const char * format,
! 2942: const char * arg1,
! 2943: long arg2,
! 2944: const char * arg3,
! 2945: const DEFBUF * defp1, /* Macro causing the problem 1 */
! 2946: const DEFBUF * defp2 /* 2 */
! 2947: )
! 2948: /*
! 2949: * Supplement macro information for diagnostic.
! 2950: */
! 2951: {
! 2952:
! 2953: if (defp1 && defp1->name != macro_name)
! 2954: expanding( defp1->name, FALSE);
! 2955: /* Inform of the problematic macro call */
! 2956: if (defp2 && defp2->name != macro_name)
! 2957: expanding( defp2->name, FALSE);
! 2958: if (severity == CERROR)
! 2959: cerror( format, arg1, arg2, arg3);
! 2960: else
! 2961: cwarn( format, arg1, arg2, arg3);
! 2962: }
! 2963:
! 2964: static void dump_args(
! 2965: const char * why,
! 2966: int nargs,
! 2967: const char ** arglist
! 2968: )
! 2969: /*
! 2970: * Dump arguments list.
! 2971: */
! 2972: {
! 2973: int i;
! 2974:
! 2975: mcpp_fprintf( DBG, "dump of %d actual arguments %s\n", nargs, why);
! 2976: for (i = 0; i < nargs; i++) {
! 2977: mcpp_fprintf( DBG, "arg[%d]", i + 1);
! 2978: dump_string( NULL, arglist[ i]);
! 2979: }
! 2980: }
! 2981:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>