1 #include <u.h> 2 #include <libc.h> 3 #include <stdio.h> 4 #include "cpp.h" 5 6 /* 7 * do a macro definition. tp points to the name being defined in the line 8 */ 9 void 10 dodefine(Tokenrow *trp) 11 { 12 Token *tp; 13 Nlist *np; 14 Tokenrow *def, *args; 15 16 tp = trp->tp+1; 17 if (tp>=trp->lp || tp->type!=NAME) { 18 error(ERROR, "#defined token is not a name"); 19 return; 20 } 21 np = lookup(tp, 1); 22 if (np->flag&ISUNCHANGE) { 23 error(ERROR, "#defined token %t can't be redefined", tp); 24 return; 25 } 26 /* collect arguments */ 27 tp += 1; 28 args = NULL; 29 if (tp<trp->lp && tp->type==LP && tp->wslen==0) { 30 /* macro with args */ 31 int narg = 0; 32 tp += 1; 33 args = new(Tokenrow); 34 maketokenrow(2, args); 35 if (tp->type!=RP) { 36 int err = 0; 37 for (;;) { 38 Token *atp; 39 if (tp->type!=NAME) { 40 err++; 41 break; 42 } 43 if (narg>=args->max) 44 growtokenrow(args); 45 for (atp=args->bp; atp<args->lp; atp++) 46 if (atp->len==tp->len 47 && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0) 48 error(ERROR, "Duplicate macro argument"); 49 *args->lp++ = *tp; 50 narg++; 51 tp += 1; 52 if (tp->type==RP) 53 break; 54 if (tp->type!=COMMA) { 55 err++; 56 break; 57 } 58 tp += 1; 59 } 60 if (err) { 61 error(ERROR, "Syntax error in macro parameters"); 62 return; 63 } 64 } 65 tp += 1; 66 } 67 trp->tp = tp; 68 if (((trp->lp)-1)->type==NL) 69 trp->lp -= 1; 70 def = normtokenrow(trp); 71 if (np->flag&ISDEFINED) { 72 if (comparetokens(def, np->vp) 73 || (np->ap==NULL) != (args==NULL) 74 || np->ap && comparetokens(args, np->ap)) 75 error(ERROR, "Macro redefinition of %t", trp->bp+2); 76 } 77 if (args) { 78 Tokenrow *tap; 79 tap = normtokenrow(args); 80 dofree(args->bp); 81 args = tap; 82 } 83 np->ap = args; 84 np->vp = def; 85 np->flag |= ISDEFINED; 86 } 87 88 /* 89 * Definition received via -D or -U 90 */ 91 void 92 doadefine(Tokenrow *trp, int type) 93 { 94 Nlist *np; 95 static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }}; 96 static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 }; 97 98 trp->tp = trp->bp; 99 if (type=='U') { 100 if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME) 101 goto syntax; 102 if ((np = lookup(trp->tp, 0)) == NULL) 103 return; 104 np->flag &= ~ISDEFINED; 105 return; 106 } 107 if (trp->tp >= trp->lp || trp->tp->type!=NAME) 108 goto syntax; 109 np = lookup(trp->tp, 1); 110 np->flag |= ISDEFINED; 111 trp->tp += 1; 112 if (trp->tp >= trp->lp || trp->tp->type==END) { 113 np->vp = &onetr; 114 return; 115 } 116 if (trp->tp->type!=ASGN) 117 goto syntax; 118 trp->tp += 1; 119 if ((trp->lp-1)->type == END) 120 trp->lp -= 1; 121 np->vp = normtokenrow(trp); 122 return; 123 syntax: 124 error(FATAL, "Illegal -D or -U argument %r", trp); 125 } 126 127 /* 128 * Do macro expansion in a row of tokens. 129 * Flag is NULL if more input can be gathered. 130 */ 131 void 132 expandrow(Tokenrow *trp, char *flag) 133 { 134 Token *tp; 135 Nlist *np; 136 137 if (flag) 138 setsource(flag, -1, ""); 139 for (tp = trp->tp; tp<trp->lp; ) { 140 if (tp->type!=NAME 141 || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0 142 || (np = lookup(tp, 0))==NULL 143 || (np->flag&(ISDEFINED|ISMAC))==0 144 || tp->hideset && checkhideset(tp->hideset, np)) { 145 tp++; 146 continue; 147 } 148 trp->tp = tp; 149 if (np->val==KDEFINED) { 150 tp->type = DEFINED; 151 if ((tp+1)<trp->lp && (tp+1)->type==NAME) 152 (tp+1)->type = NAME1; 153 else if ((tp+3)<trp->lp && (tp+1)->type==LP 154 && (tp+2)->type==NAME && (tp+3)->type==RP) 155 (tp+2)->type = NAME1; 156 else 157 error(ERROR, "Incorrect syntax for `defined'"); 158 tp++; 159 continue; 160 } 161 if (np->flag&ISMAC) 162 builtin(trp, np->val); 163 else { 164 expand(trp, np); 165 } 166 tp = trp->tp; 167 } 168 if (flag) 169 unsetsource(); 170 } 171 172 /* 173 * Expand the macro whose name is np, at token trp->tp, in the tokenrow. 174 * Return trp->tp at the first token next to be expanded 175 * (ordinarily the beginning of the expansion) 176 */ 177 void 178 expand(Tokenrow *trp, Nlist *np) 179 { 180 Tokenrow ntr; 181 int ntokc, narg, i; 182 Token *tp; 183 Tokenrow *atr[NARG+1]; 184 int hs; 185 186 copytokenrow(&ntr, np->vp); /* copy macro value */ 187 if (np->ap==NULL) /* parameterless */ 188 ntokc = 1; 189 else { 190 ntokc = gatherargs(trp, atr, &narg); 191 if (narg<0) { /* not actually a call (no '(') */ 192 trp->tp += 1; 193 return; 194 } 195 if (narg != rowlen(np->ap)) { 196 error(ERROR, "Disagreement in number of macro arguments"); 197 trp->tp->hideset = newhideset(trp->tp->hideset, np); 198 trp->tp += ntokc; 199 return; 200 } 201 substargs(np, &ntr, atr); /* put args into replacement */ 202 for (i=0; i<narg; i++) { 203 dofree(atr[i]->bp); 204 dofree(atr[i]); 205 } 206 } 207 doconcat(&ntr); /* execute ## operators */ 208 hs = newhideset(trp->tp->hideset, np); 209 for (tp=ntr.bp; tp<ntr.lp; tp++) { /* distribute hidesets */ 210 if (tp->type==NAME) { 211 if (tp->hideset==0) 212 tp->hideset = hs; 213 else 214 tp->hideset = unionhideset(tp->hideset, hs); 215 } 216 } 217 ntr.tp = ntr.bp; 218 insertrow(trp, ntokc, &ntr); 219 trp->tp -= rowlen(&ntr); 220 dofree(ntr.bp); 221 return; 222 } 223 224 /* 225 * Gather an arglist, starting in trp with tp pointing at the macro name. 226 * Return total number of tokens passed, stash number of args found. 227 * trp->tp is not changed relative to the tokenrow. 228 */ 229 int 230 gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg) 231 { 232 int parens = 1; 233 int ntok = 0; 234 Token *bp, *lp; 235 Tokenrow ttr; 236 int ntokp; 237 238 *narg = -1; /* means that there is no macro call */ 239 /* look for the ( */ 240 for (;;) { 241 trp->tp++; 242 ntok++; 243 if (trp->tp >= trp->lp) { 244 gettokens(trp, 0); 245 if ((trp->lp-1)->type==END) { 246 trp->lp -= 1; 247 trp->tp -= ntok; 248 return ntok; 249 } 250 } 251 if (trp->tp->type==LP) 252 break; 253 if (trp->tp->type!=NL) 254 return ntok; 255 } 256 *narg = 0; 257 ntok++; 258 ntokp = ntok; 259 trp->tp++; 260 /* search for the terminating ), possibly extending the row */ 261 while (parens>0) { 262 if (trp->tp >= trp->lp) 263 gettokens(trp, 0); 264 if (trp->tp->type==END) { 265 trp->lp -= 1; 266 trp->tp -= ntok; 267 error(ERROR, "EOF in macro arglist"); 268 return ntok; 269 } 270 if (trp->tp->type==NL) { 271 trp->tp += 1; 272 adjustrow(trp, -1); 273 trp->tp -= 1; 274 makespace(trp); 275 continue; 276 } 277 if (trp->tp->type==LP) 278 parens++; 279 else if (trp->tp->type==RP) 280 parens--; 281 trp->tp++; 282 ntok++; 283 } 284 trp->tp -= ntok; 285 /* Now trp->tp won't move underneath us */ 286 lp = bp = trp->tp+ntokp; 287 for (; parens>=0; lp++) { 288 if (lp->type == LP) { 289 parens++; 290 continue; 291 } 292 if (lp->type==RP) 293 parens--; 294 if (lp->type==DSHARP) 295 lp->type = DSHARP1; /* ## not special in arg */ 296 if (lp->type==COMMA && parens==0 || parens<0 && (lp-1)->type!=LP) { 297 if (*narg>=NARG-1) 298 error(FATAL, "Sorry, too many macro arguments"); 299 ttr.bp = ttr.tp = bp; 300 ttr.lp = lp; 301 atr[(*narg)++] = normtokenrow(&ttr); 302 bp = lp+1; 303 } 304 } 305 return ntok; 306 } 307 308 /* 309 * substitute the argument list into the replacement string 310 * This would be simple except for ## and # 311 */ 312 void 313 substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) 314 { 315 Tokenrow tatr; 316 Token *tp; 317 int ntok, argno; 318 319 for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) { 320 if (rtr->tp->type==SHARP) { /* string operator */ 321 tp = rtr->tp; 322 rtr->tp += 1; 323 if ((argno = lookuparg(np, rtr->tp))<0) { 324 error(ERROR, "# not followed by macro parameter"); 325 continue; 326 } 327 ntok = 1 + (rtr->tp - tp); 328 rtr->tp = tp; 329 insertrow(rtr, ntok, stringify(atr[argno])); 330 continue; 331 } 332 if (rtr->tp->type==NAME 333 && (argno = lookuparg(np, rtr->tp)) >= 0) { 334 if ((rtr->tp+1)->type==DSHARP 335 || rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP) 336 insertrow(rtr, 1, atr[argno]); 337 else { 338 copytokenrow(&tatr, atr[argno]); 339 expandrow(&tatr, "<macro>"); 340 insertrow(rtr, 1, &tatr); 341 dofree(tatr.bp); 342 } 343 continue; 344 } 345 rtr->tp++; 346 } 347 } 348 349 /* 350 * Evaluate the ## operators in a tokenrow 351 */ 352 void 353 doconcat(Tokenrow *trp) 354 { 355 Token *ltp, *ntp; 356 Tokenrow ntr; 357 int len; 358 359 for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) { 360 if (trp->tp->type==DSHARP1) 361 trp->tp->type = DSHARP; 362 else if (trp->tp->type==DSHARP) { 363 char tt[128]; 364 ltp = trp->tp-1; 365 ntp = trp->tp+1; 366 if (ltp<trp->bp || ntp>=trp->lp) { 367 error(ERROR, "## occurs at border of replacement"); 368 continue; 369 } 370 len = ltp->len + ntp->len; 371 strncpy((char*)tt, (char*)ltp->t, ltp->len); 372 strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); 373 tt[len] = '\0'; 374 setsource("<##>", -1, tt); 375 maketokenrow(3, &ntr); 376 gettokens(&ntr, 1); 377 unsetsource(); 378 if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) 379 error(WARNING, "Bad token %r produced by ##", &ntr); 380 ntr.lp = ntr.bp+1; 381 trp->tp = ltp; 382 makespace(&ntr); 383 insertrow(trp, (ntp-ltp)+1, &ntr); 384 dofree(ntr.bp); 385 trp->tp--; 386 } 387 } 388 } 389 390 /* 391 * tp is a potential parameter name of macro mac; 392 * look it up in mac's arglist, and if found, return the 393 * corresponding index in the argname array. Return -1 if not found. 394 */ 395 int 396 lookuparg(Nlist *mac, Token *tp) 397 { 398 Token *ap; 399 400 if (tp->type!=NAME || mac->ap==NULL) 401 return -1; 402 for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) { 403 if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0) 404 return ap - mac->ap->bp; 405 } 406 return -1; 407 } 408 409 /* 410 * Return a quoted version of the tokenrow (from # arg) 411 */ 412 #define STRLEN 512 413 Tokenrow * 414 stringify(Tokenrow *vp) 415 { 416 static Token t = { STRING }; 417 static Tokenrow tr = { &t, &t, &t+1, 1 }; 418 Token *tp; 419 uchar s[STRLEN]; 420 uchar *sp = s, *cp; 421 int i, instring; 422 423 *sp++ = '"'; 424 for (tp = vp->bp; tp < vp->lp; tp++) { 425 instring = tp->type==STRING || tp->type==CCON; 426 if (sp+2*tp->len >= &s[STRLEN-10]) { 427 error(ERROR, "Stringified macro arg is too long"); 428 break; 429 } 430 if (tp->wslen && (tp->flag&XPWS)==0) 431 *sp++ = ' '; 432 for (i=0, cp=tp->t; i<tp->len; i++) { 433 if (instring && (*cp=='"' || *cp=='\\')) 434 *sp++ = '\\'; 435 *sp++ = *cp++; 436 } 437 } 438 *sp++ = '"'; 439 *sp = '\0'; 440 sp = s; 441 t.len = strlen((char*)sp); 442 t.t = newstring(sp, t.len, 0); 443 return &tr; 444 } 445 446 /* 447 * expand a builtin name 448 */ 449 void 450 builtin(Tokenrow *trp, int biname) 451 { 452 char *op; 453 Token *tp; 454 Source *s; 455 456 tp = trp->tp; 457 trp->tp++; 458 /* need to find the real source */ 459 s = cursource; 460 while (s && s->fd==-1) 461 s = s->next; 462 if (s==NULL) 463 s = cursource; 464 /* most are strings */ 465 tp->type = STRING; 466 if (tp->wslen) { 467 *outp++ = ' '; 468 tp->wslen = 1; 469 } 470 op = outp; 471 *op++ = '"'; 472 switch (biname) { 473 474 case KLINENO: 475 tp->type = NUMBER; 476 op = outnum(op-1, s->line); 477 break; 478 479 case KFILE: 480 strcpy(op, s->filename); 481 op += strlen(s->filename); 482 break; 483 484 case KDATE: 485 strncpy(op, curtime+4, 7); 486 strncpy(op+7, curtime+24, 4); /* Plan 9 asctime disobeys standard */ 487 op += 11; 488 break; 489 490 case KTIME: 491 strncpy(op, curtime+11, 8); 492 op += 8; 493 break; 494 495 default: 496 error(ERROR, "cpp botch: unknown internal macro"); 497 return; 498 } 499 if (tp->type==STRING) 500 *op++ = '"'; 501 tp->t = (uchar*)outp; 502 tp->len = op - outp; 503 outp = op; 504 } 505