1File: MACRO.C Page 1 1 /* 2 Copyright 1982 3 Alcyon Corporation 4 8716 Production Ave. 5 San Diego, Ca. 92121 6 */ 7 8 #include "preproc.h" 9 10 #define CSTKSIZE 20 11 #define FILESEP '/' 12 #define NINCL 10 13 14 #ifdef UNIX 15 char *stdincl "/usr/include/"; /*standard include directory*/ 16 #endif 17 #ifdef VMS 18 char *stdincl "lib:"; 19 #endif 20 #ifdef CPM 21 char *stdincl ""; 22 #endif 23 24 int clabel 1000; 25 int nlabel 1001; 26 int nincl; 27 char *incl[10]; 28 char tmp[6]; 29 30 struct builtin { 31 char *b_name; 32 int b_type; 33 } btab[] { 34 "define", DEFINE, 35 "include", INCLUDE, 36 "undef", UNDEF, 37 "ifdef", IFDEF, 38 "ifndef", IFNDEF, 39 "else", ELSE, 40 "endif", ENDIF, 41 "if", IF, 42 0, 43 }; 44 45 char *getinclude(); 46 char cstack[CSTKSIZE]; 47 char *cstkptr, inclname[TOKSIZE]; 48 49 /* domacro - do macro processing*/ 50 /* Does the macro pre-processing on the input file and leaves the*/ 51 /* result on the output file.*/ 52 domacro(infile,outfile,nd) /* returns 1 if ok, 0 otherwise*/ 53 char *infile; /* input file name*/ 54 char *outfile; /* output file name*/ 55 int nd; /* number of defines*/ 56 { 57 register struct builtin *bp; 58 register char *l; 59 register struct symbol *sp; 1File: MACRO.C Page 2 60 register int x, nonewline; /* handle empty new lines with SOH */ 61 register char *p; 62 filep = &filestack[0]; 63 64 if( fopen(infile,&(filep->inbuf),0) < 0 ) { /* 3rd arg for versados */ 65 error("can't open source file %s\n",infile); 66 return(0); 67 } 68 if( fcreat(outfile,&outbuf,0) < 0 ) { /* 3rd arg for versados */ 69 error("can't creat %s\n",outfile); 70 return(0); 71 } 72 for (sp= &symtab[0]; sp<= &symtab[HSIZE-1]; sp++) /*3.4*/ 73 sp->s_def = null; /* clear out symbol table */ 74 if( !defap ) { 75 defp = defap = sbrk(1024); 76 defmax = defcount = 1024; 77 } 78 else { /* multiple files, define area already exists */ 79 defcount = defmax; 80 for (x = defmax, defp = defap; x>0; x--) 81 *defp++ = 0; 82 defp = defap; 83 } 84 lineno = 1; 85 nonewline = defused = mfail = 0; 86 pbp = &pbbuf[0]; 87 cstkptr = &cstack[0]; 88 install("Newlabel",NEWLABEL); 89 install("Label",LABEL); 90 while( --nd >= 0 ) 91 dinstall(defs[nd].ptr,defs[nd].value); 92 while( getline(infile) ) { 93 l = line; 94 if( filep == &filestack[0] && pbp == &pbbuf[0] ) 95 lineno++; 96 else if ( !pflag && !asflag ) { /*[vlh] add fname & line#*/ 97 if (*l) { 98 putc(SOH,&outbuf); 99 for (p = (filep)->ifile; *p; p++) 100 putc(*p,&outbuf); 101 putc(SOH,&outbuf); 102 itoa((filep)->lineno,tmp,5); 103 for (p = tmp; *p==' '; ) p++; 104 for ( ; *p; p++) 105 putc(*p,&outbuf); 106 putc(' ',&outbuf); 107 if (!(*l)) putc(' ',&outbuf); 108 } 109 else nonewline++; 110 (filep)->lineno++; 111 } 112 while( *l ) 113 putc(*l++,&outbuf); 114 if (!nonewline) putc('\n',&outbuf); 115 else nonewline = 0; 116 } 117 if( cstkptr != &cstack[0] ) 118 error("unmatched conditional"); 1File: MACRO.C Page 3 119 if( defused > defmax ) 120 defmax = defused; 121 v6flush(&outbuf); 122 close(outbuf.fd); 123 close(filep->inbuf.fd); 124 return(mfail==0); 125 } 126 127 install(name,def) 128 char *name; 129 int def; 130 { 131 register struct symbol *sp; 132 133 sp = getsp(name); 134 symcopy(name,sp->s_name); 135 sp->s_def = defp; 136 putd(def); 137 putd('\0'); 138 } 139 140 dinstall(name,def) /* returns - none*/ 141 char *name; /* macro name*/ 142 char *def; /* pointer to definition*/ 143 { 144 register struct symbol *sp; 145 146 sp = getsp(name); 147 symcopy(name,sp->s_name); 148 sp->s_def = defp; 149 putd(NOARGS); 150 if (def) /* [vlh] character strings... */ 151 while(*def) putd(*def++); 152 else putd('1'); /* [vlh] default define value */ 153 putd('\0'); 154 } 155 156 /* kwlook - look up the macro built-in names*/ 157 /* Searches thru the built-in table for the name.*/ 158 kwlook(name) /* returns keyword index or 0*/ 159 char *name; /* keyword name to lookup*/ 160 { 161 register struct builtin *bp; 162 163 for( bp = &btab[0]; bp->b_name; bp++ ) 164 if( strcmp(bp->b_name,name) == 0 ) 165 return(bp->b_type); 166 return(0); 167 } 168 169 /* 170 * getline - get input line handling macro statements 171 * Checks for a preprocessor statement on the line and if there 172 * is one there, it processes it. Note that most of the work is 173 * in determining whether we need to skip the current line or not. 174 * This is all handled with the condition stack and the skip variable. 175 * The skip variable is non-zero if any condition on the condition 176 * stack is SKIP. 177 */ 1File: MACRO.C Page 4 178 getline(infile) /* returns 0 for EOF, 1 otherwise*/ 179 char *infile; /* [vlh] for quoted include files */ 180 { 181 char token[TOKSIZE]; 182 register int type, i; 183 register char *p; 184 185 initl(); 186 if( (type=gettok(token)) == EOF ) 187 return(0); 188 if( type == POUND ) { 189 if( (type=getntok(token)) == NEWL ) 190 return(1); 191 switch( kwlook(token) ) { 192 193 case IFDEF: 194 if( getntok(token) == ALPHA && lookup(token) ) 195 push(NOSKIP); 196 else { 197 push(SKIP); 198 skip++; 199 } 200 break; 201 202 case IFNDEF: 203 if( getntok(token) == ALPHA && lookup(token) ) { 204 push(SKIP); 205 skip++; 206 } 207 else 208 push(NOSKIP); 209 break; 210 211 case ENDIF: 212 if( (i=pop()) == SKIP ) 213 skip--; 214 else if( i != NOSKIP ) 215 error("invalid #endif"); 216 break; 217 218 case ELSE: 219 if( (i=pop()) == SKIP ) { 220 skip--; 221 push(NOSKIP); 222 } 223 else if( i == NOSKIP ) { 224 skip++; 225 push(SKIP); 226 } 227 else 228 error("invalid #else"); 229 break; 230 231 case DEFINE: 232 if( !skip ) /*if in skip, don't do define*/ 233 dodefine(); 234 break; 235 236 case UNDEF: 1File: MACRO.C Page 5 237 if( !skip ) { /*if in skip, don't undef*/ 238 if( (type=getntok(token)) == ALPHA ) 239 undefine(token); 240 } 241 break; 242 243 case INCLUDE: 244 if( !skip ) /*if in skip, don't do include*/ 245 doinclude(infile); 246 break; 247 248 case IF: 249 if( cexpr() ) /*evaluate constant expression*/ 250 push(NOSKIP); /*non-zero, so don't skip*/ 251 else { 252 push(SKIP); 253 skip++; 254 } 255 break; 256 257 default: 258 error("invalid preprocessor command"); 259 break; 260 } 261 eatup(); 262 } 263 else if( type == NEWL ) 264 ; 265 else if( skip ) 266 eatup(); 267 else { 268 for( ; type != NEWL && type != EOF ; type = gettok(token) ) { 269 if( type == ALPHA && (p=lookup(token)) ) 270 expand(p); 271 else { 272 for( p = token; *p ; ) 273 putl(*p++); 274 } 275 } 276 } 277 putl('\0'); 278 return(1); 279 } 280 281 /* eatup - eat up the rest of the input line until a newline or EOF*/ 282 /* Does gettok calls.*/ 283 eatup() /* returns - none*/ 284 { 285 register int type; 286 char etoken[TOKSIZE]; 287 288 while( (type=gettok(etoken)) != NEWL && type != EOF ) 289 ; 290 } 291 292 /* putl - put a character to the current output line*/ 293 /* Checks for line overflow.*/ 294 putl(c) /* returns - none*/ 295 int c; /* character to put on line*/ 1File: MACRO.C Page 6 296 { 297 if( linep < &line[LINESIZE] ) 298 *linep++ = c; 299 else if ( !loverflow ) { 300 loverflow++; 301 error("line overflow"); 302 } 303 } 304 305 /* initl - initialize current line*/ 306 /* Sets the line pointer and the line overflow flag.*/ 307 initl() /* returns - none*/ 308 { 309 *(linep= &line[0]) = '\0'; 310 loverflow = 0; 311 } 312 313 /* putd - put a character to the define buffer*/ 314 /* Does dynamic allocation for define buffer*/ 315 putd(c) /* returns - none*/ 316 int c; /* character to put in buffer*/ 317 { 318 if( !defcount ) { 319 if( sbrk(DEFSIZE) == -1 ) { 320 error("define table overflow"); 321 cexit(); 322 } 323 defcount = DEFSIZE; 324 } 325 defused++; 326 defcount--; 327 *defp++ = c; 328 } 329 330 /* undefine - does undef command*/ 331 /* Sets the symbols definition to the null pointer*/ 332 undefine(name) /* returns - none*/ 333 char *name; /* pointer to name to undef*/ 334 { 335 register struct symbol *sp; 336 337 sp = getsp(name); 338 if( sp->s_def ) 339 sp->s_def = null; 340 } 341 342 /* dodefine - do #define processing*/ 343 /* Checks the define name, collects formal arguements and saves*/ 344 /* macro definition, substituting for formal arguments as it goes.*/ 345 dodefine() /* returns - none*/ 346 { 347 char token[TOKSIZE], *args[MAXARGS], argbuf[ARGBSIZE]; 348 register char *abp, *p; 349 register int type, nargs, i; 350 register struct symbol *sp; 351 352 if( (type=getntok(token)) != ALPHA ) { 353 error("bad define name: %s",token); 354 return; 1File: MACRO.C Page 7 355 } 356 sp = getsp(token); 357 symcopy(token,sp->s_name); 358 sp->s_def = defp; 359 nargs = 0; 360 abp = argbuf; 361 if( (type=gettok(token)) == LPAREN ) { 362 for( ; (type=getfarg(token)) != RPAREN; nargs++ ) { 363 if( nargs >= MAXARGS ) { 364 error("too many arguments"); 365 break; 366 } 367 args[nargs] = abp; 368 for( p = token; *abp++ = *p++; ) { 369 if( abp >= &argbuf[ARGBSIZE] ) { 370 error("argument buffer overflow"); 371 break; 372 } 373 } 374 } 375 putd(nargs); 376 } 377 else { 378 pbtok(token); 379 putd(NOARGS); 380 } 381 type = getntok(token); /*get next non-white token*/ 382 for( ; type != NEWL && type != EOF; type = gettok(token) ) { 383 if( type == ALPHA ) { 384 for( i = 0; i < nargs; i++ ) { 385 if( strcmp(args[i],token) == 0 ) 386 break; 387 } 388 if( i < nargs ) { /*sub ARG marker for formal arg*/ 389 putd(i+1); 390 putd(ARG); 391 continue; 392 } 393 } 394 else if( type == BSLASH ) { 395 if( (i=ngetch()) == '\n' ) { /*multi-line macro?*/ 396 if( filep == &filestack[0] && pbp == &pbbuf[0] ) { 397 lineno++; 398 putc('\n',&outbuf); 399 } 400 } 401 putd(i); 402 continue; 403 } 404 for( p = token; *p ; ) 405 putd(*p++); 406 } 407 pbtok(token); 408 putd('\0'); 409 } 410 411 /* expand - expands the macro definition*/ 412 /* Checks for define recursion and #define x x problems, collects*/ 413 /* the actual arguments using getaarg, and then expands the macro*/ 1File: MACRO.C Page 8 414 /* by pushing it onto the push back buffer, substituting arguments*/ 415 /* as it goes.*/ 416 expand(sp) /* returns - none*/ 417 struct symbol *sp; /* pointer to macro to expand*/ 418 { 419 char argbuf[ARGBSIZE], *args[MAXARGS], token[TOKSIZE]; 420 register char *p, *abp, *mdef; 421 register int i, j, nargs, type; 422 423 if( pbflag++ > 100 ) { 424 error("define recursion"); 425 return; 426 } 427 if( strcmp(sp->s_name,mdef=sp->s_def) == 0 ) { /*handle #define x x*/ 428 while( *mdef ) 429 putl(*mdef++); 430 return; 431 } 432 nargs = 0; 433 if( *mdef == NOARGS ) /*suppress grabbing of args*/ 434 ; 435 else if( gettok(token) != LPAREN ) 436 pbtok(token); 437 else { 438 abp = &argbuf[0]; 439 while( (type=getaarg(token)) != EOF ) { 440 if( nargs >= MAXARGS ) { 441 error("too many arguments"); 442 return; 443 } 444 args[nargs++] = abp; 445 for( p = token; *abp++ = *p++; ) { 446 if( abp >= &argbuf[ARGBSIZE] ) { 447 error("argument buffer overflow"); 448 return; 449 } 450 } 451 if( type == RPAREN ) 452 break; 453 } 454 } 455 if( *mdef == NEWLABEL ) { 456 clabel = nlabel; 457 if( !nargs ) 458 nlabel++; 459 else 460 nlabel =+ atoi(args[0]); 461 } 462 else if( *mdef == LABEL ) { 463 if( !nargs ) 464 i = clabel; 465 else 466 i = clabel + atoi(args[0]); 467 pbnum(i); 468 pbtok("_L"); 469 } 470 else { 471 mdef++; /*skip no. of args*/ 472 for( p = mdef + strlen(mdef) - 1; p >= mdef; p-- ) { 1File: MACRO.C Page 9 473 if( *p == ARG ) { 474 if( (j= *--p) <= nargs ) 475 pbtok(args[j-1]); 476 } 477 else 478 putback(*p); 479 } 480 } 481 } 482 483 /* getfarg - get macro formal parameters*/ 484 /* Skips blanks and handles "," and ")".*/ 485 getfarg(token) /* returns token type*/ 486 char *token; /* token returned*/ 487 { 488 register int type; 489 490 if( (type=getntok(token)) == RPAREN || type == ALPHA ) 491 return(type); 492 if( type != COMMA || (type=getntok(token)) != ALPHA ) 493 error("bad argument:%s",token); 494 return(type); 495 } 496 497 /* getntok - get next token, suppressing white space*/ 498 /* Merely gettok's until non-white space is there*/ 499 getntok(token) /* returns token type*/ 500 char *token; /* token returned*/ 501 { 502 register int type; 503 504 while( (type=gettok(token)) == WHITE ) 505 ; 506 return(type); 507 } 508 509 /* getaarg - get macro actual argument*/ 510 /* This handles the collecting of the macro's call arguments.*/ 511 /* Note that you may have parenthesis as part of the macro argument,*/ 512 /* hence you need to keep track of them.*/ 513 getaarg(argp) /* returns token type*/ 514 char *argp; /* argument returned*/ 515 { 516 int type, plevel, i; 517 register char *p, *ap; 518 char token[TOKSIZE]; 519 520 ap = argp; 521 *ap = '\0'; 522 plevel = 0; 523 i = TOKSIZE; 524 while( ((type=gettok(token)) != COMMA && type != RPAREN) || plevel ) { 525 for( p = token; *ap = *p++; ap++ ) 526 if( --i <= 0 ) { 527 error("macro argument too long"); 528 return(EOF); 529 } 530 if( type == LPAREN ) 531 plevel++; 1File: MACRO.C Page 10 532 else if( type == RPAREN ) 533 plevel--; 534 else if( type == EOF ) { 535 error("unexpected EOF"); 536 cexit(); 537 } 538 } 539 if( ap == argp ) 540 type = EOF; 541 return(type); 542 } 543 544 /* push - push a #ifdef condition value on condition stack*/ 545 /* Checks for stack overflow.*/ 546 push(val) /* returns - none*/ 547 int val; /* value to push*/ 548 { 549 if( cstkptr >= &cstack[CSTKSIZE] ) { 550 error("condition stack overflow"); 551 cexit(); 552 } 553 *cstkptr++ = val; 554 } 555 556 /* pop - pop the #ifdef, etc. condition stack*/ 557 /* Checks for stack undeflow.*/ 558 pop() /* returns - top of condition stack*/ 559 { 560 if( cstkptr <= &cstack[0] ) 561 return(-1); 562 return( *--cstkptr ); 563 } 564 565 /* doinclude - handle #include command*/ 566 /* Checks for file name or library file name and pushes file on*/ 567 /* include file stack.*/ 568 doinclude(infile) /* returns - none*/ 569 char *infile; /* [vlh] for quoted include files */ 570 { 571 register int type, fd; 572 char token[TOKSIZE], fname[TOKSIZE]; 573 register char *p, *q, c, *ptr1, *ptr2; 574 int i, j; 575 576 p = fname; 577 if( (type=getntok(token)) == SQUOTE || type == DQUOTE ) { 578 for( c = token[0], q = &token[1]; *q != c; ) 579 *p++ = *q++; 580 *p = '\0'; 581 p = getinclude(fname,infile); 582 } 583 else if( type != LESS ) { 584 error("bad include file"); 585 return; 586 } 587 else { 588 while( (type=gettok(token))!=GREAT && type!=NEWL && type!=EOF ) 589 for( q = token; *p = *q++; p++ ) 590 ; 1File: MACRO.C Page 11 591 if( type != GREAT ) { 592 error("bad include file name"); 593 pbtok(token); 594 return; 595 } 596 p = getinclude(fname,0L); 597 } 598 eatup(); /*need here...*/ 599 filep++; 600 if( filep >= &filestack[FSTACK] ) 601 error("includes nested too deeply"); 602 else { 603 if( fopen(p,&(filep->inbuf),0) < 0 )/* 3rd arg for versados */ 604 error("can't open include file %s\n",p); 605 else { 606 filep->ifd = fd; 607 filep->lineno = 0; /* [vlh] */ 608 doifile(p); 609 } 610 } 611 putback('\n'); /*for eatup in domacro*/ 612 } 613 614 doifile(p) /* [vlh] */ 615 char *p; 616 { 617 register char *iptr; 618 register int ndx; 619 620 while ((ndx = index(p,FILESEP)) >= 0) p =+ ndx+1; 621 for( iptr = filep->ifile; *p; ) *iptr++ = *p++; 622 *iptr = 0; 623 } 624 625 /* getinclude - get include file full pathname */ 626 char * 627 getinclude(fname,parent) /* [vlh] */ 628 char *fname; 629 char *parent; /* search parent-file home directory ? */ 630 { 631 register char *q, *t; 632 register int i, fd, ndx; 633 634 if (parent) { /* include filename surrounded by quotes */ 635 q = (filep == &filestack[0]) ? parent : (filep)->ifile; 636 t = &inclname; 637 while ((ndx = index(q,FILESEP)) >= 0) { 638 ndx++; 639 while (ndx--) *t++ = *q++; 640 } 641 for (q=fname; *t++ = *q++; ); 642 *t = 0; 643 if ((fd = open(inclname,0)) >= 0) { /* found it */ 644 close(fd); 645 return(&inclname); 646 } 647 } 648 for (i=0; i= 0) { 653 close(fd); 654 return(&inclname); 655 } 656 } 657 for(t=inclname, q=stdincl; *t++ = *q++; ) ; 658 for(q=fname, --t; *t++ = *q++; ) ; 659 *t = 0; 660 return(&inclname); 661 } 662 663 pbnum(num) /* returns - none*/ 664 int num; 665 { 666 register int digit; 667 668 do { 669 digit = num % 10; 670 num =/ 10; 671 putback(digit+'0'); 672 } while( num > 0 ); 673 }