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