domacro.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  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. /* PREPROCESSOR: CONTROLLINE INTERPRETER */
  7. #include <stdlib.h>
  8. #include <string.h>
  9. #include "interface.h"
  10. #include "LLlex.h"
  11. #include "Lpars.h"
  12. #include "debug.h"
  13. #include "idf.h"
  14. #include "input.h"
  15. #include "ifdepth.h"
  16. #include "botch_free.h"
  17. #include "nparams.h"
  18. #include "parbufsize.h"
  19. #include "textsize.h"
  20. #include "idfsize.h"
  21. #include <assert.h>
  22. #include <alloc.h>
  23. #include "class.h"
  24. #include "macro.h"
  25. #include "bits.h"
  26. extern char **inctable; /* list of include directories */
  27. static char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
  28. /* 1 if a corresponding ELSE has been */
  29. /* encountered. */
  30. int nestlevel = -1;
  31. int svnestlevel[30] = {-1};
  32. int nestcount;
  33. extern int do_preprocess;
  34. /* Prototypes */
  35. static int ifexpr();
  36. static void do_include();
  37. static void do_define();
  38. static void push_if();
  39. static void do_elif();
  40. static void do_else();
  41. static void do_if();
  42. static void do_endif();
  43. static void do_ifdef(int how);
  44. static void do_undef();
  45. static void do_line(unsigned int l);
  46. static int getparams(char *buf[], char parbuf[]);
  47. static int macroeq(char *s, char *t);
  48. static char *get_text(char *formals[], int *length);
  49. /* Externel dependency */
  50. char * getwdir(char *fn);
  51. char *GetIdentifier()
  52. {
  53. /* returns a pointer to the descriptor of the identifier that is
  54. read from the input stream. A null-pointer is returned if
  55. the input does not contain an identifier.
  56. The substitution of macros is disabled.
  57. */
  58. int tok;
  59. struct token tk;
  60. ReplaceMacros = 0;
  61. tok = GetToken(&tk);
  62. ReplaceMacros = 1;
  63. return tok == IDENTIFIER ? tk.tk_str : (char *)0;
  64. }
  65. /* domacro() is the control line interpreter. The '#' has already
  66. been read by the lexical analyzer by which domacro() is called.
  67. The token appearing directly after the '#' is obtained by calling
  68. the basic lexical analyzing function GetToken() and is interpreted
  69. to perform the action belonging to that token.
  70. An error message is produced when the token is not recognized,
  71. i.e. it is not one of "define" .. "undef" , integer or newline.
  72. */
  73. void domacro()
  74. {
  75. struct token tk; /* the token itself */
  76. struct idf *id;
  77. switch(GetToken(&tk)) { /* select control line action */
  78. case IDENTIFIER: /* is it a macro keyword? */
  79. id = findidf(tk.tk_str);
  80. if (!id) {
  81. error("%s: unknown control", tk.tk_str);
  82. skipline();
  83. free(tk.tk_str);
  84. break;
  85. }
  86. free(tk.tk_str);
  87. switch (id->id_resmac) {
  88. case K_DEFINE: /* "define" */
  89. do_define();
  90. break;
  91. case K_ELIF: /* "elif" */
  92. do_elif();
  93. break;
  94. case K_ELSE: /* "else" */
  95. do_else();
  96. break;
  97. case K_ENDIF: /* "endif" */
  98. do_endif();
  99. break;
  100. case K_IF: /* "if" */
  101. do_if();
  102. break;
  103. case K_IFDEF: /* "ifdef" */
  104. do_ifdef(1);
  105. break;
  106. case K_IFNDEF: /* "ifndef" */
  107. do_ifdef(0);
  108. break;
  109. case K_INCLUDE: /* "include" */
  110. do_include();
  111. break;
  112. case K_LINE: /* "line" */
  113. /* set LineNumber and FileName according to
  114. the arguments.
  115. */
  116. if (GetToken(&tk) != INTEGER) {
  117. error("#line without linenumber");
  118. PushBack();
  119. skipline();
  120. }
  121. else
  122. do_line((unsigned int)tk.tk_val);
  123. break;
  124. case K_UNDEF: /* "undef" */
  125. do_undef();
  126. break;
  127. case K_PRAGMA: /* "pragma" */
  128. /* ignore for now
  129. */
  130. skipline();
  131. break;
  132. default:
  133. /* invalid word seen after the '#' */
  134. error("%s: unknown control", id->id_text);
  135. skipline();
  136. }
  137. break;
  138. case INTEGER: /* # <integer> [<filespecifier>]? */
  139. do_line((unsigned int)tk.tk_val);
  140. break;
  141. case EOF: /* only `#' on this line: do nothing, ignore */
  142. break;
  143. default: /* invalid token following '#' */
  144. error("illegal # line");
  145. PushBack();
  146. skipline();
  147. }
  148. }
  149. static void skip_block(int to_endif)
  150. {
  151. /* skip_block() skips the input from
  152. 1) a false #if, #ifdef, #ifndef or #elif until the
  153. corresponding #elif (resulting in true), #else or
  154. #endif is read.
  155. 2) a #else corresponding to a true #if, #ifdef,
  156. #ifndef or #elif until the corresponding #endif is
  157. seen.
  158. */
  159. int ch;
  160. int skiplevel = nestlevel; /* current nesting level */
  161. struct token tk;
  162. struct idf *id;
  163. NoUnstack++;
  164. for (;;) {
  165. LoadChar(ch); /* read first character after newline */
  166. if (ch != '#') {
  167. if (ch == EOI) {
  168. NoUnstack--;
  169. return;
  170. }
  171. PushBack();
  172. skipline();
  173. continue;
  174. }
  175. if (GetToken(&tk) != IDENTIFIER) {
  176. PushBack();
  177. skipline();
  178. continue;
  179. }
  180. /* an IDENTIFIER: look for #if, #ifdef and #ifndef
  181. without interpreting them.
  182. Interpret #else, #elif and #endif if they occur
  183. on the same level.
  184. */
  185. id = findidf(tk.tk_str);
  186. free(tk.tk_str);
  187. if (id) switch(id->id_resmac) {
  188. default:
  189. skipline();
  190. break;
  191. case K_IF:
  192. case K_IFDEF:
  193. case K_IFNDEF:
  194. push_if();
  195. skipline();
  196. continue;
  197. case K_ELIF:
  198. if (ifstack[nestlevel])
  199. warning("#elif after #else/#elif");
  200. if (! to_endif && nestlevel == skiplevel) {
  201. nestlevel--;
  202. push_if();
  203. if (ifexpr()) { /* implicit skipline() */
  204. NoUnstack--;
  205. return;
  206. }
  207. }
  208. else skipline();
  209. break;
  210. case K_ELSE:
  211. if (ifstack[nestlevel])
  212. warning("#else after #else/#elif");
  213. skipline();
  214. if (! to_endif) {
  215. ++(ifstack[nestlevel]);
  216. if (nestlevel == skiplevel) {
  217. NoUnstack--;
  218. return;
  219. }
  220. }
  221. break;
  222. case K_ENDIF:
  223. assert(nestlevel >= 0);
  224. skipline();
  225. if (nestlevel == skiplevel) {
  226. nestlevel--;
  227. NoUnstack--;
  228. return;
  229. }
  230. nestlevel--;
  231. break;
  232. }
  233. }
  234. }
  235. static int ifexpr()
  236. {
  237. /* ifexpr() returns whether the restricted constant
  238. expression following #if or #elif evaluates to true. This
  239. is done by calling the LLgen generated subparser for
  240. constant expressions. The result of this expression will
  241. be given in the extern long variable "ifval".
  242. */
  243. extern arith ifval;
  244. int errors = err_occurred;
  245. ifval = (arith)0;
  246. AccDefined = 1;
  247. UnknownIdIsZero = 1;
  248. PushLex(); /* NEW parser */
  249. If_expr(); /* invoke constant expression parser */
  250. PopLex(); /* OLD parser */
  251. AccDefined = 0;
  252. UnknownIdIsZero = 0;
  253. return (errors == err_occurred) && (ifval != (arith)0);
  254. }
  255. static void do_include()
  256. {
  257. /* do_include() performs the inclusion of a file.
  258. */
  259. char *filenm;
  260. char *result;
  261. int tok;
  262. struct token tk;
  263. AccFileSpecifier = 1;
  264. if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
  265. filenm = tk.tk_str;
  266. else {
  267. error("bad include syntax");
  268. filenm = (char *)0;
  269. }
  270. AccFileSpecifier = 0;
  271. PushBack();
  272. skipline();
  273. inctable[0] = WorkingDir;
  274. if (filenm) {
  275. if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
  276. if (do_preprocess) error("cannot find include file \"%s\"", filenm);
  277. else warning("cannot find include file \"%s\"", filenm);
  278. add_dependency(filenm);
  279. }
  280. else {
  281. add_dependency(result);
  282. WorkingDir = getwdir(result);
  283. svnestlevel[++nestcount] = nestlevel;
  284. FileName = result;
  285. LineNumber = 1;
  286. }
  287. }
  288. }
  289. static void do_define()
  290. {
  291. /* do_define() interprets a #define control line.
  292. */
  293. char *str;
  294. int nformals = -1; /* keep track of the number of formals */
  295. char *formals[NPARAMS]; /* pointers to the names of the formals */
  296. char parbuf[PARBUFSIZE]; /* names of formals */
  297. char *repl_text; /* start of the replacement text */
  298. int length; /* length of the replacement text */
  299. int ch;
  300. /* read the #defined macro's name */
  301. if (!(str = GetIdentifier())) {
  302. error("#define: illegal macro name");
  303. PushBack();
  304. skipline();
  305. return;
  306. }
  307. /* there is a formal parameter list if the identifier is
  308. followed immediately by a '('.
  309. */
  310. LoadChar(ch);
  311. if (ch == '(') {
  312. if ((nformals = getparams(formals, parbuf)) == -1) {
  313. PushBack();
  314. skipline();
  315. free(str);
  316. return; /* an error occurred */
  317. }
  318. LoadChar(ch);
  319. }
  320. /* read the replacement text if there is any */
  321. ch = skipspaces(ch,0); /* find first character of the text */
  322. assert(ch != EOI);
  323. if (class(ch) == STNL) {
  324. /* Treat `#define something' as `#define something ""'
  325. */
  326. repl_text = "";
  327. length = 0;
  328. }
  329. else {
  330. PushBack();
  331. repl_text = get_text((nformals > 0) ? formals : 0, &length);
  332. }
  333. macro_def(str2idf(str, 0), repl_text, nformals, length, NOFLAG);
  334. LineNumber++;
  335. }
  336. static void push_if()
  337. {
  338. if (nestlevel >= IFDEPTH)
  339. fatal("too many nested #if/#ifdef/#ifndef");
  340. else
  341. ifstack[++nestlevel] = 0;
  342. }
  343. static void do_elif()
  344. {
  345. if (nestlevel <= svnestlevel[nestcount] || (ifstack[nestlevel])) {
  346. error("#elif without corresponding #if");
  347. skipline();
  348. }
  349. else { /* restart at this level as if a #if is detected. */
  350. nestlevel--;
  351. push_if();
  352. skip_block(1);
  353. }
  354. }
  355. static void do_else()
  356. {
  357. skipline();
  358. if (nestlevel <= svnestlevel[nestcount] || (ifstack[nestlevel]))
  359. error("#else without corresponding #if");
  360. else { /* mark this level as else-d */
  361. ++(ifstack[nestlevel]);
  362. skip_block(1);
  363. }
  364. }
  365. static void do_endif()
  366. {
  367. skipline();
  368. if (nestlevel <= svnestlevel[nestcount])
  369. error("#endif without corresponding #if");
  370. else nestlevel--;
  371. }
  372. static void do_if()
  373. {
  374. push_if();
  375. if (!ifexpr()) /* a false #if/#elif expression */
  376. skip_block(0);
  377. }
  378. static void do_ifdef(int how)
  379. {
  380. struct idf *id;
  381. char *str;
  382. /* how == 1 : ifdef; how == 0 : ifndef
  383. */
  384. push_if();
  385. str = GetIdentifier();
  386. if (!str) {
  387. error("illegal #ifdef construction");
  388. id = 0;
  389. }
  390. else {
  391. id = findidf(str);
  392. free(str);
  393. }
  394. /* The next test is a shorthand for:
  395. (how && !id->id_macro) || (!how && id->id_macro)
  396. */
  397. if (how ^ (id && id->id_macro != 0))
  398. skip_block(0);
  399. else {
  400. PushBack();
  401. skipline();
  402. }
  403. }
  404. static void do_undef()
  405. {
  406. struct idf *id;
  407. char *str = GetIdentifier();
  408. /* Forget a macro definition. */
  409. if (str) {
  410. if ((id = findidf(str))) {
  411. if (id->id_macro) { /* forget the macro */
  412. free_macro(id->id_macro);
  413. id->id_macro = (struct macro *) 0;
  414. } /* else: don't complain */
  415. }
  416. free(str);
  417. }
  418. else
  419. error("illegal #undef construction");
  420. PushBack();
  421. skipline();
  422. }
  423. static void do_line(unsigned int l)
  424. {
  425. struct token tk;
  426. int t = GetToken(&tk);
  427. PushBack();
  428. skipline();
  429. LineNumber = l; /* the number of the next input line */
  430. if (t == STRING) /* is there a filespecifier? */
  431. FileName = tk.tk_str;
  432. }
  433. static int getparams(char *buf[], char parbuf[])
  434. {
  435. /* getparams() reads the formal parameter list of a macro
  436. definition.
  437. The number of parameters is returned.
  438. As a formal parameter list is expected when calling this
  439. routine, -1 is returned if an error is detected, for
  440. example:
  441. #define one(1), where 1 is not an identifier.
  442. Note that the '(' has already been eaten.
  443. The names of the formal parameters are stored into parbuf.
  444. */
  445. char **pbuf = &buf[0];
  446. int c;
  447. char *ptr = &parbuf[0];
  448. char **pbuf2;
  449. LoadChar(c);
  450. c = skipspaces(c,0);
  451. if (c == ')') { /* no parameters: #define name() */
  452. *pbuf = (char *) 0;
  453. return 0;
  454. }
  455. for (;;) { /* eat the formal parameter list */
  456. if (class(c) != STIDF) { /* not an identifier */
  457. error("#define: bad formal parameter");
  458. return -1;
  459. }
  460. *pbuf = ptr; /* name of the formal */
  461. *ptr++ = c;
  462. if (ptr >= &parbuf[PARBUFSIZE])
  463. fatal("formal parameter buffer overflow");
  464. do { /* eat the identifier name */
  465. LoadChar(c);
  466. *ptr++ = c;
  467. if (ptr >= &parbuf[PARBUFSIZE])
  468. fatal("formal parameter buffer overflow");
  469. } while (in_idf(c));
  470. *(ptr - 1) = '\0'; /* mark end of the name */
  471. /* Check if this formal parameter is already used.
  472. Usually, macros do not have many parameters, so ...
  473. */
  474. for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
  475. if (!strcmp(*pbuf2, *pbuf)) {
  476. warning("formal parameter \"%s\" already used",
  477. *pbuf);
  478. }
  479. }
  480. pbuf++;
  481. c = skipspaces(c,0);
  482. if (c == ')') { /* end of the formal parameter list */
  483. *pbuf = (char *) 0;
  484. return pbuf - buf;
  485. }
  486. if (c != ',') {
  487. error("#define: bad formal parameter list");
  488. return -1;
  489. }
  490. LoadChar(c);
  491. c = skipspaces(c,0);
  492. }
  493. /*NOTREACHED*/
  494. }
  495. void macro_def(struct idf *id, char *text, int nformals, int length, int flags)
  496. {
  497. /* macro_def() puts the contents and information of a macro
  498. definition into a structure and stores it into the symbol
  499. table entry belonging to the name of the macro.
  500. A warning is given if the definition overwrites another.
  501. */
  502. struct macro *newdef = id->id_macro;
  503. if (newdef) { /* is there a redefinition? */
  504. if (macroeq(newdef->mc_text, text))
  505. return;
  506. warning("redefine \"%s\"", id->id_text);
  507. }
  508. else {
  509. #ifdef DOBITS
  510. unsigned char *p = (unsigned char *)id->id_text;
  511. #define setbit(bx) if (!*p) goto go_on; bits[*p++] |= (bx)
  512. setbit(bit0);
  513. setbit(bit1);
  514. setbit(bit2);
  515. setbit(bit3);
  516. setbit(bit4);
  517. setbit(bit5);
  518. setbit(bit6);
  519. setbit(bit7);
  520. go_on:
  521. #endif
  522. id->id_macro = newdef = new_macro();
  523. }
  524. newdef->mc_text = text; /* replacement text */
  525. newdef->mc_nps = nformals; /* nr of formals */
  526. newdef->mc_length = length; /* length of repl. text */
  527. newdef->mc_flag = flags; /* special flags */
  528. newdef->mc_count = 0;
  529. }
  530. static int find_name(char *nm, char *index[])
  531. {
  532. /* find_name() returns the index of "nm" in the namelist
  533. "index" if it can be found there. 0 is returned if it is
  534. not there.
  535. */
  536. char **ip = &index[0];
  537. while (*ip)
  538. if (strcmp(nm, *ip++) == 0)
  539. return ip - &index[0];
  540. /* arrived here, nm is not in the name list. */
  541. return 0;
  542. }
  543. static char *get_text(char *formals[], int *length)
  544. {
  545. /* get_text() copies the replacement text of a macro
  546. definition with zero, one or more parameters, thereby
  547. substituting each formal parameter by a special character
  548. (non-ascii: 0200 & (order-number in the formal parameter
  549. list)) in order to substitute this character later by the
  550. actual parameter. The replacement text is copied into
  551. itself because the copied text will contain fewer or the
  552. same amount of characters. The length of the replacement
  553. text is returned.
  554. Implementation:
  555. finite automaton : we are only interested in
  556. identifiers, because they might be replaced by some actual
  557. parameter. Other tokens will not be seen as such.
  558. */
  559. int c;
  560. unsigned int text_size;
  561. char *text = Malloc(text_size = ITEXTSIZE);
  562. unsigned int pos = 0;
  563. LoadChar(c);
  564. while ((c != EOI) && (class(c) != STNL)) {
  565. if (c == '\\') { /* check for "\\\n" */
  566. LoadChar(c);
  567. if (c == '\n') {
  568. /* More than one line is used for the
  569. replacement text.
  570. Replace "\\\n" by " ".
  571. */
  572. text[pos++] = ' ';
  573. ++LineNumber;
  574. LoadChar(c);
  575. }
  576. else
  577. text[pos++] = '\\';
  578. if (pos == text_size)
  579. text = Realloc(text, text_size <<= 1);
  580. }
  581. else
  582. if ( c == '/') {
  583. LoadChar(c);
  584. if (c == '*') {
  585. skipcomment();
  586. /* text[pos++] = ' '; ??? Why ??? */
  587. LoadChar(c);
  588. }
  589. else
  590. text[pos++] = '/';
  591. if (pos == text_size)
  592. text = Realloc(text, text_size <<= 1);
  593. }
  594. else
  595. if (formals && class(c) == STIDF) {
  596. char id_buf[IDFSIZE + 1];
  597. char *idp = id_buf;
  598. int n;
  599. /* read identifier: it may be a formal parameter */
  600. *idp++ = c;
  601. do {
  602. LoadChar(c);
  603. if (idp <= &id_buf[IDFSIZE])
  604. *idp++ = c;
  605. } while (in_idf(c));
  606. *--idp = '\0';
  607. if ((n = find_name(id_buf, formals))) {
  608. /* construct the formal parameter mark */
  609. text[pos++] = FORMALP | (char) n;
  610. if (pos == text_size)
  611. text = Realloc(text,
  612. text_size <<= 1);
  613. }
  614. else {
  615. int sz = idp - id_buf + 1;
  616. idp = id_buf;
  617. while (pos + sz >= text_size) text_size <<= 1;
  618. text = Realloc(text, text_size);
  619. while ((text[pos++] = *idp++)) ;
  620. pos--;
  621. }
  622. }
  623. else {
  624. text[pos++] = c;
  625. if (pos == text_size)
  626. text = Realloc(text, text_size <<= 1);
  627. LoadChar(c);
  628. }
  629. }
  630. text[pos++] = '\0';
  631. text = Realloc(text, pos);
  632. *length = pos - 1;
  633. return text;
  634. }
  635. #define BLANK(ch) ((ch == ' ') || (ch == '\t'))
  636. /* macroeq() decides whether two macro replacement texts are
  637. identical. This version compares the texts, which occur
  638. as strings, without taking care of the leading and trailing
  639. blanks (spaces and tabs).
  640. */
  641. static int macroeq(char *s, char *t)
  642. {
  643. /* skip leading spaces */
  644. while (BLANK(*s)) s++;
  645. while (BLANK(*t)) t++;
  646. /* first non-blank encountered in both strings */
  647. /* The actual comparison loop: */
  648. while (*s && *s == *t)
  649. s++, t++;
  650. /* two cases are possible when arrived here: */
  651. if (*s == '\0') { /* *s == '\0' */
  652. while (BLANK(*t)) t++;
  653. return *t == '\0';
  654. }
  655. else { /* *s != *t */
  656. while (BLANK(*s)) s++;
  657. while (BLANK(*t)) t++;
  658. return (*s == '\0') && (*t == '\0');
  659. }
  660. }