replace.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /*
  2. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
  3. * See the copyright notice in the ACK home directory, in the file "Copyright".
  4. */
  5. /* $Id$ */
  6. /* M A C R O R E P L A C E M E N T */
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include "pathlength.h"
  11. #include "strsize.h"
  12. #include "nparams.h"
  13. #include "idfsize.h"
  14. #include "numsize.h"
  15. #include "alloc.h"
  16. #include "idf.h"
  17. #include "input.h"
  18. #include "macro.h"
  19. #include "arith.h"
  20. #include "LLlex.h"
  21. #include "class.h"
  22. #include "debug.h"
  23. #include "assert.h"
  24. #include "macbuf.h"
  25. #include "replace.h"
  26. extern int InputLevel;
  27. struct repl *ReplaceList; /* list of currently active macros */
  28. void expand_defined(struct repl *repl);
  29. void getactuals(struct repl *repl, struct idf *idf);
  30. void macro_func(struct idf *idef);
  31. void macro2buffer(struct repl *repl, struct idf *idf, struct args *args);
  32. void add2repl(struct repl *repl, int ch);
  33. void stash(struct repl *repl, int ch, int stashraw);
  34. int expand_macro(struct repl *repl, struct idf *idf);
  35. int replace(struct idf *idf)
  36. {
  37. /* replace is called by the lexical analyzer to perform
  38. macro replacement. The routine actualy functions as a
  39. higher interface to the real thing: expand_macro().
  40. */
  41. struct repl *repl;
  42. if (!(idf->id_macro)) return 0;
  43. if (idf->id_macro->mc_flag & NOREPLACE)
  44. return 0;
  45. repl = new_repl();
  46. repl->r_ptr = repl->r_text = Malloc((unsigned)(repl->r_size = LAPBUF));
  47. repl->r_args = new_args();
  48. repl->r_idf = idf;
  49. if (!expand_macro(repl, idf))
  50. return 0;
  51. InputLevel++;
  52. InsertText(repl->r_text, (int)(repl->r_ptr - repl->r_text));
  53. idf->id_macro->mc_flag |= NOREPLACE;
  54. repl->r_level = InputLevel;
  55. repl->next = ReplaceList;
  56. ReplaceList = repl;
  57. return 1;
  58. }
  59. void unstackrepl()
  60. {
  61. Unstacked++;
  62. }
  63. void freeargs(struct args *args)
  64. {
  65. register int i;
  66. /* We must don't know how many parameters were specified, so be
  67. * prepared to free all NPARAMS parameters.
  68. * When an expvec is !NULL, the rawvec will also be !NULL.
  69. * When an expvec is NULL, all remaining vectors will also be NULL.
  70. */
  71. for (i = 0; i < NPARAMS; i++) {
  72. if (args->a_expvec[i]) {
  73. free(args->a_expvec[i]);
  74. free(args->a_rawvec[i]);
  75. } else break;
  76. }
  77. free_args(args);
  78. }
  79. void EnableMacros()
  80. {
  81. register struct repl *r = ReplaceList, *prev = 0;
  82. assert(Unstacked > 0);
  83. while(r) {
  84. struct repl *nxt = r->next;
  85. if (r->r_level > InputLevel) {
  86. r->r_idf->id_macro->mc_flag &= ~NOREPLACE;
  87. if (!prev) ReplaceList = nxt;
  88. else prev->next = nxt;
  89. free(r->r_text);
  90. freeargs(r->r_args);
  91. free_repl(r);
  92. }
  93. else prev = r;
  94. r = nxt;
  95. }
  96. Unstacked = 0;
  97. }
  98. int expand_macro(struct repl *repl, struct idf *idf)
  99. {
  100. /* expand_macro() does the actual macro replacement.
  101. "idf" is a description of the identifier which
  102. caused the replacement.
  103. If the identifier represents a function-like macro
  104. call, the number of actual parameters is checked
  105. against the number of formal parameters. Note that
  106. in ANSI C the parameters are expanded first;
  107. this is done by calling getactuals().
  108. When the possible parameters are expanded, the replace-
  109. ment list associated with "idf" is expanded.
  110. expand_macro() returns 1 if the replacement succeeded
  111. and 0 if some error occurred.
  112. A special case is "defined". This acts as a unary operator
  113. on a single, unexpanded identifier, which may be surrounded
  114. by parenthesis. The function expand_defined() handles this.
  115. */
  116. register struct macro *mac = idf->id_macro;
  117. struct args *args = repl->r_args;
  118. register int ch;
  119. if (mac->mc_nps != -1) { /* with parameter list */
  120. if (mac->mc_flag & FUNC) {
  121. /* the following assertion won't compile:
  122. assert(!strcmp("defined", idf->id_text));
  123. */
  124. if (!AccDefined) return 0;
  125. expand_defined(repl);
  126. return 1;
  127. }
  128. ch = GetChar();
  129. ch = skipspaces(ch,1);
  130. if (ch != '(') { /* no replacement if no () */
  131. ChPushBack(ch);
  132. return 0;
  133. } else
  134. getactuals(repl, idf);
  135. }
  136. if (mac->mc_flag & FUNC) /* this macro leads to special action */
  137. macro_func(idf);
  138. macro2buffer(repl, idf, args);
  139. /* According to the ANSI definition:
  140. #define a +
  141. a+b; --> + + b ;
  142. 'a' must be substituded, but the result should be
  143. three tokens: + + ID. Therefore a token separator is
  144. inserted after the replacement.
  145. */
  146. if (repl->r_text == repl->r_ptr || *(repl->r_ptr -1) != TOKSEP) {
  147. add2repl(repl, TOKSEP);
  148. }
  149. return 1;
  150. }
  151. void expand_defined(struct repl *repl)
  152. {
  153. register int ch = GetChar();
  154. struct idf *id;
  155. char *str;
  156. int parens = 0;
  157. ch = skipspaces(ch, 0);
  158. if (ch == '(') {
  159. parens++;
  160. ch = GetChar();
  161. ch = skipspaces(ch, 0);
  162. }
  163. if ((class(ch) != STIDF) && (class(ch) != STELL)) {
  164. error("identifier missing");
  165. if (parens && ch != ')') error(") missing");
  166. if (!parens || ch != ')') ChPushBack(ch);
  167. add2repl(repl,'0');
  168. return;
  169. }
  170. ChPushBack(ch);
  171. str = GetIdentifier(0);
  172. if (str) {
  173. id = findidf(str);
  174. free(str);
  175. } else id = 0;
  176. ch = GetChar();
  177. ch = skipspaces(ch, 0);
  178. if (parens && ch != ')') error(") missing");
  179. if (!parens || ch != ')') ChPushBack(ch);
  180. add2repl(repl, (id && id->id_macro) ? '1' : '0');
  181. add2repl(repl, ' ');
  182. }
  183. void newarg(struct args *args)
  184. {
  185. args->a_expptr = args->a_expbuf = Malloc((unsigned)(args->a_expsize = ARGBUF));
  186. args->a_rawptr = args->a_rawbuf = Malloc((unsigned)(args->a_rawsize = ARGBUF));
  187. }
  188. void getactuals(struct repl *repl, struct idf *idf)
  189. {
  190. /* Get the actual parameters from the input stream.
  191. The hard part is done by actual(), only comma's and
  192. other syntactic trivialities are checked here.
  193. */
  194. register struct args *args = repl->r_args;
  195. register int nps = idf->id_macro->mc_nps;
  196. register int argcnt;
  197. register int ch;
  198. argcnt = 0;
  199. newarg(args);
  200. if ((ch = GetChar()) != ')') {
  201. UnGetChar();
  202. while ((ch = actual(repl)) != ')' ) {
  203. if (ch != ',') {
  204. error("illegal macro call");
  205. return;
  206. }
  207. stash(repl, '\0', 1);
  208. args->a_expvec[argcnt] = args->a_expbuf;
  209. args->a_rawvec[argcnt] = args->a_rawbuf;
  210. ++argcnt;
  211. if (argcnt == STDC_NPARAMS)
  212. strict("number of parameters exceeds ANSI standard");
  213. if (argcnt >= NPARAMS)
  214. fatal("argument vector overflow");
  215. newarg(args);
  216. }
  217. stash(repl, '\0', 1);
  218. args->a_expvec[argcnt] = args->a_expbuf;
  219. args->a_rawvec[argcnt] = args->a_rawbuf;
  220. ++argcnt;
  221. }
  222. if (argcnt < nps)
  223. error("too few macro arguments");
  224. else if (argcnt > nps)
  225. error("too many macro arguments");
  226. }
  227. void saveraw(struct repl *repl)
  228. {
  229. register struct repl *nrepl = ReplaceList;
  230. register struct args *ap = nrepl->r_args;
  231. register char *p;
  232. /* stash identifier name */
  233. for (p = nrepl->r_idf->id_text; *p != '\0'; p++)
  234. stash(repl, *p, -1);
  235. /* The following code deals with expanded function
  236. like macro calls. It makes the following code
  237. work:
  238. #define def(a,b) x(a,b)
  239. #define glue(a,b) a ## b
  240. glue(abc,def(a,b))
  241. Results in:
  242. abcdef(a,b);
  243. */
  244. if (ap->a_rawvec[0]) {
  245. /* stash arguments */
  246. register int i;
  247. for (i = 0; ap->a_rawvec[i] != (char *)0; i++) {
  248. if (i == 0) stash(repl, '(', -1);
  249. else stash(repl, ',', -1);
  250. for (p = ap->a_rawvec[i]; *p != '\0'; p++)
  251. stash(repl, *p, -1);
  252. }
  253. stash(repl, ')', -1);
  254. }
  255. }
  256. int actual(struct repl *repl)
  257. {
  258. /* This routine deals with the scanning of an actual parameter.
  259. It keeps in account the opening and closing brackets,
  260. preprocessor numbers, strings and character constants.
  261. */
  262. register int ch = 0;
  263. register int level = 0, nostashraw = 0;
  264. int lastch;
  265. static int Unstacked_missed;
  266. while (1) {
  267. lastch = ch;
  268. ch = GetChar();
  269. if (nostashraw
  270. && nostashraw >= Unstacked_missed) {
  271. nostashraw -= Unstacked_missed;
  272. Unstacked_missed = 0;
  273. }
  274. if (Unstacked) {
  275. nostashraw -= Unstacked;
  276. if (nostashraw < 0) {
  277. Unstacked_missed = -nostashraw;
  278. nostashraw = 0;
  279. }
  280. EnableMacros();
  281. }
  282. if (class(ch) == STIDF || class(ch) == STELL) {
  283. /* Scan a preprocessor identifier token. If the
  284. token is a macro, it is expanded first.
  285. */
  286. char buf[(IDFSIZE > NUMSIZE ? IDFSIZE : NUMSIZE) + 1];
  287. register char *p = buf;
  288. register struct idf *idef;
  289. register int pos = -1;
  290. extern int idfsize;
  291. int NoExpandMacro;
  292. if (ch == NOEXPM) {
  293. NoExpandMacro= 1;
  294. ch = GetChar();
  295. } else NoExpandMacro = 0;
  296. do {
  297. if (++pos < idfsize) {
  298. *p++ = ch;
  299. }
  300. ch = GetChar();
  301. } while (in_idf(ch));
  302. *p++ = '\0';
  303. ch = '\0'; /* Could be a non-stashed TOKSEP */
  304. UnGetChar();
  305. /* When the identifier has an associated macro
  306. replacement list, it's expanded.
  307. */
  308. idef = findidf(buf);
  309. if (!idef || NoExpandMacro || !replace(idef)) {
  310. if (NoExpandMacro
  311. || (idef && idef->id_macro
  312. && (idef->id_macro->mc_flag & NOREPLACE)))
  313. stash(repl, NOEXPM, !nostashraw);
  314. for (p = buf; *p != '\0'; p++)
  315. stash(repl, *p, !nostashraw);
  316. } else {
  317. if (!nostashraw) saveraw(repl);
  318. nostashraw++;
  319. }
  320. } else if (class(ch) == STNUM) {
  321. /* a preprocessing number has the following
  322. regular expression:
  323. [0-9|"."[0-9]]{[0-9"."a-zA-Z_]|{[Ee][+-]}}*
  324. */
  325. stash(repl, ch, !nostashraw);
  326. if (ch == '.') {
  327. ch = GetChar();
  328. if (class(ch) != STNUM) {
  329. ch = '\0'; /* Could be a non-stashed TOKSEP */
  330. UnGetChar();
  331. continue;
  332. }
  333. else stash(repl, ch, !nostashraw);
  334. }
  335. ch = GetChar();
  336. while (in_idf(ch) || ch == '.') {
  337. stash(repl, ch, !nostashraw);
  338. if ((ch = GetChar()) == 'e' || ch == 'E') {
  339. stash(repl, ch, !nostashraw);
  340. ch = GetChar();
  341. if (ch == '+' || ch == '-') {
  342. stash(repl, ch, !nostashraw);
  343. ch = GetChar();
  344. }
  345. }
  346. }
  347. ch = '\0'; /* Could be a non-stashed TOKSEP */
  348. UnGetChar();
  349. } else if (ch == '(') {
  350. /* a comma may occur within parentheses */
  351. level++;
  352. stash(repl, ch, !nostashraw);
  353. } else if (ch == ')') {
  354. level--;
  355. /* test on closing parenthesis of macro call */
  356. if (level < 0) return ')';
  357. stash(repl, ch, !nostashraw);
  358. } else if (ch == ',') {
  359. if (level <= 0) { /* comma separator for next argument */
  360. if (level)
  361. error("unbalanced parenthesis");
  362. if (!nostashraw)
  363. return ','; /* ??? */
  364. }
  365. stash(repl, ch, !nostashraw);
  366. } else if (ch == '\n') {
  367. /* newlines are accepted as white spaces */
  368. LineNumber++;
  369. /* This piece of code needs some explanation:
  370. consider the call of a macro defined as:
  371. #define sum(a,b) (a+b)
  372. in the following form:
  373. sum(
  374. /_* comment *_/ #include phone_number
  375. ,2);
  376. in which case the include must be handled
  377. interpreted as such.
  378. */
  379. a_new_line: ch = GetChar();
  380. while (class(ch) == STSKIP || ch == '/') {
  381. if (ch == '/') {
  382. if ((ch = GetChar()) == '*' && !InputLevel) {
  383. skipcomment();
  384. stash(repl, ' ', !nostashraw);
  385. ch = GetChar();
  386. continue;
  387. } else {
  388. UnGetChar();
  389. ch = '/';
  390. }
  391. stash(repl, '/', !nostashraw);
  392. break;
  393. } else ch = GetChar();
  394. }
  395. if (ch == '#') {
  396. domacro();
  397. goto a_new_line;
  398. } else if (ch == EOI) {
  399. error("unterminated macro call");
  400. return ')';
  401. }
  402. if (ch != '/') {
  403. UnGetChar();
  404. ch = ' ';
  405. stash(repl, ' ', !nostashraw);
  406. }
  407. } else if (ch == '/') {
  408. /* comments are treated as one white space token */
  409. if ((ch = GetChar()) == '*' && !InputLevel) {
  410. skipcomment();
  411. stash(repl, ' ', !nostashraw);
  412. } else {
  413. UnGetChar();
  414. ch = '/';
  415. stash(repl, '/', !nostashraw);
  416. }
  417. } else if (ch == '\'' || ch == '"') {
  418. /* Strings are considered as ONE token, thus no
  419. replacement within strings.
  420. */
  421. register int match = ch;
  422. stash(repl, ch, !nostashraw);
  423. while ((ch = GetChar()) != EOI) {
  424. if (ch == match)
  425. break;
  426. if (ch == '\\') {
  427. stash(repl, ch, !nostashraw);
  428. ch = GetChar();
  429. } else if (ch == '\n') {
  430. error("newline in string");
  431. LineNumber++;
  432. stash(repl, match, !nostashraw);
  433. break;
  434. }
  435. stash(repl, ch, !nostashraw);
  436. }
  437. if (ch != match) {
  438. error("unterminated macro call");
  439. return ')';
  440. }
  441. stash(repl, ch, !nostashraw);
  442. } else {
  443. if (lastch == TOKSEP && ch == TOKSEP) continue;
  444. stash(repl, ch, !nostashraw);
  445. }
  446. }
  447. }
  448. void macro_func(struct idf *idef)
  449. {
  450. /* macro_func() performs the special actions needed with some
  451. macros. These macros are __FILE__ and __LINE__ which
  452. replacement texts must be evaluated at the time they are
  453. used.
  454. */
  455. register struct macro *mac = idef->id_macro;
  456. static char FilNamBuf[PATHLENGTH];
  457. char *long2str();
  458. switch (idef->id_text[2]) {
  459. case 'F': /* __FILE__ */
  460. FilNamBuf[0] = '"';
  461. strcpy(&FilNamBuf[1], FileName);
  462. strcat(FilNamBuf, "\"");
  463. mac->mc_text = FilNamBuf;
  464. mac->mc_length = strlen(FilNamBuf);
  465. break;
  466. case 'L': /* __LINE__ */
  467. mac->mc_text = long2str((long)LineNumber, 10);
  468. mac->mc_length = strlen(mac->mc_text);
  469. break;
  470. default:
  471. crash("(macro_func)");
  472. /*NOTREACHED*/
  473. }
  474. }
  475. void macro2buffer(struct repl *repl, struct idf *idf, struct args *args)
  476. {
  477. /* macro2buffer expands the replacement list and places the
  478. result onto the replacement buffer. It deals with the #
  479. and ## operators, and inserts the actual parameters.
  480. The argument buffer contains the raw argument (needed
  481. for the # and ## operators), and the expanded argument
  482. (for all other parameter substitutions).
  483. The grammar of the replacement list is:
  484. repl_list: TOKEN repl_list
  485. | PARAMETER repl_list
  486. | '#' PARAMETER
  487. | TOKEN '##' TOKEN
  488. | PARAMETER '##' TOKEN
  489. | TOKEN '##' PARAMETER
  490. | PARAMETER '##' PARAMETER
  491. ;
  492. As the grammar indicates, we could make a DFA and
  493. use this finite state machine for the replacement
  494. list parsing (inserting the arguments, etc.).
  495. Currently we go through the replacement list in a
  496. linear fashion. This is VERY expensive, something
  497. smarter should be done (but even a DFA is O(|s|)).
  498. */
  499. register char *ptr = idf->id_macro->mc_text;
  500. int err = 0;
  501. int func = idf->id_macro->mc_nps != -1;
  502. char *stringify();
  503. assert(ptr[idf->id_macro->mc_length] == '\0');
  504. while (*ptr) {
  505. if (*ptr == '\'' || *ptr == '"') {
  506. register int delim = *ptr;
  507. do {
  508. add2repl(repl, *ptr);
  509. if (*ptr == '\\')
  510. add2repl(repl, *++ptr);
  511. if (*ptr == '\0') {
  512. error("unterminated string");
  513. return;
  514. }
  515. ptr++;
  516. } while (*ptr != delim || *ptr == '\0');
  517. add2repl(repl, *ptr++);
  518. } else if (*ptr == '#' && (func || *(ptr+1) == '#')) {
  519. if (*++ptr == '#') {
  520. register int tmpindex;
  521. /* ## - paste operator */
  522. ptr++;
  523. /* trim the actual replacement list */
  524. --repl->r_ptr;
  525. while (repl->r_ptr >= repl->r_text
  526. && is_wsp(*(unsigned char *)repl->r_ptr))
  527. --repl->r_ptr;
  528. /* ## occurred at the beginning of the replacement list.
  529. */
  530. if (repl->r_ptr < repl->r_text) {
  531. err = 1;
  532. break;
  533. }
  534. if (repl->r_ptr >= repl->r_text
  535. && *repl->r_ptr == TOKSEP)
  536. --repl->r_ptr;
  537. ++repl->r_ptr;
  538. tmpindex = repl->r_ptr - repl->r_text;
  539. /* tmpindex can be 0 */
  540. /* skip space in macro replacement list */
  541. while ((*ptr & FORMALP) == 0 && is_wsp(*(unsigned char *)ptr))
  542. ptr++;
  543. /* ## occurred at the end of the replacement list.
  544. */
  545. if (*ptr & FORMALP) {
  546. register int n = *ptr++ & 0177;
  547. register char *p;
  548. assert(n > 0);
  549. p = args->a_rawvec[n-1];
  550. if (p) { /* else macro argument missing */
  551. while (is_wsp(*(unsigned char *)p)) p++;
  552. if (*p == NOEXPM) p++;
  553. while (*p)
  554. add2repl(repl, *p++);
  555. }
  556. while (tmpindex > 0
  557. && in_idf((unsigned char)repl->r_text[tmpindex]))
  558. tmpindex--;
  559. if (tmpindex >= 0
  560. && repl->r_text[tmpindex] == NOEXPM)
  561. repl->r_text[tmpindex] = TOKSEP;
  562. } else if (*ptr == '\0') {
  563. err = 1;
  564. break;
  565. } else {
  566. if (in_idf(*(unsigned char *)ptr)) {
  567. tmpindex--;
  568. while (tmpindex > 0
  569. && in_idf((unsigned char)repl->r_text[tmpindex]))
  570. tmpindex--;
  571. if (tmpindex >= 0
  572. && repl->r_text[tmpindex] == NOEXPM)
  573. repl->r_text[tmpindex] = TOKSEP;
  574. }
  575. }
  576. } else { /* # operator */
  577. ptr = stringify(repl, ptr, args);
  578. }
  579. } else if (*ptr & FORMALP) {
  580. /* insert actual parameter */
  581. register int n = *ptr++ & 0177;
  582. register char *p, *q;
  583. assert(n > 0);
  584. /* This is VERY dirty, we look ahead for the
  585. ## operator. If it's found we use the raw
  586. argument buffer instead of the expanded
  587. one.
  588. */
  589. for (p = ptr; (*p & FORMALP) == 0 && is_wsp(*(unsigned char *)p); p++)
  590. /* EMPTY */;
  591. if (*p == '#' && p[1] == '#')
  592. q = args->a_rawvec[n-1];
  593. else
  594. q = args->a_expvec[n-1];
  595. if (q) /* else macro argument missing */
  596. while (*q)
  597. add2repl(repl, *q++);
  598. if (repl->r_text == repl->r_ptr || *(repl->r_ptr-1) != TOKSEP)
  599. add2repl(repl, TOKSEP);
  600. } else {
  601. add2repl(repl, *ptr++);
  602. }
  603. }
  604. if (err)
  605. error("illegal use of ## operator");
  606. }
  607. char *stringify(struct repl *repl, char *ptr, struct args *args)
  608. {
  609. /* If a parameter is immediately preceded by a # token
  610. both are replaced by a single string literal that
  611. contains the spelling of the token sequence for the
  612. corresponding argument.
  613. Each occurrence of white space between the argument's
  614. tokens become a single space character in the string
  615. literal. White spaces before the first token and after
  616. the last token comprising the argument are deleted.
  617. To retain the original spelling we insert backslashes
  618. as appropriate. We only escape backslashes if they
  619. occure within string tokens.
  620. */
  621. register int space = 1; /* skip leading spaces */
  622. register int delim = 0; /* string or character constant delim */
  623. register int backslash = 0; /* last character was a \ */
  624. /* skip spaces macro replacement list */
  625. while ((*ptr & FORMALP) == 0 && is_wsp(*(unsigned char *)ptr))
  626. ptr++;
  627. if (*ptr & FORMALP) {
  628. register int n = *ptr++ & 0177;
  629. register char *p;
  630. assert(n != 0);
  631. p = args->a_rawvec[n-1];
  632. add2repl(repl, '"');
  633. while (*p) {
  634. if (is_wsp(*(unsigned char *)p)) {
  635. if (!space) {
  636. space = 1;
  637. add2repl(repl, ' ');
  638. }
  639. p++;
  640. continue;
  641. }
  642. space = 0;
  643. if (!delim && (*p == '"' || *p == '\''))
  644. delim = *p;
  645. else if (*p == delim && !backslash)
  646. delim = 0;
  647. backslash = *p == '\\';
  648. if (*p == '"' || (delim && *p == '\\'))
  649. add2repl(repl, '\\');
  650. if (*p == TOKSEP || *p == NOEXPM) p++;
  651. else add2repl(repl, *p++);
  652. }
  653. /* trim spaces in the replacement list */
  654. for (--repl->r_ptr; is_wsp(*(unsigned char *)repl->r_ptr); repl->r_ptr--)
  655. /* EMPTY */;
  656. ++repl->r_ptr; /* oops, one to far */
  657. add2repl(repl, '"');
  658. } else
  659. error("illegal use of # operator");
  660. return ptr;
  661. }
  662. /* The following routine is also called from domacro.c.
  663. */
  664. void add2repl(struct repl *repl, int ch)
  665. {
  666. register int index = repl->r_ptr - repl->r_text;
  667. assert(index < repl->r_size);
  668. if (index + 2 >= repl->r_size) {
  669. repl->r_text = Realloc(repl->r_text, (unsigned)(repl->r_size <<= 1));
  670. repl->r_ptr = repl->r_text + index;
  671. }
  672. *repl->r_ptr++ = ch;
  673. *repl->r_ptr = '\0';
  674. }
  675. /* If the variable stashraw is negative, we must only stash into the raw
  676. * buffer. If the variable is zero, we must only stash into the expanded
  677. * buffer. Otherwise, we must use both buffers.
  678. */
  679. void stash(struct repl *repl, int ch, int stashraw)
  680. {
  681. /* Stash characters into the macro expansion buffer.
  682. */
  683. register struct args *args = repl->r_args;
  684. register int index = args->a_expptr - args->a_expbuf;
  685. if (stashraw >= 0) {
  686. assert(index < args->a_expsize);
  687. if (index + 1 >= args->a_expsize) {
  688. args->a_expbuf = Realloc(args->a_expbuf,
  689. (unsigned)(args->a_expsize <<= 1));
  690. args->a_expptr = args->a_expbuf + index;
  691. }
  692. *args->a_expptr++ = ch;
  693. }
  694. if (stashraw) {
  695. index = args->a_rawptr - args->a_rawbuf;
  696. assert(index < args->a_rawsize);
  697. if (index + 1 >= args->a_rawsize) {
  698. args->a_rawbuf = Realloc(args->a_rawbuf,
  699. (unsigned)(args->a_rawsize <<= 1));
  700. args->a_rawptr = args->a_rawbuf + index;
  701. }
  702. *args->a_rawptr++ = ch;
  703. }
  704. }