macro.c 11 KB

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