macro.c 11 KB

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