domacro.c 15 KB

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