domacro.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  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 "debug.h"
  10. #include "specials.h"
  11. #include "arith.h"
  12. #include "LLlex.h"
  13. #include "Lpars.h"
  14. #include "idf.h"
  15. #include "input.h"
  16. #include "nopp.h"
  17. #include "lint.h"
  18. #include "skip.h"
  19. #include "domacro.h"
  20. #include "error.h"
  21. #include "pragma.h"
  22. #include "program.h"
  23. #include "main.h"
  24. #include "replace_loc.h"
  25. #ifndef NOPP
  26. #include "ifdepth.h"
  27. #include "botch_free.h"
  28. #include "nparams.h"
  29. #include "parbufsize.h"
  30. #include "textsize.h"
  31. #include "idfsize.h"
  32. #include "assert.h"
  33. #include <alloc.h>
  34. #include "class.h"
  35. #include "macro.h"
  36. #include "macbuf.h"
  37. #include "replace.h"
  38. #include "dbsymtab.h"
  39. #ifdef DBSYMTAB
  40. #include <stb.h>
  41. #include <em.h>
  42. int IncludeLevel = 0;
  43. #endif
  44. extern char options[];
  45. extern char **inctable; /* list of include directories */
  46. char ifstack[IFDEPTH]; /* if-stack: the content of an entry is */
  47. /* 1 if a corresponding ELSE has been */
  48. /* encountered. */
  49. int nestlevel = -1;
  50. extern char *getwdir();
  51. /* skiponerr -> skip the rest of the line on error */
  52. struct idf *GetIdentifier(int skiponerr)
  53. {
  54. /* returns a pointer to the descriptor of the identifier that is
  55. read from the input stream. When the input doe not contain
  56. an identifier, the rest of the line is skipped when
  57. skiponerr is on, and a null-pointer is returned.
  58. The substitution of macros is disabled.
  59. */
  60. int tmp = UnknownIdIsZero;
  61. int tok;
  62. struct token tk;
  63. UnknownIdIsZero = ReplaceMacros = 0;
  64. tok = GetToken(&tk);
  65. ReplaceMacros = 1;
  66. UnknownIdIsZero = tmp;
  67. if (tok != IDENTIFIER) {
  68. if (skiponerr && tok != EOI) SkipToNewLine();
  69. return (struct idf *)0;
  70. }
  71. return tk.tk_idf;
  72. }
  73. /* domacro() is the control line interpreter. The '#' has already
  74. been read by the lexical analyzer by which domacro() is called.
  75. The token appearing directly after the '#' is obtained by calling
  76. the basic lexical analyzing function GetToken() and is interpreted
  77. to perform the action belonging to that token.
  78. An error message is produced when the token is not recognized,
  79. i.e. it is not one of "define" .. "undef" , integer or newline.
  80. */
  81. void domacro()
  82. {
  83. struct token tk; /* the token itself */
  84. int toknum;
  85. EoiForNewline = 1;
  86. ReplaceMacros = 0;
  87. toknum = GetToken(&tk);
  88. ReplaceMacros = 1;
  89. switch(toknum) { /* select control line action */
  90. case IDENTIFIER: /* is it a macro keyword? */
  91. switch (tk.tk_idf->id_resmac) {
  92. case K_DEFINE: /* "define" */
  93. do_define();
  94. break;
  95. case K_ELIF: /* "elif" */
  96. do_elif();
  97. break;
  98. case K_ELSE: /* "else" */
  99. do_else();
  100. break;
  101. case K_ENDIF: /* "endif" */
  102. do_endif();
  103. break;
  104. case K_IF: /* "if" */
  105. do_if();
  106. break;
  107. case K_IFDEF: /* "ifdef" */
  108. do_ifdef(1);
  109. break;
  110. case K_IFNDEF: /* "ifndef" */
  111. do_ifdef(0);
  112. break;
  113. case K_INCLUDE: /* "include" */
  114. do_include();
  115. break;
  116. case K_LINE: /* "line" */
  117. /* set LineNumber and FileName according to
  118. the arguments.
  119. */
  120. if (GetToken(&tk) != INTEGER) {
  121. lexerror("bad #line syntax");
  122. SkipToNewLine();
  123. }
  124. else
  125. do_line((unsigned int)tk.tk_ival);
  126. break;
  127. case K_ERROR: /* "error" */
  128. do_error();
  129. break;
  130. case K_WARNING: /* "warning" */
  131. do_warning();
  132. break;
  133. case K_PRAGMA: /* "pragma" */
  134. do_pragma();
  135. break;
  136. case K_UNDEF: /* "undef" */
  137. do_undef((struct idf *) 0);
  138. break;
  139. default:
  140. /* invalid word seen after the '#' */
  141. lexerror("%s: unknown control", tk.tk_idf->id_text);
  142. SkipToNewLine();
  143. }
  144. break;
  145. case INTEGER: /* # <integer> [<filespecifier>]? */
  146. do_line((unsigned int)tk.tk_ival);
  147. break;
  148. case EOI: /* only `#' on this line: do nothing, ignore */
  149. break;
  150. default: /* invalid token following '#' */
  151. lexerror("illegal # line");
  152. SkipToNewLine();
  153. }
  154. EoiForNewline = 0;
  155. }
  156. #ifdef LINT
  157. int lint_skip_comment;
  158. #endif
  159. void skip_block(int to_endif)
  160. {
  161. /* skip_block() skips the input from
  162. 1) a false #if, #ifdef, #ifndef or #elif until the
  163. corresponding #elif (resulting in true), #else or
  164. #endif is read.
  165. 2) a #else corresponding to a true #if, #ifdef,
  166. #ifndef or #elif until the corresponding #endif is
  167. seen.
  168. */
  169. int ch;
  170. int skiplevel = nestlevel; /* current nesting level */
  171. struct token tk;
  172. int toknum;
  173. #ifdef LINT
  174. lint_skip_comment++;
  175. #endif
  176. NoUnstack++;
  177. for (;;) {
  178. ch = GetChar(); /* read first character after newline */
  179. while (class(ch) == STSKIP)
  180. ch = GetChar();
  181. if (ch != '#') {
  182. if (ch == EOI) {
  183. NoUnstack--;
  184. #ifdef LINT
  185. lint_skip_comment--;
  186. #endif
  187. return;
  188. }
  189. /* A possible '/' is not pushed back */
  190. if (ch == '/') {
  191. ch = GetChar();
  192. if (ch != '*') UnGetChar();
  193. else {
  194. skipcomment();
  195. continue;
  196. }
  197. } else UnGetChar();
  198. SkipToNewLine();
  199. continue;
  200. }
  201. ReplaceMacros = 0;
  202. toknum = GetToken(&tk);
  203. ReplaceMacros = 1;
  204. if (toknum != IDENTIFIER) {
  205. if (toknum != INTEGER) {
  206. lexerror("illegal # line");
  207. }
  208. SkipToNewLine();
  209. continue;
  210. }
  211. /* an IDENTIFIER: look for #if, #ifdef and #ifndef
  212. without interpreting them.
  213. Interpret #else, #elif and #endif if they occur
  214. on the same level.
  215. */
  216. switch(tk.tk_idf->id_resmac) {
  217. default:
  218. case K_UNKNOWN:
  219. /* invalid word seen after the '#' */
  220. lexwarning("%s: unknown control", tk.tk_idf->id_text);
  221. /* fallthrough */
  222. case K_DEFINE:
  223. case K_ERROR:
  224. case K_INCLUDE:
  225. case K_LINE:
  226. case K_PRAGMA:
  227. case K_UNDEF:
  228. case K_FILE:
  229. SkipToNewLine();
  230. break;
  231. case K_IF:
  232. case K_IFDEF:
  233. case K_IFNDEF:
  234. push_if();
  235. SkipToNewLine();
  236. break;
  237. case K_ELIF:
  238. if (ifstack[nestlevel])
  239. lexerror("#elif after #else");
  240. if (!to_endif && nestlevel == skiplevel) {
  241. nestlevel--;
  242. push_if();
  243. if (ifexpr()) {
  244. NoUnstack--;
  245. #ifdef LINT
  246. lint_skip_comment--;
  247. #endif
  248. return;
  249. }
  250. }
  251. else SkipToNewLine(); /* otherwise done in ifexpr() */
  252. break;
  253. case K_ELSE:
  254. if (ifstack[nestlevel])
  255. lexerror("#else after #else");
  256. ++(ifstack[nestlevel]);
  257. if (!to_endif && nestlevel == skiplevel) {
  258. if (SkipToNewLine()) {
  259. if (!options['o'])
  260. lexstrict("garbage following #else");
  261. }
  262. NoUnstack--;
  263. #ifdef LINT
  264. lint_skip_comment--;
  265. #endif
  266. return;
  267. }
  268. else SkipToNewLine();
  269. break;
  270. case K_ENDIF:
  271. ASSERT(nestlevel > nestlow);
  272. if (nestlevel == skiplevel) {
  273. if (SkipToNewLine()) {
  274. if (!options['o'])
  275. lexstrict("garbage following #endif");
  276. }
  277. nestlevel--;
  278. NoUnstack--;
  279. #ifdef LINT
  280. lint_skip_comment--;
  281. #endif
  282. return;
  283. }
  284. else SkipToNewLine();
  285. nestlevel--;
  286. break;
  287. }
  288. }
  289. }
  290. int ifexpr()
  291. {
  292. /* ifexpr() returns whether the restricted constant
  293. expression following #if or #elif evaluates to true. This
  294. is done by calling the LLgen generated subparser for
  295. constant expressions. The result of this expression will
  296. be given in the extern long variable "ifval".
  297. */
  298. extern arith ifval;
  299. int errors = err_occurred;
  300. ifval = (arith)0;
  301. AccDefined = 1;
  302. UnknownIdIsZero = 1;
  303. PushLex(); /* NEW parser */
  304. If_expr(); /* invoke constant expression parser */
  305. PopLex(); /* OLD parser */
  306. AccDefined = 0;
  307. UnknownIdIsZero = 0;
  308. return (errors == err_occurred) && (ifval != (arith)0);
  309. }
  310. void do_include()
  311. {
  312. /* do_include() performs the inclusion of a file.
  313. */
  314. char *filenm;
  315. char *result;
  316. int tok;
  317. struct token tk;
  318. AccFileSpecifier = 1;
  319. if (((tok = GetToken(&tk)) == FILESPECIFIER) || tok == STRING)
  320. filenm = tk.tk_bts;
  321. else {
  322. lexerror("bad include syntax");
  323. filenm = (char *)0;
  324. }
  325. AccFileSpecifier = 0;
  326. if (SkipToNewLine()) {
  327. lexerror("bad include syntax");
  328. }
  329. inctable[0] = WorkingDir;
  330. if (filenm) {
  331. if (!InsertFile(filenm, &inctable[tok==FILESPECIFIER],&result)){
  332. lexerror("cannot open include file \"%s\"", filenm);
  333. add_dependency(filenm);
  334. free(filenm);
  335. }
  336. else {
  337. add_dependency(result);
  338. WorkingDir = getwdir(result);
  339. File_Inserted = 1;
  340. FileName = result;
  341. LineNumber = 0;
  342. nestlow = nestlevel;
  343. #ifdef DBSYMTAB
  344. IncludeLevel++;
  345. if (options['g']) {
  346. C_ms_stb_cst(FileName, N_BINCL, 0, (arith) 0);
  347. }
  348. #endif /* DBSYMTAB */
  349. if (result != filenm) free(filenm);
  350. }
  351. }
  352. }
  353. void do_define()
  354. {
  355. /* do_define() interprets a #define control line.
  356. */
  357. struct idf *id; /* the #defined identifier's descriptor */
  358. int nformals = -1; /* keep track of the number of formals */
  359. char *formals[NPARAMS]; /* pointers to the names of the formals */
  360. char parbuf[PARBUFSIZE]; /* names of formals */
  361. char *repl_text; /* start of the replacement text */
  362. int length; /* length of the replacement text */
  363. register ch;
  364. char *get_text();
  365. /* read the #defined macro's name */
  366. if (!(id = GetIdentifier(1))) {
  367. lexerror("illegal #define line");
  368. return;
  369. }
  370. /* there is a formal parameter list if the identifier is
  371. followed immediately by a '('.
  372. */
  373. ch = GetChar();
  374. if (ch == '(') {
  375. if ((nformals = getparams(formals, parbuf)) == -1) {
  376. SkipToNewLine();
  377. return; /* an error occurred */
  378. }
  379. ch = GetChar();
  380. }
  381. /* read the replacement text if there is any */
  382. ch = skipspaces(ch,0); /* find first character of the text */
  383. ASSERT(ch != EOI);
  384. /* UnGetChar() is not right when replacement starts with a '/' */
  385. ChPushBack(ch);
  386. repl_text = get_text((nformals > 0) ? formals : 0, &length);
  387. macro_def(id, repl_text, nformals, length, NOFLAG);
  388. LineNumber++;
  389. }
  390. void push_if()
  391. {
  392. if (nestlevel >= IFDEPTH)
  393. fatal("too many nested #if/#ifdef/#ifndef");
  394. else
  395. ifstack[++nestlevel] = 0;
  396. }
  397. void do_elif()
  398. {
  399. if (nestlevel <= nestlow) {
  400. lexerror("#elif without corresponding #if");
  401. SkipToNewLine();
  402. }
  403. else { /* restart at this level as if a #if is detected. */
  404. if (ifstack[nestlevel]) {
  405. lexerror("#elif after #else");
  406. SkipToNewLine();
  407. }
  408. nestlevel--;
  409. push_if();
  410. skip_block(1);
  411. }
  412. }
  413. void do_else()
  414. {
  415. if (SkipToNewLine())
  416. if (!options['o'])
  417. lexstrict("garbage following #else");
  418. if (nestlevel <= nestlow)
  419. lexerror("#else without corresponding #if");
  420. else { /* mark this level as else-d */
  421. if (ifstack[nestlevel]) {
  422. lexerror("#else after #else");
  423. }
  424. ++(ifstack[nestlevel]);
  425. skip_block(1);
  426. }
  427. }
  428. void do_endif()
  429. {
  430. if (SkipToNewLine()) {
  431. if (!options['o'])
  432. lexstrict("garbage following #endif");
  433. }
  434. if (nestlevel <= nestlow) {
  435. lexerror("#endif without corresponding #if");
  436. }
  437. else nestlevel--;
  438. }
  439. void do_if()
  440. {
  441. push_if();
  442. if (!ifexpr()) /* a false #if/#elif expression */
  443. skip_block(0);
  444. }
  445. void do_ifdef(how)
  446. {
  447. struct idf *id;
  448. /* how == 1 : ifdef; how == 0 : ifndef
  449. */
  450. push_if();
  451. if (!(id = GetIdentifier(1)))
  452. lexerror("illegal #ifdef construction");
  453. else if (SkipToNewLine())
  454. if (!options['o'])
  455. lexstrict("garbage following #%s <identifier>",
  456. how ? "ifdef" : "ifndef");
  457. /* The next test is a shorthand for:
  458. (how && !id->id_macro) || (!how && id->id_macro)
  459. */
  460. if (how ^ (id && id->id_macro != 0))
  461. skip_block(0);
  462. }
  463. /* argidf != NULL when the undef came from a -U option */
  464. void do_undef(struct idf *argidf)
  465. {
  466. struct idf *id = argidf;
  467. /* Forget a macro definition. */
  468. if (id || (id = GetIdentifier(1))) {
  469. if (id->id_macro) { /* forget the macro */
  470. if (id->id_macro->mc_flag & NOUNDEF) {
  471. lexerror("it is not allowed to undef %s", id->id_text);
  472. } else {
  473. free(id->id_macro->mc_text);
  474. free_macro(id->id_macro);
  475. id->id_macro = (struct macro *) 0;
  476. }
  477. } /* else: don't complain */
  478. if (!argidf) {
  479. if (SkipToNewLine())
  480. if (!options['o'])
  481. lexstrict("garbage following #undef");
  482. }
  483. }
  484. else
  485. lexerror("illegal #undef construction");
  486. }
  487. void do_error()
  488. {
  489. int len;
  490. char *get_text();
  491. char *bp = get_text((char **) 0, &len);
  492. lexerror("user error: %s", bp);
  493. free(bp);
  494. LineNumber++;
  495. }
  496. void do_warning()
  497. {
  498. int len;
  499. char *get_text();
  500. char *bp = get_text((char **) 0, &len);
  501. lexwarning("user warning: %s", bp);
  502. free(bp);
  503. LineNumber++;
  504. }
  505. int getparams(char *buf[], char parbuf[])
  506. {
  507. /* getparams() reads the formal parameter list of a macro
  508. definition.
  509. The number of parameters is returned.
  510. As a formal parameter list is expected when calling this
  511. routine, -1 is returned if an error is detected, for
  512. example:
  513. #define one(1), where 1 is not an identifier.
  514. Note that the '(' has already been eaten.
  515. The names of the formal parameters are stored into parbuf.
  516. */
  517. char **pbuf = &buf[0];
  518. int c;
  519. char *ptr = &parbuf[0];
  520. char **pbuf2;
  521. c = GetChar();
  522. c = skipspaces(c,0);
  523. if (c == ')') { /* no parameters: #define name() */
  524. *pbuf = (char *) 0;
  525. return 0;
  526. }
  527. for (;;) { /* eat the formal parameter list */
  528. if (class(c) != STIDF && class(c) != STELL) {
  529. lexerror("#define: bad formal parameter");
  530. return -1;
  531. }
  532. *pbuf = ptr; /* name of the formal */
  533. *ptr++ = c;
  534. if (ptr >= &parbuf[PARBUFSIZE])
  535. fatal("formal parameter buffer overflow");
  536. do { /* eat the identifier name */
  537. c = GetChar();
  538. *ptr++ = c;
  539. if (ptr >= &parbuf[PARBUFSIZE])
  540. fatal("formal parameter buffer overflow");
  541. } while (in_idf(c));
  542. *(ptr - 1) = '\0'; /* mark end of the name */
  543. /* Check if this formal parameter is already used.
  544. Usually, macros do not have many parameters, so ...
  545. */
  546. for (pbuf2 = pbuf - 1; pbuf2 >= &buf[0]; pbuf2--) {
  547. if (!strcmp(*pbuf2, *pbuf)) {
  548. lexerror("formal parameter \"%s\" already used",
  549. *pbuf);
  550. }
  551. }
  552. pbuf++;
  553. c = skipspaces(c,0);
  554. if (c == ')') { /* end of the formal parameter list */
  555. *pbuf = (char *) 0;
  556. return pbuf - buf;
  557. }
  558. if (c != ',') {
  559. lexerror("#define: bad formal parameter list");
  560. return -1;
  561. }
  562. c = GetChar();
  563. c = skipspaces(c,0);
  564. }
  565. /*NOTREACHED*/
  566. }
  567. void macro_def(struct idf *id, char *text, int nformals, int length, int flags)
  568. {
  569. struct macro *newdef = id->id_macro;
  570. /* macro_def() puts the contents and information of a macro
  571. definition into a structure and stores it into the symbol
  572. table entry belonging to the name of the macro.
  573. An error is given if there was already a definition
  574. */
  575. if (newdef) { /* is there a redefinition? */
  576. if (newdef->mc_flag & NOUNDEF) {
  577. lexerror("it is not allowed to redefine %s", id->id_text);
  578. } else if (!macroeq(newdef->mc_text, text))
  579. lexerror("illegal redefine of \"%s\"", id->id_text);
  580. free(text);
  581. return;
  582. }
  583. id->id_macro = newdef = new_macro();
  584. newdef->mc_text = text; /* replacement text */
  585. newdef->mc_nps = nformals; /* nr of formals */
  586. newdef->mc_length = length; /* length of repl. text */
  587. newdef->mc_flag = flags; /* special flags */
  588. }
  589. int find_name(char *nm, char *index[])
  590. {
  591. /* find_name() returns the index of "nm" in the namelist
  592. "index" if it can be found there. 0 is returned if it is
  593. not there.
  594. */
  595. char **ip = &index[0];
  596. while (*ip)
  597. if (strcmp(nm, *ip++) == 0)
  598. return ip - &index[0];
  599. /* arrived here, nm is not in the name list. */
  600. return 0;
  601. }
  602. #define BLANK(ch) ((ch == ' ') || (ch == '\t'))
  603. char *get_text(char *formals[], int *length)
  604. {
  605. /* get_text() copies the replacement text of a macro
  606. definition with zero, one or more parameters, thereby
  607. substituting each formal parameter by a special character
  608. (non-ascii: 0200 & (order-number in the formal parameter
  609. list)) in order to substitute this character later by the
  610. actual parameter. The replacement text is copied into
  611. itself because the copied text will contain fewer or the
  612. same amount of characters. The length of the replacement
  613. text is returned.
  614. Implementation:
  615. finite automaton : we are interested in
  616. 1- white space, sequences must be mapped onto 1 single
  617. blank.
  618. 2- identifiers, since they might be replaced by some
  619. actual parameter.
  620. 3- strings and character constants, since replacing
  621. variables within them is illegal, and white-space is
  622. significant.
  623. 4- comment, same as for 1
  624. Other tokens will not be seen as such.
  625. */
  626. int c;
  627. struct repl repls;
  628. struct repl *repl = &repls;
  629. int blank = 0;
  630. c = GetChar();
  631. repl->r_ptr = repl->r_text = Malloc(repl->r_size = ITEXTSIZE);
  632. *repl->r_ptr = '\0';
  633. while ((c != EOI) && (class(c) != STNL)) {
  634. if (BLANK(c)) {
  635. blank++;
  636. c = GetChar();
  637. continue;
  638. }
  639. if (c == '\'' || c == '"') {
  640. int delim = c;
  641. if (blank) {
  642. blank = 0;
  643. add2repl(repl, ' ');
  644. }
  645. do {
  646. add2repl(repl, c);
  647. if (c == '\\') add2repl(repl, GetChar());
  648. c = GetChar();
  649. } while (c != delim && c != EOI && class(c) != STNL);
  650. if (c == EOI || class(c) == STNL) {
  651. lexstrict("unclosed opening %c", delim);
  652. break;
  653. }
  654. add2repl(repl, c);
  655. c = GetChar();
  656. } else if (c == '/') {
  657. c = GetChar();
  658. if (c == '*') {
  659. skipcomment();
  660. blank++;
  661. c = GetChar();
  662. continue;
  663. }
  664. if (blank) {
  665. blank = 0;
  666. add2repl(repl, ' ');
  667. }
  668. add2repl(repl, '/');
  669. } else if (formals
  670. && (class(c) == STIDF || class(c) == STELL)) {
  671. char id_buf[IDFSIZE + 1];
  672. char *idp = id_buf;
  673. int n;
  674. /* read identifier: it may be a formal parameter */
  675. *idp++ = c;
  676. do {
  677. c = GetChar();
  678. if (idp <= &id_buf[IDFSIZE])
  679. *idp++ = c;
  680. } while (in_idf(c));
  681. *--idp = '\0';
  682. if (blank) {
  683. blank = 0;
  684. add2repl(repl, ' ');
  685. }
  686. /* construct the formal parameter mark or identifier */
  687. if ((n = find_name(id_buf, formals)))
  688. add2repl(repl, FORMALP | (char) n);
  689. else {
  690. idp = id_buf;
  691. while (*idp) add2repl(repl, *idp++);
  692. }
  693. } else if (class(c) == STNUM) {
  694. if (blank) {
  695. blank = 0;
  696. add2repl(repl, ' ');
  697. }
  698. add2repl(repl, c);
  699. if (c == '.') {
  700. c = GetChar();
  701. if (class(c) != STNUM) {
  702. continue;
  703. }
  704. add2repl(repl, c);
  705. }
  706. c = GetChar();
  707. while(in_idf(c) || c == '.') {
  708. add2repl(repl, c);
  709. if((c = GetChar()) == 'e' || c == 'E') {
  710. add2repl(repl, c);
  711. c = GetChar();
  712. if (c == '+' || c == '-') {
  713. add2repl(repl, c);
  714. c = GetChar();
  715. }
  716. }
  717. }
  718. } else {
  719. if (blank) {
  720. blank = 0;
  721. add2repl(repl, ' ');
  722. }
  723. add2repl(repl, c);
  724. c = GetChar();
  725. }
  726. }
  727. *length = repl->r_ptr - repl->r_text;
  728. return Realloc(repl->r_text, (unsigned)(repl->r_ptr - repl->r_text +1));
  729. }
  730. /* macroeq() decides whether two macro replacement texts are
  731. identical. This version compares the texts, which occur
  732. as strings, without taking care of the leading and trailing
  733. blanks (spaces and tabs).
  734. */
  735. int macroeq(char *s, char *t)
  736. {
  737. /* skip leading spaces */
  738. while (BLANK(*s)) s++;
  739. while (BLANK(*t)) t++;
  740. /* first non-blank encountered in both strings */
  741. /* The actual comparison loop: */
  742. while (*s && *s == *t)
  743. s++, t++;
  744. /* two cases are possible when arrived here: */
  745. if (*s == '\0') { /* *s == '\0' */
  746. while (BLANK(*t)) t++;
  747. return *t == '\0';
  748. }
  749. else { /* *s != *t */
  750. while (BLANK(*s)) s++;
  751. while (BLANK(*t)) t++;
  752. return (*s == '\0') && (*t == '\0');
  753. }
  754. }
  755. #else /* NOPP */
  756. /* skiponerr -> skip the rest of the line on error */
  757. struct idf *GetIdentifier(int skiponerr)
  758. {
  759. /* returns a pointer to the descriptor of the identifier that is
  760. read from the input stream. When the input does not contain
  761. an identifier, the rest of the line is skipped when
  762. skiponerr is on, and a null-pointer is returned.
  763. The substitution of macros is disabled.
  764. */
  765. int tok;
  766. struct token tk;
  767. tok = GetToken(&tk);
  768. if (tok != IDENTIFIER) {
  769. if (skiponerr && tok != EOI) SkipToNewLine();
  770. return (struct idf *)0;
  771. }
  772. return tk.tk_idf;
  773. }
  774. void domacro()
  775. {
  776. int tok;
  777. struct token tk;
  778. EoiForNewline = 1;
  779. if ((tok = GetToken(&tk)) == IDENTIFIER) {
  780. if (! strcmp(tk.tk_idf->id_text, "pragma")) {
  781. do_pragma();
  782. EoiForNewline = 0;
  783. return;
  784. }
  785. } else if (tok == INTEGER) {
  786. do_line((unsigned int) tk.tk_ival);
  787. EoiForNewline = 0;
  788. return;
  789. }
  790. lexerror("illegal # line");
  791. EoiForNewline = 0;
  792. SkipToNewLine();
  793. }
  794. #endif /* NOPP */
  795. void do_line(unsigned int l)
  796. {
  797. struct token tk;
  798. int t = GetToken(&tk);
  799. if (t != EOI) SkipToNewLine();
  800. LineNumber = l; /* the number of the next input line */
  801. if (t == STRING) { /* is there a filespecifier? */
  802. /*
  803. * Do not attempt to free the old string, since it might
  804. * be used in a def structure.
  805. */
  806. #ifdef DBSYMTAB
  807. if (options['g'] && strcmp(FileName, tk.tk_bts) != 0) {
  808. C_ms_std(tk.tk_bts, N_SOL, 0);
  809. }
  810. #endif /* DBSYMTAB */
  811. FileName = tk.tk_bts;
  812. }
  813. }