1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir #include <stdio.h> 29*cdf0e10cSrcweir #include <ctype.h> 30*cdf0e10cSrcweir #include "cppdef.h" 31*cdf0e10cSrcweir #include "cpp.h" 32*cdf0e10cSrcweir /* 33*cdf0e10cSrcweir * parm[], parmp, and parlist[] are used to store #define() argument 34*cdf0e10cSrcweir * lists. nargs contains the actual number of parameters stored. 35*cdf0e10cSrcweir */ 36*cdf0e10cSrcweir static char parm[NPARMWORK + 1]; /* define param work buffer */ 37*cdf0e10cSrcweir static char *parmp; /* Free space in parm */ 38*cdf0e10cSrcweir static char *parlist[LASTPARM]; /* -> start of each parameter */ 39*cdf0e10cSrcweir static int nargs; /* Parameters for this macro */ 40*cdf0e10cSrcweir 41*cdf0e10cSrcweir void InitCpp4() 42*cdf0e10cSrcweir { 43*cdf0e10cSrcweir int i; 44*cdf0e10cSrcweir for( i = 0; i < NPARMWORK; i++ ) 45*cdf0e10cSrcweir parm[ i ] = 0; 46*cdf0e10cSrcweir for( i = 0; i < LASTPARM; i++ ) 47*cdf0e10cSrcweir parlist[ i ] = NULL; 48*cdf0e10cSrcweir 49*cdf0e10cSrcweir nargs = 0; 50*cdf0e10cSrcweir } 51*cdf0e10cSrcweir 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir void dodefine() 54*cdf0e10cSrcweir /* 55*cdf0e10cSrcweir * Called from control when a #define is scanned. This module 56*cdf0e10cSrcweir * parses formal parameters and the replacement string. When 57*cdf0e10cSrcweir * the formal parameter name is encountered in the replacement 58*cdf0e10cSrcweir * string, it is replaced by a character in the range 128 to 59*cdf0e10cSrcweir * 128+NPARAM (this allows up to 32 parameters within the 60*cdf0e10cSrcweir * Dec Multinational range). If cpp is ported to an EBCDIC 61*cdf0e10cSrcweir * machine, you will have to make other arrangements. 62*cdf0e10cSrcweir * 63*cdf0e10cSrcweir * There is some special case code to distinguish 64*cdf0e10cSrcweir * #define foo bar 65*cdf0e10cSrcweir * from #define foo() bar 66*cdf0e10cSrcweir * 67*cdf0e10cSrcweir * Also, we make sure that 68*cdf0e10cSrcweir * #define foo foo 69*cdf0e10cSrcweir * expands to "foo" but doesn't put cpp into an infinite loop. 70*cdf0e10cSrcweir * 71*cdf0e10cSrcweir * A warning message is printed if you redefine a symbol to a 72*cdf0e10cSrcweir * different text. I.e, 73*cdf0e10cSrcweir * #define foo 123 74*cdf0e10cSrcweir * #define foo 123 75*cdf0e10cSrcweir * is ok, but 76*cdf0e10cSrcweir * #define foo 123 77*cdf0e10cSrcweir * #define foo +123 78*cdf0e10cSrcweir * is not. 79*cdf0e10cSrcweir * 80*cdf0e10cSrcweir * The following subroutines are called from define(): 81*cdf0e10cSrcweir * checkparm called when a token is scanned. It checks through the 82*cdf0e10cSrcweir * array of formal parameters. If a match is found, the 83*cdf0e10cSrcweir * token is replaced by a control byte which will be used 84*cdf0e10cSrcweir * to locate the parameter when the macro is expanded. 85*cdf0e10cSrcweir * textput puts a string in the macro work area (parm[]), updating 86*cdf0e10cSrcweir * parmp to point to the first free byte in parm[]. 87*cdf0e10cSrcweir * textput() tests for work buffer overflow. 88*cdf0e10cSrcweir * charput puts a single character in the macro work area (parm[]) 89*cdf0e10cSrcweir * in a manner analogous to textput(). 90*cdf0e10cSrcweir */ 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir register int c; 93*cdf0e10cSrcweir register DEFBUF *dp; /* -> new definition */ 94*cdf0e10cSrcweir int isredefine; /* TRUE if redefined */ 95*cdf0e10cSrcweir char *old = 0; /* Remember redefined */ 96*cdf0e10cSrcweir 97*cdf0e10cSrcweir if (type[(c = skipws())] != LET) 98*cdf0e10cSrcweir goto bad_define; 99*cdf0e10cSrcweir isredefine = FALSE; /* Set if redefining */ 100*cdf0e10cSrcweir if ((dp = lookid(c)) == NULL) /* If not known now */ 101*cdf0e10cSrcweir dp = defendel(token, FALSE); /* Save the name */ 102*cdf0e10cSrcweir else { /* It's known: */ 103*cdf0e10cSrcweir isredefine = TRUE; /* Remember this fact */ 104*cdf0e10cSrcweir old = dp->repl; /* Remember replacement */ 105*cdf0e10cSrcweir dp->repl = NULL; /* No replacement now */ 106*cdf0e10cSrcweir } 107*cdf0e10cSrcweir parlist[0] = parmp = parm; /* Setup parm buffer */ 108*cdf0e10cSrcweir if ((c = get()) == '(') { /* With arguments? */ 109*cdf0e10cSrcweir nargs = 0; /* Init formals counter */ 110*cdf0e10cSrcweir do { /* Collect formal parms */ 111*cdf0e10cSrcweir if (nargs >= LASTPARM) 112*cdf0e10cSrcweir cfatal("Too many arguments for macro", NULLST); 113*cdf0e10cSrcweir else if ((c = skipws()) == ')') 114*cdf0e10cSrcweir break; /* Got them all */ 115*cdf0e10cSrcweir else if (type[c] != LET) /* Bad formal syntax */ 116*cdf0e10cSrcweir goto bad_define; 117*cdf0e10cSrcweir scanid(c); /* Get the formal param */ 118*cdf0e10cSrcweir parlist[nargs++] = parmp; /* Save its start */ 119*cdf0e10cSrcweir textput(token); /* Save text in parm[] */ 120*cdf0e10cSrcweir } while ((c = skipws()) == ','); /* Get another argument */ 121*cdf0e10cSrcweir if (c != ')') /* Must end at ) */ 122*cdf0e10cSrcweir goto bad_define; 123*cdf0e10cSrcweir c = ' '; /* Will skip to body */ 124*cdf0e10cSrcweir } 125*cdf0e10cSrcweir else { 126*cdf0e10cSrcweir /* 127*cdf0e10cSrcweir * DEF_NOARGS is needed to distinguish between 128*cdf0e10cSrcweir * "#define foo" and "#define foo()". 129*cdf0e10cSrcweir */ 130*cdf0e10cSrcweir nargs = DEF_NOARGS; /* No () parameters */ 131*cdf0e10cSrcweir } 132*cdf0e10cSrcweir if (type[c] == SPA) /* At whitespace? */ 133*cdf0e10cSrcweir c = skipws(); /* Not any more. */ 134*cdf0e10cSrcweir workp = work; /* Replacement put here */ 135*cdf0e10cSrcweir inmacro = TRUE; /* Keep \<newline> now */ 136*cdf0e10cSrcweir while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ 137*cdf0e10cSrcweir #if OK_CONCAT 138*cdf0e10cSrcweir #if COMMENT_INVISIBLE 139*cdf0e10cSrcweir if (c == COM_SEP) { /* Token concatenation? */ 140*cdf0e10cSrcweir save(TOK_SEP); /* Stuff a delimiter */ 141*cdf0e10cSrcweir c = get(); 142*cdf0e10cSrcweir #else 143*cdf0e10cSrcweir if (c == '#') { /* Token concatenation? */ 144*cdf0e10cSrcweir while (workp > work && type[(int)workp[-1]] == SPA) 145*cdf0e10cSrcweir --workp; /* Erase leading spaces */ 146*cdf0e10cSrcweir save(TOK_SEP); /* Stuff a delimiter */ 147*cdf0e10cSrcweir c = skipws(); /* Eat whitespace */ 148*cdf0e10cSrcweir #endif 149*cdf0e10cSrcweir if (type[c] == LET) /* Another token here? */ 150*cdf0e10cSrcweir ; /* Stuff it normally */ 151*cdf0e10cSrcweir else if (type[c] == DIG) { /* Digit string after? */ 152*cdf0e10cSrcweir while (type[c] == DIG) { /* Stuff the digits */ 153*cdf0e10cSrcweir save(c); 154*cdf0e10cSrcweir c = get(); 155*cdf0e10cSrcweir } 156*cdf0e10cSrcweir save(TOK_SEP); /* Delimit 2nd token */ 157*cdf0e10cSrcweir } 158*cdf0e10cSrcweir else { 159*cdf0e10cSrcweir #if ! COMMENT_INVISIBLE 160*cdf0e10cSrcweir ciwarn("Strange character after # (%d.)", c); 161*cdf0e10cSrcweir #endif 162*cdf0e10cSrcweir } 163*cdf0e10cSrcweir continue; 164*cdf0e10cSrcweir } 165*cdf0e10cSrcweir #endif 166*cdf0e10cSrcweir switch (type[c]) { 167*cdf0e10cSrcweir case LET: 168*cdf0e10cSrcweir checkparm(c, dp); /* Might be a formal */ 169*cdf0e10cSrcweir break; 170*cdf0e10cSrcweir 171*cdf0e10cSrcweir case DIG: /* Number in mac. body */ 172*cdf0e10cSrcweir case DOT: /* Maybe a float number */ 173*cdf0e10cSrcweir scannumber(c, save); /* Scan it off */ 174*cdf0e10cSrcweir break; 175*cdf0e10cSrcweir 176*cdf0e10cSrcweir case QUO: /* String in mac. body */ 177*cdf0e10cSrcweir #if STRING_FORMAL 178*cdf0e10cSrcweir stparmscan(c, dp); /* Do string magic */ 179*cdf0e10cSrcweir #else 180*cdf0e10cSrcweir stparmscan(c); 181*cdf0e10cSrcweir #endif 182*cdf0e10cSrcweir break; 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir case BSH: /* Backslash */ 185*cdf0e10cSrcweir save('\\'); 186*cdf0e10cSrcweir if ((c = get()) == '\n') 187*cdf0e10cSrcweir wrongline = TRUE; 188*cdf0e10cSrcweir save(c); 189*cdf0e10cSrcweir break; 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir case SPA: /* Absorb whitespace */ 192*cdf0e10cSrcweir /* 193*cdf0e10cSrcweir * Note: the "end of comment" marker is passed on 194*cdf0e10cSrcweir * to allow comments to separate tokens. 195*cdf0e10cSrcweir */ 196*cdf0e10cSrcweir if (workp[-1] == ' ') /* Absorb multiple */ 197*cdf0e10cSrcweir break; /* spaces */ 198*cdf0e10cSrcweir else if (c == '\t') 199*cdf0e10cSrcweir c = ' '; /* Normalize tabs */ 200*cdf0e10cSrcweir /* Fall through to store character */ 201*cdf0e10cSrcweir default: /* Other character */ 202*cdf0e10cSrcweir save(c); 203*cdf0e10cSrcweir break; 204*cdf0e10cSrcweir } 205*cdf0e10cSrcweir c = get(); 206*cdf0e10cSrcweir } 207*cdf0e10cSrcweir inmacro = FALSE; /* Stop newline hack */ 208*cdf0e10cSrcweir unget(); /* For control check */ 209*cdf0e10cSrcweir if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ 210*cdf0e10cSrcweir workp--; 211*cdf0e10cSrcweir *workp = EOS; /* Terminate work */ 212*cdf0e10cSrcweir dp->repl = savestring(work); /* Save the string */ 213*cdf0e10cSrcweir dp->nargs = nargs; /* Save arg count */ 214*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 215*cdf0e10cSrcweir if (debug) 216*cdf0e10cSrcweir dumpadef("macro definition", dp); 217*cdf0e10cSrcweir else if (bDumpDefs) 218*cdf0e10cSrcweir dumpadef(NULL, dp); 219*cdf0e10cSrcweir #endif 220*cdf0e10cSrcweir if (isredefine) { /* Error if redefined */ 221*cdf0e10cSrcweir if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) 222*cdf0e10cSrcweir || (old == NULL && dp->repl != NULL) 223*cdf0e10cSrcweir || (old != NULL && dp->repl == NULL)) { 224*cdf0e10cSrcweir #ifdef STRICT_UNDEF 225*cdf0e10cSrcweir cerror("Redefining defined variable \"%s\"", dp->name); 226*cdf0e10cSrcweir #else 227*cdf0e10cSrcweir cwarn("Redefining defined variable \"%s\"", dp->name); 228*cdf0e10cSrcweir #endif 229*cdf0e10cSrcweir } 230*cdf0e10cSrcweir if (old != NULL) /* We don't need the */ 231*cdf0e10cSrcweir free(old); /* old definition now. */ 232*cdf0e10cSrcweir } 233*cdf0e10cSrcweir return; 234*cdf0e10cSrcweir 235*cdf0e10cSrcweir bad_define: 236*cdf0e10cSrcweir cerror("#define syntax error", NULLST); 237*cdf0e10cSrcweir inmacro = FALSE; /* Stop <newline> hack */ 238*cdf0e10cSrcweir } 239*cdf0e10cSrcweir 240*cdf0e10cSrcweir void checkparm(int c, DEFBUF* dp) 241*cdf0e10cSrcweir /* 242*cdf0e10cSrcweir * Replace this param if it's defined. Note that the macro name is a 243*cdf0e10cSrcweir * possible replacement token. We stuff DEF_MAGIC in front of the token 244*cdf0e10cSrcweir * which is treated as a LETTER by the token scanner and eaten by 245*cdf0e10cSrcweir * the output routine. This prevents the macro expander from 246*cdf0e10cSrcweir * looping if someone writes "#define foo foo". 247*cdf0e10cSrcweir */ 248*cdf0e10cSrcweir { 249*cdf0e10cSrcweir register int i; 250*cdf0e10cSrcweir register char *cp; 251*cdf0e10cSrcweir 252*cdf0e10cSrcweir scanid(c); /* Get parm to token[] */ 253*cdf0e10cSrcweir for (i = 0; i < nargs; i++) { /* For each argument */ 254*cdf0e10cSrcweir if (streq(parlist[i], token)) { /* If it's known */ 255*cdf0e10cSrcweir #ifdef SOLAR 256*cdf0e10cSrcweir save(DEL); 257*cdf0e10cSrcweir #endif 258*cdf0e10cSrcweir save(i + MAC_PARM); /* Save a magic cookie */ 259*cdf0e10cSrcweir return; /* And exit the search */ 260*cdf0e10cSrcweir } 261*cdf0e10cSrcweir } 262*cdf0e10cSrcweir if (streq(dp->name, token)) /* Macro name in body? */ 263*cdf0e10cSrcweir save(DEF_MAGIC); /* Save magic marker */ 264*cdf0e10cSrcweir for (cp = token; *cp != EOS;) /* And save */ 265*cdf0e10cSrcweir save(*cp++); /* The token itself */ 266*cdf0e10cSrcweir } 267*cdf0e10cSrcweir 268*cdf0e10cSrcweir #if STRING_FORMAL 269*cdf0e10cSrcweir void stparmscan(delim, dp) 270*cdf0e10cSrcweir int delim; 271*cdf0e10cSrcweir register DEFBUF *dp; 272*cdf0e10cSrcweir /* 273*cdf0e10cSrcweir * Scan the string (starting with the given delimiter). 274*cdf0e10cSrcweir * The token is replaced if it is the only text in this string or 275*cdf0e10cSrcweir * character constant. The algorithm follows checkparm() above. 276*cdf0e10cSrcweir * Note that scanstring() has approved of the string. 277*cdf0e10cSrcweir */ 278*cdf0e10cSrcweir { 279*cdf0e10cSrcweir register int c; 280*cdf0e10cSrcweir 281*cdf0e10cSrcweir /* 282*cdf0e10cSrcweir * Warning -- this code hasn't been tested for a while. 283*cdf0e10cSrcweir * It exists only to preserve compatibility with earlier 284*cdf0e10cSrcweir * implementations of cpp. It is not part of the Draft 285*cdf0e10cSrcweir * ANSI Standard C language. 286*cdf0e10cSrcweir */ 287*cdf0e10cSrcweir save(delim); 288*cdf0e10cSrcweir instring = TRUE; 289*cdf0e10cSrcweir while ((c = get()) != delim 290*cdf0e10cSrcweir && c != '\n' 291*cdf0e10cSrcweir && c != EOF_CHAR) { 292*cdf0e10cSrcweir if (type[c] == LET) /* Maybe formal parm */ 293*cdf0e10cSrcweir checkparm(c, dp); 294*cdf0e10cSrcweir else { 295*cdf0e10cSrcweir save(c); 296*cdf0e10cSrcweir if (c == '\\') 297*cdf0e10cSrcweir save(get()); 298*cdf0e10cSrcweir } 299*cdf0e10cSrcweir } 300*cdf0e10cSrcweir instring = FALSE; 301*cdf0e10cSrcweir if (c != delim) 302*cdf0e10cSrcweir cerror("Unterminated string in macro body", NULLST); 303*cdf0e10cSrcweir save(c); 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir #else 306*cdf0e10cSrcweir void stparmscan(int delim) 307*cdf0e10cSrcweir /* 308*cdf0e10cSrcweir * Normal string parameter scan. 309*cdf0e10cSrcweir */ 310*cdf0e10cSrcweir { 311*cdf0e10cSrcweir register char *wp; 312*cdf0e10cSrcweir register int i; 313*cdf0e10cSrcweir 314*cdf0e10cSrcweir wp = workp; /* Here's where it starts */ 315*cdf0e10cSrcweir if (!scanstring(delim, save)) 316*cdf0e10cSrcweir return; /* Exit on scanstring error */ 317*cdf0e10cSrcweir workp[-1] = EOS; /* Erase trailing quote */ 318*cdf0e10cSrcweir wp++; /* -> first string content byte */ 319*cdf0e10cSrcweir for (i = 0; i < nargs; i++) { 320*cdf0e10cSrcweir if (streq(parlist[i], wp)) { 321*cdf0e10cSrcweir #ifdef SOLAR 322*cdf0e10cSrcweir *wp++ = DEL; 323*cdf0e10cSrcweir *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ 324*cdf0e10cSrcweir *wp++ = (char)(i + MAC_PARM); /* Make a formal marker */ 325*cdf0e10cSrcweir *wp = wp[-4]; /* Add on closing quote */ 326*cdf0e10cSrcweir workp = wp + 1; /* Reset string end */ 327*cdf0e10cSrcweir #else 328*cdf0e10cSrcweir *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ 329*cdf0e10cSrcweir *wp++ = (i + MAC_PARM); /* Make a formal marker */ 330*cdf0e10cSrcweir *wp = wp[-3]; /* Add on closing quote */ 331*cdf0e10cSrcweir workp = wp + 1; /* Reset string end */ 332*cdf0e10cSrcweir #endif 333*cdf0e10cSrcweir return; 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir workp[-1] = wp[-1]; /* Nope, reset end quote. */ 337*cdf0e10cSrcweir } 338*cdf0e10cSrcweir #endif 339*cdf0e10cSrcweir 340*cdf0e10cSrcweir void doundef() 341*cdf0e10cSrcweir /* 342*cdf0e10cSrcweir * Remove the symbol from the defined list. 343*cdf0e10cSrcweir * Called from the #control processor. 344*cdf0e10cSrcweir */ 345*cdf0e10cSrcweir { 346*cdf0e10cSrcweir register int c; 347*cdf0e10cSrcweir 348*cdf0e10cSrcweir if (type[(c = skipws())] != LET) 349*cdf0e10cSrcweir cerror("Illegal #undef argument", NULLST); 350*cdf0e10cSrcweir else { 351*cdf0e10cSrcweir scanid(c); /* Get name to token[] */ 352*cdf0e10cSrcweir if (defendel(token, TRUE) == NULL) { 353*cdf0e10cSrcweir #ifdef STRICT_UNDEF 354*cdf0e10cSrcweir cwarn("Symbol \"%s\" not defined in #undef", token); 355*cdf0e10cSrcweir #endif 356*cdf0e10cSrcweir } 357*cdf0e10cSrcweir } 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir void textput(char* text) 361*cdf0e10cSrcweir /* 362*cdf0e10cSrcweir * Put the string in the parm[] buffer. 363*cdf0e10cSrcweir */ 364*cdf0e10cSrcweir { 365*cdf0e10cSrcweir register int size; 366*cdf0e10cSrcweir 367*cdf0e10cSrcweir size = strlen(text) + 1; 368*cdf0e10cSrcweir if ((parmp + size) >= &parm[NPARMWORK]) 369*cdf0e10cSrcweir cfatal("Macro work area overflow", NULLST); 370*cdf0e10cSrcweir else { 371*cdf0e10cSrcweir strcpy(parmp, text); 372*cdf0e10cSrcweir parmp += size; 373*cdf0e10cSrcweir } 374*cdf0e10cSrcweir } 375*cdf0e10cSrcweir 376*cdf0e10cSrcweir void charput(int c) 377*cdf0e10cSrcweir /* 378*cdf0e10cSrcweir * Put the byte in the parm[] buffer. 379*cdf0e10cSrcweir */ 380*cdf0e10cSrcweir { 381*cdf0e10cSrcweir if (parmp >= &parm[NPARMWORK]) 382*cdf0e10cSrcweir cfatal("Macro work area overflow", NULLST); 383*cdf0e10cSrcweir else { 384*cdf0e10cSrcweir *parmp++ = (char)c; 385*cdf0e10cSrcweir } 386*cdf0e10cSrcweir } 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir /* 389*cdf0e10cSrcweir * M a c r o E x p a n s i o n 390*cdf0e10cSrcweir */ 391*cdf0e10cSrcweir 392*cdf0e10cSrcweir static DEFBUF *macro; /* Catches start of infinite macro */ 393*cdf0e10cSrcweir 394*cdf0e10cSrcweir void expand(DEFBUF* tokenp) 395*cdf0e10cSrcweir /* 396*cdf0e10cSrcweir * Expand a macro. Called from the cpp mainline routine (via subroutine 397*cdf0e10cSrcweir * macroid()) when a token is found in the symbol table. It calls 398*cdf0e10cSrcweir * expcollect() to parse actual parameters, checking for the correct number. 399*cdf0e10cSrcweir * It then creates a "file" containing a single line containing the 400*cdf0e10cSrcweir * macro with actual parameters inserted appropriately. This is 401*cdf0e10cSrcweir * "pushed back" onto the input stream. (When the get() routine runs 402*cdf0e10cSrcweir * off the end of the macro line, it will dismiss the macro itself.) 403*cdf0e10cSrcweir */ 404*cdf0e10cSrcweir { 405*cdf0e10cSrcweir register int c; 406*cdf0e10cSrcweir register FILEINFO *file; 407*cdf0e10cSrcweir #ifndef ZTC /* BP */ 408*cdf0e10cSrcweir extern FILEINFO *getfile(); 409*cdf0e10cSrcweir #endif 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 412*cdf0e10cSrcweir if (debug) 413*cdf0e10cSrcweir dumpadef("expand entry", tokenp); 414*cdf0e10cSrcweir #endif 415*cdf0e10cSrcweir /* 416*cdf0e10cSrcweir * If no macro is pending, save the name of this macro 417*cdf0e10cSrcweir * for an eventual error message. 418*cdf0e10cSrcweir */ 419*cdf0e10cSrcweir if (recursion++ == 0) 420*cdf0e10cSrcweir macro = tokenp; 421*cdf0e10cSrcweir else if (recursion == RECURSION_LIMIT) { 422*cdf0e10cSrcweir cerror("Recursive macro definition of \"%s\"", tokenp->name); 423*cdf0e10cSrcweir fprintf(stderr, "(Defined by \"%s\")\n", macro->name); 424*cdf0e10cSrcweir if (rec_recover) { 425*cdf0e10cSrcweir do { 426*cdf0e10cSrcweir c = get(); 427*cdf0e10cSrcweir } while (infile != NULL && infile->fp == NULL); 428*cdf0e10cSrcweir unget(); 429*cdf0e10cSrcweir recursion = 0; 430*cdf0e10cSrcweir return; 431*cdf0e10cSrcweir } 432*cdf0e10cSrcweir } 433*cdf0e10cSrcweir /* 434*cdf0e10cSrcweir * Here's a macro to expand. 435*cdf0e10cSrcweir */ 436*cdf0e10cSrcweir nargs = 0; /* Formals counter */ 437*cdf0e10cSrcweir parmp = parm; /* Setup parm buffer */ 438*cdf0e10cSrcweir switch (tokenp->nargs) { 439*cdf0e10cSrcweir case (-2): /* __LINE__ */ 440*cdf0e10cSrcweir sprintf(work, "%d", line); 441*cdf0e10cSrcweir ungetstring(work); 442*cdf0e10cSrcweir break; 443*cdf0e10cSrcweir 444*cdf0e10cSrcweir case (-3): /* __FILE__ */ 445*cdf0e10cSrcweir for (file = infile; file != NULL; file = file->parent) { 446*cdf0e10cSrcweir if (file->fp != NULL) { 447*cdf0e10cSrcweir sprintf(work, "\"%s\"", (file->progname != NULL) 448*cdf0e10cSrcweir ? file->progname : file->filename); 449*cdf0e10cSrcweir ungetstring(work); 450*cdf0e10cSrcweir break; 451*cdf0e10cSrcweir } 452*cdf0e10cSrcweir } 453*cdf0e10cSrcweir break; 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir default: 456*cdf0e10cSrcweir /* 457*cdf0e10cSrcweir * Nothing funny about this macro. 458*cdf0e10cSrcweir */ 459*cdf0e10cSrcweir if (tokenp->nargs < 0) 460*cdf0e10cSrcweir cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name); 461*cdf0e10cSrcweir while ((c = skipws()) == '\n') /* Look for (, skipping */ 462*cdf0e10cSrcweir wrongline = TRUE; /* spaces and newlines */ 463*cdf0e10cSrcweir if (c != '(') { 464*cdf0e10cSrcweir /* 465*cdf0e10cSrcweir * If the programmer writes 466*cdf0e10cSrcweir * #define foo() ... 467*cdf0e10cSrcweir * ... 468*cdf0e10cSrcweir * foo [no ()] 469*cdf0e10cSrcweir * just write foo to the output stream. 470*cdf0e10cSrcweir */ 471*cdf0e10cSrcweir unget(); 472*cdf0e10cSrcweir cwarn("Macro \"%s\" needs arguments", tokenp->name); 473*cdf0e10cSrcweir fputs(tokenp->name, pCppOut ); 474*cdf0e10cSrcweir return; 475*cdf0e10cSrcweir } 476*cdf0e10cSrcweir else if (expcollect()) { /* Collect arguments */ 477*cdf0e10cSrcweir if (tokenp->nargs != nargs) { /* Should be an error? */ 478*cdf0e10cSrcweir cwarn("Wrong number of macro arguments for \"%s\"", 479*cdf0e10cSrcweir tokenp->name); 480*cdf0e10cSrcweir } 481*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 482*cdf0e10cSrcweir if (debug) 483*cdf0e10cSrcweir dumpparm("expand"); 484*cdf0e10cSrcweir #endif 485*cdf0e10cSrcweir } /* Collect arguments */ 486*cdf0e10cSrcweir case DEF_NOARGS: /* No parameters just stuffs */ 487*cdf0e10cSrcweir expstuff(tokenp); /* Do actual parameters */ 488*cdf0e10cSrcweir } /* nargs switch */ 489*cdf0e10cSrcweir } 490*cdf0e10cSrcweir 491*cdf0e10cSrcweir FILE_LOCAL int 492*cdf0e10cSrcweir expcollect() 493*cdf0e10cSrcweir /* 494*cdf0e10cSrcweir * Collect the actual parameters for this macro. TRUE if ok. 495*cdf0e10cSrcweir */ 496*cdf0e10cSrcweir { 497*cdf0e10cSrcweir register int c; 498*cdf0e10cSrcweir register int paren; /* For embedded ()'s */ 499*cdf0e10cSrcweir for (;;) { 500*cdf0e10cSrcweir paren = 0; /* Collect next arg. */ 501*cdf0e10cSrcweir while ((c = skipws()) == '\n') /* Skip over whitespace */ 502*cdf0e10cSrcweir wrongline = TRUE; /* and newlines. */ 503*cdf0e10cSrcweir if (c == ')') { /* At end of all args? */ 504*cdf0e10cSrcweir /* 505*cdf0e10cSrcweir * Note that there is a guard byte in parm[] 506*cdf0e10cSrcweir * so we don't have to check for overflow here. 507*cdf0e10cSrcweir */ 508*cdf0e10cSrcweir *parmp = EOS; /* Make sure terminated */ 509*cdf0e10cSrcweir break; /* Exit collection loop */ 510*cdf0e10cSrcweir } 511*cdf0e10cSrcweir else if (nargs >= LASTPARM) 512*cdf0e10cSrcweir cfatal("Too many arguments in macro expansion", NULLST); 513*cdf0e10cSrcweir parlist[nargs++] = parmp; /* At start of new arg */ 514*cdf0e10cSrcweir for (;; c = cget()) { /* Collect arg's bytes */ 515*cdf0e10cSrcweir if (c == EOF_CHAR) { 516*cdf0e10cSrcweir cerror("end of file within macro argument", NULLST); 517*cdf0e10cSrcweir return (FALSE); /* Sorry. */ 518*cdf0e10cSrcweir } 519*cdf0e10cSrcweir else if (c == '\\') { /* Quote next character */ 520*cdf0e10cSrcweir charput(c); /* Save the \ for later */ 521*cdf0e10cSrcweir charput(cget()); /* Save the next char. */ 522*cdf0e10cSrcweir continue; /* And go get another */ 523*cdf0e10cSrcweir } 524*cdf0e10cSrcweir else if (type[c] == QUO) { /* Start of string? */ 525*cdf0e10cSrcweir scanstring(c, charput); /* Scan it off */ 526*cdf0e10cSrcweir continue; /* Go get next char */ 527*cdf0e10cSrcweir } 528*cdf0e10cSrcweir else if (c == '(') /* Worry about balance */ 529*cdf0e10cSrcweir paren++; /* To know about commas */ 530*cdf0e10cSrcweir else if (c == ')') { /* Other side too */ 531*cdf0e10cSrcweir if (paren == 0) { /* At the end? */ 532*cdf0e10cSrcweir unget(); /* Look at it later */ 533*cdf0e10cSrcweir break; /* Exit arg getter. */ 534*cdf0e10cSrcweir } 535*cdf0e10cSrcweir paren--; /* More to come. */ 536*cdf0e10cSrcweir } 537*cdf0e10cSrcweir else if (c == ',' && paren == 0) /* Comma delimits args */ 538*cdf0e10cSrcweir break; 539*cdf0e10cSrcweir else if (c == '\n') /* Newline inside arg? */ 540*cdf0e10cSrcweir wrongline = TRUE; /* We'll need a #line */ 541*cdf0e10cSrcweir charput(c); /* Store this one */ 542*cdf0e10cSrcweir } /* Collect an argument */ 543*cdf0e10cSrcweir charput(EOS); /* Terminate argument */ 544*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 545*cdf0e10cSrcweir if (debug) 546*cdf0e10cSrcweir fprintf( pCppOut, "parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); 547*cdf0e10cSrcweir #endif 548*cdf0e10cSrcweir } /* Collect all args. */ 549*cdf0e10cSrcweir return (TRUE); /* Normal return */ 550*cdf0e10cSrcweir } 551*cdf0e10cSrcweir 552*cdf0e10cSrcweir FILE_LOCAL 553*cdf0e10cSrcweir void expstuff(DEFBUF* tokenp) 554*cdf0e10cSrcweir /* 555*cdf0e10cSrcweir * Stuff the macro body, replacing formal parameters by actual parameters. 556*cdf0e10cSrcweir */ 557*cdf0e10cSrcweir { 558*cdf0e10cSrcweir register int c; /* Current character */ 559*cdf0e10cSrcweir register char *inp; /* -> repl string */ 560*cdf0e10cSrcweir register char *defp; /* -> macro output buff */ 561*cdf0e10cSrcweir int size; /* Actual parm. size */ 562*cdf0e10cSrcweir char *defend; /* -> output buff end */ 563*cdf0e10cSrcweir int string_magic; /* String formal hack */ 564*cdf0e10cSrcweir FILEINFO *file; /* Funny #include */ 565*cdf0e10cSrcweir #ifndef ZTC /* BP */ 566*cdf0e10cSrcweir extern FILEINFO *getfile(); 567*cdf0e10cSrcweir #endif 568*cdf0e10cSrcweir 569*cdf0e10cSrcweir file = getfile(NBUFF, tokenp->name); 570*cdf0e10cSrcweir inp = tokenp->repl; /* -> macro replacement */ 571*cdf0e10cSrcweir defp = file->buffer; /* -> output buffer */ 572*cdf0e10cSrcweir defend = defp + (NBUFF - 1); /* Note its end */ 573*cdf0e10cSrcweir if (inp != NULL) { 574*cdf0e10cSrcweir while ((c = (*inp++ & 0xFF)) != EOS) { 575*cdf0e10cSrcweir #ifdef SOLAR 576*cdf0e10cSrcweir if (c == DEL) { 577*cdf0e10cSrcweir c = (*inp++ & 0xFF); 578*cdf0e10cSrcweir #else 579*cdf0e10cSrcweir if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { 580*cdf0e10cSrcweir #endif 581*cdf0e10cSrcweir string_magic = (c == (MAC_PARM + PAR_MAC)); 582*cdf0e10cSrcweir if (string_magic) 583*cdf0e10cSrcweir c = (*inp++ & 0xFF); 584*cdf0e10cSrcweir /* 585*cdf0e10cSrcweir * Replace formal parameter by actual parameter string. 586*cdf0e10cSrcweir */ 587*cdf0e10cSrcweir if ((c -= MAC_PARM) < nargs) { 588*cdf0e10cSrcweir size = strlen(parlist[c]); 589*cdf0e10cSrcweir if ((defp + size) >= defend) 590*cdf0e10cSrcweir goto nospace; 591*cdf0e10cSrcweir /* 592*cdf0e10cSrcweir * Erase the extra set of quotes. 593*cdf0e10cSrcweir */ 594*cdf0e10cSrcweir if (string_magic && defp[-1] == parlist[c][0]) { 595*cdf0e10cSrcweir strcpy(defp-1, parlist[c]); 596*cdf0e10cSrcweir defp += (size - 2); 597*cdf0e10cSrcweir } 598*cdf0e10cSrcweir else { 599*cdf0e10cSrcweir strcpy(defp, parlist[c]); 600*cdf0e10cSrcweir defp += size; 601*cdf0e10cSrcweir } 602*cdf0e10cSrcweir } 603*cdf0e10cSrcweir } 604*cdf0e10cSrcweir else if (defp >= defend) { 605*cdf0e10cSrcweir nospace: cfatal("Out of space in macro \"%s\" arg expansion", 606*cdf0e10cSrcweir tokenp->name); 607*cdf0e10cSrcweir } 608*cdf0e10cSrcweir else { 609*cdf0e10cSrcweir *defp++ = (char)c; 610*cdf0e10cSrcweir } 611*cdf0e10cSrcweir } 612*cdf0e10cSrcweir } 613*cdf0e10cSrcweir *defp = EOS; 614*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 615*cdf0e10cSrcweir if (debug > 1) 616*cdf0e10cSrcweir fprintf( pCppOut, "macroline: \"%s\"\n", file->buffer); 617*cdf0e10cSrcweir #endif 618*cdf0e10cSrcweir } 619*cdf0e10cSrcweir 620*cdf0e10cSrcweir #if OSL_DEBUG_LEVEL > 1 621*cdf0e10cSrcweir void dumpparm(char* why) 622*cdf0e10cSrcweir /* 623*cdf0e10cSrcweir * Dump parameter list. 624*cdf0e10cSrcweir */ 625*cdf0e10cSrcweir { 626*cdf0e10cSrcweir register int i; 627*cdf0e10cSrcweir 628*cdf0e10cSrcweir fprintf( pCppOut, "dump of %d parameters (%d bytes total) %s\n", 629*cdf0e10cSrcweir nargs, parmp - parm, why); 630*cdf0e10cSrcweir for (i = 0; i < nargs; i++) { 631*cdf0e10cSrcweir fprintf( pCppOut, "parm[%d] (%d) = \"%s\"\n", 632*cdf0e10cSrcweir i + 1, (int)strlen(parlist[i]), parlist[i]); 633*cdf0e10cSrcweir } 634*cdf0e10cSrcweir } 635*cdf0e10cSrcweir #endif 636