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