/contrib/groff/src/preproc/pic/lex.cpp

https://bitbucket.org/freebsd/freebsd-head/ · C++ · 2001 lines · 1925 code · 50 blank · 26 comment · 250 complexity · 271c6112c363e0fa8a5979fa51482e08 MD5 · raw file

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002, 2003, 2004
  3. Free Software Foundation, Inc.
  4. Written by James Clark (jjc@jclark.com)
  5. This file is part of groff.
  6. groff is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 2, or (at your option) any later
  9. version.
  10. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License along
  15. with groff; see the file COPYING. If not, write to the Free Software
  16. Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
  17. #include "pic.h"
  18. #include "ptable.h"
  19. #include "object.h"
  20. #include "pic_tab.h"
  21. declare_ptable(char)
  22. implement_ptable(char)
  23. PTABLE(char) macro_table;
  24. class macro_input : public input {
  25. char *s;
  26. char *p;
  27. public:
  28. macro_input(const char *);
  29. ~macro_input();
  30. int get();
  31. int peek();
  32. };
  33. class argument_macro_input : public input {
  34. char *s;
  35. char *p;
  36. char *ap;
  37. int argc;
  38. char *argv[9];
  39. public:
  40. argument_macro_input(const char *, int, char **);
  41. ~argument_macro_input();
  42. int get();
  43. int peek();
  44. };
  45. input::input() : next(0)
  46. {
  47. }
  48. input::~input()
  49. {
  50. }
  51. int input::get_location(const char **, int *)
  52. {
  53. return 0;
  54. }
  55. file_input::file_input(FILE *f, const char *fn)
  56. : fp(f), filename(fn), lineno(0), ptr("")
  57. {
  58. }
  59. file_input::~file_input()
  60. {
  61. fclose(fp);
  62. }
  63. int file_input::read_line()
  64. {
  65. for (;;) {
  66. line.clear();
  67. lineno++;
  68. for (;;) {
  69. int c = getc(fp);
  70. if (c == EOF)
  71. break;
  72. else if (invalid_input_char(c))
  73. lex_error("invalid input character code %1", c);
  74. else {
  75. line += char(c);
  76. if (c == '\n')
  77. break;
  78. }
  79. }
  80. if (line.length() == 0)
  81. return 0;
  82. if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
  83. && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
  84. && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
  85. || compatible_flag))) {
  86. line += '\0';
  87. ptr = line.contents();
  88. return 1;
  89. }
  90. }
  91. }
  92. int file_input::get()
  93. {
  94. if (*ptr != '\0' || read_line())
  95. return (unsigned char)*ptr++;
  96. else
  97. return EOF;
  98. }
  99. int file_input::peek()
  100. {
  101. if (*ptr != '\0' || read_line())
  102. return (unsigned char)*ptr;
  103. else
  104. return EOF;
  105. }
  106. int file_input::get_location(const char **fnp, int *lnp)
  107. {
  108. *fnp = filename;
  109. *lnp = lineno;
  110. return 1;
  111. }
  112. macro_input::macro_input(const char *str)
  113. {
  114. p = s = strsave(str);
  115. }
  116. macro_input::~macro_input()
  117. {
  118. a_delete s;
  119. }
  120. int macro_input::get()
  121. {
  122. if (p == 0 || *p == '\0')
  123. return EOF;
  124. else
  125. return (unsigned char)*p++;
  126. }
  127. int macro_input::peek()
  128. {
  129. if (p == 0 || *p == '\0')
  130. return EOF;
  131. else
  132. return (unsigned char)*p;
  133. }
  134. // Character representing $1. Must be invalid input character.
  135. #define ARG1 14
  136. char *process_body(const char *body)
  137. {
  138. char *s = strsave(body);
  139. int j = 0;
  140. for (int i = 0; s[i] != '\0'; i++)
  141. if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
  142. if (s[i+1] != '0')
  143. s[j++] = ARG1 + s[++i] - '1';
  144. }
  145. else
  146. s[j++] = s[i];
  147. s[j] = '\0';
  148. return s;
  149. }
  150. argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
  151. : ap(0), argc(ac)
  152. {
  153. for (int i = 0; i < argc; i++)
  154. argv[i] = av[i];
  155. p = s = process_body(body);
  156. }
  157. argument_macro_input::~argument_macro_input()
  158. {
  159. for (int i = 0; i < argc; i++)
  160. a_delete argv[i];
  161. a_delete s;
  162. }
  163. int argument_macro_input::get()
  164. {
  165. if (ap) {
  166. if (*ap != '\0')
  167. return (unsigned char)*ap++;
  168. ap = 0;
  169. }
  170. if (p == 0)
  171. return EOF;
  172. while (*p >= ARG1 && *p <= ARG1 + 8) {
  173. int i = *p++ - ARG1;
  174. if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  175. ap = argv[i];
  176. return (unsigned char)*ap++;
  177. }
  178. }
  179. if (*p == '\0')
  180. return EOF;
  181. return (unsigned char)*p++;
  182. }
  183. int argument_macro_input::peek()
  184. {
  185. if (ap) {
  186. if (*ap != '\0')
  187. return (unsigned char)*ap;
  188. ap = 0;
  189. }
  190. if (p == 0)
  191. return EOF;
  192. while (*p >= ARG1 && *p <= ARG1 + 8) {
  193. int i = *p++ - ARG1;
  194. if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  195. ap = argv[i];
  196. return (unsigned char)*ap;
  197. }
  198. }
  199. if (*p == '\0')
  200. return EOF;
  201. return (unsigned char)*p;
  202. }
  203. class input_stack {
  204. static input *current_input;
  205. static int bol_flag;
  206. public:
  207. static void push(input *);
  208. static void clear();
  209. static int get_char();
  210. static int peek_char();
  211. static int get_location(const char **fnp, int *lnp);
  212. static void push_back(unsigned char c, int was_bol = 0);
  213. static int bol();
  214. };
  215. input *input_stack::current_input = 0;
  216. int input_stack::bol_flag = 0;
  217. inline int input_stack::bol()
  218. {
  219. return bol_flag;
  220. }
  221. void input_stack::clear()
  222. {
  223. while (current_input != 0) {
  224. input *tem = current_input;
  225. current_input = current_input->next;
  226. delete tem;
  227. }
  228. bol_flag = 1;
  229. }
  230. void input_stack::push(input *in)
  231. {
  232. in->next = current_input;
  233. current_input = in;
  234. }
  235. void lex_init(input *top)
  236. {
  237. input_stack::clear();
  238. input_stack::push(top);
  239. }
  240. void lex_cleanup()
  241. {
  242. while (input_stack::get_char() != EOF)
  243. ;
  244. }
  245. int input_stack::get_char()
  246. {
  247. while (current_input != 0) {
  248. int c = current_input->get();
  249. if (c != EOF) {
  250. bol_flag = c == '\n';
  251. return c;
  252. }
  253. // don't pop the top-level input off the stack
  254. if (current_input->next == 0)
  255. return EOF;
  256. input *tem = current_input;
  257. current_input = current_input->next;
  258. delete tem;
  259. }
  260. return EOF;
  261. }
  262. int input_stack::peek_char()
  263. {
  264. while (current_input != 0) {
  265. int c = current_input->peek();
  266. if (c != EOF)
  267. return c;
  268. if (current_input->next == 0)
  269. return EOF;
  270. input *tem = current_input;
  271. current_input = current_input->next;
  272. delete tem;
  273. }
  274. return EOF;
  275. }
  276. class char_input : public input {
  277. int c;
  278. public:
  279. char_input(int);
  280. int get();
  281. int peek();
  282. };
  283. char_input::char_input(int n) : c((unsigned char)n)
  284. {
  285. }
  286. int char_input::get()
  287. {
  288. int n = c;
  289. c = EOF;
  290. return n;
  291. }
  292. int char_input::peek()
  293. {
  294. return c;
  295. }
  296. void input_stack::push_back(unsigned char c, int was_bol)
  297. {
  298. push(new char_input(c));
  299. bol_flag = was_bol;
  300. }
  301. int input_stack::get_location(const char **fnp, int *lnp)
  302. {
  303. for (input *p = current_input; p; p = p->next)
  304. if (p->get_location(fnp, lnp))
  305. return 1;
  306. return 0;
  307. }
  308. string context_buffer;
  309. string token_buffer;
  310. double token_double;
  311. int token_int;
  312. void interpolate_macro_with_args(const char *body)
  313. {
  314. char *argv[9];
  315. int argc = 0;
  316. int i;
  317. for (i = 0; i < 9; i++)
  318. argv[i] = 0;
  319. int level = 0;
  320. int c;
  321. enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL;
  322. do {
  323. token_buffer.clear();
  324. for (;;) {
  325. c = input_stack::get_char();
  326. if (c == EOF) {
  327. lex_error("end of input while scanning macro arguments");
  328. break;
  329. }
  330. if (state == NORMAL && level == 0 && (c == ',' || c == ')')) {
  331. if (token_buffer.length() > 0) {
  332. token_buffer += '\0';
  333. argv[argc] = strsave(token_buffer.contents());
  334. }
  335. // for `foo()', argc = 0
  336. if (argc > 0 || c != ')' || i > 0)
  337. argc++;
  338. break;
  339. }
  340. token_buffer += char(c);
  341. switch (state) {
  342. case NORMAL:
  343. if (c == '"')
  344. state = IN_STRING;
  345. else if (c == '(')
  346. level++;
  347. else if (c == ')')
  348. level--;
  349. break;
  350. case IN_STRING:
  351. if (c == '"')
  352. state = NORMAL;
  353. else if (c == '\\')
  354. state = IN_STRING_QUOTED;
  355. break;
  356. case IN_STRING_QUOTED:
  357. state = IN_STRING;
  358. break;
  359. }
  360. }
  361. } while (c != ')' && c != EOF);
  362. input_stack::push(new argument_macro_input(body, argc, argv));
  363. }
  364. static int docmp(const char *s1, int n1, const char *s2, int n2)
  365. {
  366. if (n1 < n2) {
  367. int r = memcmp(s1, s2, n1);
  368. return r ? r : -1;
  369. }
  370. else if (n1 > n2) {
  371. int r = memcmp(s1, s2, n2);
  372. return r ? r : 1;
  373. }
  374. else
  375. return memcmp(s1, s2, n1);
  376. }
  377. int lookup_keyword(const char *str, int len)
  378. {
  379. static struct keyword {
  380. const char *name;
  381. int token;
  382. } table[] = {
  383. { "Here", HERE },
  384. { "above", ABOVE },
  385. { "aligned", ALIGNED },
  386. { "and", AND },
  387. { "arc", ARC },
  388. { "arrow", ARROW },
  389. { "at", AT },
  390. { "atan2", ATAN2 },
  391. { "below", BELOW },
  392. { "between", BETWEEN },
  393. { "bottom", BOTTOM },
  394. { "box", BOX },
  395. { "by", BY },
  396. { "ccw", CCW },
  397. { "center", CENTER },
  398. { "chop", CHOP },
  399. { "circle", CIRCLE },
  400. { "color", COLORED },
  401. { "colored", COLORED },
  402. { "colour", COLORED },
  403. { "coloured", COLORED },
  404. { "command", COMMAND },
  405. { "copy", COPY },
  406. { "cos", COS },
  407. { "cw", CW },
  408. { "dashed", DASHED },
  409. { "define", DEFINE },
  410. { "diam", DIAMETER },
  411. { "diameter", DIAMETER },
  412. { "do", DO },
  413. { "dotted", DOTTED },
  414. { "down", DOWN },
  415. { "east", EAST },
  416. { "ellipse", ELLIPSE },
  417. { "else", ELSE },
  418. { "end", END },
  419. { "exp", EXP },
  420. { "figname", FIGNAME },
  421. { "fill", FILL },
  422. { "filled", FILL },
  423. { "for", FOR },
  424. { "from", FROM },
  425. { "height", HEIGHT },
  426. { "ht", HEIGHT },
  427. { "if", IF },
  428. { "int", INT },
  429. { "invis", INVISIBLE },
  430. { "invisible", INVISIBLE },
  431. { "last", LAST },
  432. { "left", LEFT },
  433. { "line", LINE },
  434. { "ljust", LJUST },
  435. { "log", LOG },
  436. { "lower", LOWER },
  437. { "max", K_MAX },
  438. { "min", K_MIN },
  439. { "move", MOVE },
  440. { "north", NORTH },
  441. { "of", OF },
  442. { "outline", OUTLINED },
  443. { "outlined", OUTLINED },
  444. { "plot", PLOT },
  445. { "print", PRINT },
  446. { "rad", RADIUS },
  447. { "radius", RADIUS },
  448. { "rand", RAND },
  449. { "reset", RESET },
  450. { "right", RIGHT },
  451. { "rjust", RJUST },
  452. { "same", SAME },
  453. { "sh", SH },
  454. { "shaded", SHADED },
  455. { "sin", SIN },
  456. { "solid", SOLID },
  457. { "south", SOUTH },
  458. { "spline", SPLINE },
  459. { "sprintf", SPRINTF },
  460. { "sqrt", SQRT },
  461. { "srand", SRAND },
  462. { "start", START },
  463. { "the", THE },
  464. { "then", THEN },
  465. { "thick", THICKNESS },
  466. { "thickness", THICKNESS },
  467. { "thru", THRU },
  468. { "to", TO },
  469. { "top", TOP },
  470. { "undef", UNDEF },
  471. { "until", UNTIL },
  472. { "up", UP },
  473. { "upper", UPPER },
  474. { "way", WAY },
  475. { "west", WEST },
  476. { "wid", WIDTH },
  477. { "width", WIDTH },
  478. { "with", WITH },
  479. };
  480. const keyword *start = table;
  481. const keyword *end = table + sizeof(table)/sizeof(table[0]);
  482. while (start < end) {
  483. // start <= target < end
  484. const keyword *mid = start + (end - start)/2;
  485. int cmp = docmp(str, len, mid->name, strlen(mid->name));
  486. if (cmp == 0)
  487. return mid->token;
  488. if (cmp < 0)
  489. end = mid;
  490. else
  491. start = mid + 1;
  492. }
  493. return 0;
  494. }
  495. int get_token_after_dot(int c)
  496. {
  497. // get_token deals with the case where c is a digit
  498. switch (c) {
  499. case 'h':
  500. input_stack::get_char();
  501. c = input_stack::peek_char();
  502. if (c == 't') {
  503. input_stack::get_char();
  504. context_buffer = ".ht";
  505. return DOT_HT;
  506. }
  507. else if (c == 'e') {
  508. input_stack::get_char();
  509. c = input_stack::peek_char();
  510. if (c == 'i') {
  511. input_stack::get_char();
  512. c = input_stack::peek_char();
  513. if (c == 'g') {
  514. input_stack::get_char();
  515. c = input_stack::peek_char();
  516. if (c == 'h') {
  517. input_stack::get_char();
  518. c = input_stack::peek_char();
  519. if (c == 't') {
  520. input_stack::get_char();
  521. context_buffer = ".height";
  522. return DOT_HT;
  523. }
  524. input_stack::push_back('h');
  525. }
  526. input_stack::push_back('g');
  527. }
  528. input_stack::push_back('i');
  529. }
  530. input_stack::push_back('e');
  531. }
  532. input_stack::push_back('h');
  533. return '.';
  534. case 'x':
  535. input_stack::get_char();
  536. context_buffer = ".x";
  537. return DOT_X;
  538. case 'y':
  539. input_stack::get_char();
  540. context_buffer = ".y";
  541. return DOT_Y;
  542. case 'c':
  543. input_stack::get_char();
  544. c = input_stack::peek_char();
  545. if (c == 'e') {
  546. input_stack::get_char();
  547. c = input_stack::peek_char();
  548. if (c == 'n') {
  549. input_stack::get_char();
  550. c = input_stack::peek_char();
  551. if (c == 't') {
  552. input_stack::get_char();
  553. c = input_stack::peek_char();
  554. if (c == 'e') {
  555. input_stack::get_char();
  556. c = input_stack::peek_char();
  557. if (c == 'r') {
  558. input_stack::get_char();
  559. context_buffer = ".center";
  560. return DOT_C;
  561. }
  562. input_stack::push_back('e');
  563. }
  564. input_stack::push_back('t');
  565. }
  566. input_stack::push_back('n');
  567. }
  568. input_stack::push_back('e');
  569. }
  570. context_buffer = ".c";
  571. return DOT_C;
  572. case 'n':
  573. input_stack::get_char();
  574. c = input_stack::peek_char();
  575. if (c == 'e') {
  576. input_stack::get_char();
  577. context_buffer = ".ne";
  578. return DOT_NE;
  579. }
  580. else if (c == 'w') {
  581. input_stack::get_char();
  582. context_buffer = ".nw";
  583. return DOT_NW;
  584. }
  585. else {
  586. context_buffer = ".n";
  587. return DOT_N;
  588. }
  589. break;
  590. case 'e':
  591. input_stack::get_char();
  592. c = input_stack::peek_char();
  593. if (c == 'n') {
  594. input_stack::get_char();
  595. c = input_stack::peek_char();
  596. if (c == 'd') {
  597. input_stack::get_char();
  598. context_buffer = ".end";
  599. return DOT_END;
  600. }
  601. input_stack::push_back('n');
  602. context_buffer = ".e";
  603. return DOT_E;
  604. }
  605. context_buffer = ".e";
  606. return DOT_E;
  607. case 'w':
  608. input_stack::get_char();
  609. c = input_stack::peek_char();
  610. if (c == 'i') {
  611. input_stack::get_char();
  612. c = input_stack::peek_char();
  613. if (c == 'd') {
  614. input_stack::get_char();
  615. c = input_stack::peek_char();
  616. if (c == 't') {
  617. input_stack::get_char();
  618. c = input_stack::peek_char();
  619. if (c == 'h') {
  620. input_stack::get_char();
  621. context_buffer = ".width";
  622. return DOT_WID;
  623. }
  624. input_stack::push_back('t');
  625. }
  626. context_buffer = ".wid";
  627. return DOT_WID;
  628. }
  629. input_stack::push_back('i');
  630. }
  631. context_buffer = ".w";
  632. return DOT_W;
  633. case 's':
  634. input_stack::get_char();
  635. c = input_stack::peek_char();
  636. if (c == 'e') {
  637. input_stack::get_char();
  638. context_buffer = ".se";
  639. return DOT_SE;
  640. }
  641. else if (c == 'w') {
  642. input_stack::get_char();
  643. context_buffer = ".sw";
  644. return DOT_SW;
  645. }
  646. else {
  647. if (c == 't') {
  648. input_stack::get_char();
  649. c = input_stack::peek_char();
  650. if (c == 'a') {
  651. input_stack::get_char();
  652. c = input_stack::peek_char();
  653. if (c == 'r') {
  654. input_stack::get_char();
  655. c = input_stack::peek_char();
  656. if (c == 't') {
  657. input_stack::get_char();
  658. context_buffer = ".start";
  659. return DOT_START;
  660. }
  661. input_stack::push_back('r');
  662. }
  663. input_stack::push_back('a');
  664. }
  665. input_stack::push_back('t');
  666. }
  667. context_buffer = ".s";
  668. return DOT_S;
  669. }
  670. break;
  671. case 't':
  672. input_stack::get_char();
  673. c = input_stack::peek_char();
  674. if (c == 'o') {
  675. input_stack::get_char();
  676. c = input_stack::peek_char();
  677. if (c == 'p') {
  678. input_stack::get_char();
  679. context_buffer = ".top";
  680. return DOT_N;
  681. }
  682. input_stack::push_back('o');
  683. }
  684. context_buffer = ".t";
  685. return DOT_N;
  686. case 'l':
  687. input_stack::get_char();
  688. c = input_stack::peek_char();
  689. if (c == 'e') {
  690. input_stack::get_char();
  691. c = input_stack::peek_char();
  692. if (c == 'f') {
  693. input_stack::get_char();
  694. c = input_stack::peek_char();
  695. if (c == 't') {
  696. input_stack::get_char();
  697. context_buffer = ".left";
  698. return DOT_W;
  699. }
  700. input_stack::push_back('f');
  701. }
  702. input_stack::push_back('e');
  703. }
  704. context_buffer = ".l";
  705. return DOT_W;
  706. case 'r':
  707. input_stack::get_char();
  708. c = input_stack::peek_char();
  709. if (c == 'a') {
  710. input_stack::get_char();
  711. c = input_stack::peek_char();
  712. if (c == 'd') {
  713. input_stack::get_char();
  714. context_buffer = ".rad";
  715. return DOT_RAD;
  716. }
  717. input_stack::push_back('a');
  718. }
  719. else if (c == 'i') {
  720. input_stack::get_char();
  721. c = input_stack::peek_char();
  722. if (c == 'g') {
  723. input_stack::get_char();
  724. c = input_stack::peek_char();
  725. if (c == 'h') {
  726. input_stack::get_char();
  727. c = input_stack::peek_char();
  728. if (c == 't') {
  729. input_stack::get_char();
  730. context_buffer = ".right";
  731. return DOT_E;
  732. }
  733. input_stack::push_back('h');
  734. }
  735. input_stack::push_back('g');
  736. }
  737. input_stack::push_back('i');
  738. }
  739. context_buffer = ".r";
  740. return DOT_E;
  741. case 'b':
  742. input_stack::get_char();
  743. c = input_stack::peek_char();
  744. if (c == 'o') {
  745. input_stack::get_char();
  746. c = input_stack::peek_char();
  747. if (c == 't') {
  748. input_stack::get_char();
  749. c = input_stack::peek_char();
  750. if (c == 't') {
  751. input_stack::get_char();
  752. c = input_stack::peek_char();
  753. if (c == 'o') {
  754. input_stack::get_char();
  755. c = input_stack::peek_char();
  756. if (c == 'm') {
  757. input_stack::get_char();
  758. context_buffer = ".bottom";
  759. return DOT_S;
  760. }
  761. input_stack::push_back('o');
  762. }
  763. input_stack::push_back('t');
  764. }
  765. context_buffer = ".bot";
  766. return DOT_S;
  767. }
  768. input_stack::push_back('o');
  769. }
  770. context_buffer = ".b";
  771. return DOT_S;
  772. default:
  773. context_buffer = '.';
  774. return '.';
  775. }
  776. }
  777. int get_token(int lookup_flag)
  778. {
  779. context_buffer.clear();
  780. for (;;) {
  781. int n = 0;
  782. int bol = input_stack::bol();
  783. int c = input_stack::get_char();
  784. if (bol && c == command_char) {
  785. token_buffer.clear();
  786. token_buffer += c;
  787. // the newline is not part of the token
  788. for (;;) {
  789. c = input_stack::peek_char();
  790. if (c == EOF || c == '\n')
  791. break;
  792. input_stack::get_char();
  793. token_buffer += char(c);
  794. }
  795. context_buffer = token_buffer;
  796. return COMMAND_LINE;
  797. }
  798. switch (c) {
  799. case EOF:
  800. return EOF;
  801. case ' ':
  802. case '\t':
  803. break;
  804. case '\\':
  805. {
  806. int d = input_stack::peek_char();
  807. if (d != '\n') {
  808. context_buffer = '\\';
  809. return '\\';
  810. }
  811. input_stack::get_char();
  812. break;
  813. }
  814. case '#':
  815. do {
  816. c = input_stack::get_char();
  817. } while (c != '\n' && c != EOF);
  818. if (c == '\n')
  819. context_buffer = '\n';
  820. return c;
  821. case '"':
  822. context_buffer = '"';
  823. token_buffer.clear();
  824. for (;;) {
  825. c = input_stack::get_char();
  826. if (c == '\\') {
  827. context_buffer += '\\';
  828. c = input_stack::peek_char();
  829. if (c == '"') {
  830. input_stack::get_char();
  831. token_buffer += '"';
  832. context_buffer += '"';
  833. }
  834. else
  835. token_buffer += '\\';
  836. }
  837. else if (c == '\n') {
  838. error("newline in string");
  839. break;
  840. }
  841. else if (c == EOF) {
  842. error("missing `\"'");
  843. break;
  844. }
  845. else if (c == '"') {
  846. context_buffer += '"';
  847. break;
  848. }
  849. else {
  850. context_buffer += char(c);
  851. token_buffer += char(c);
  852. }
  853. }
  854. return TEXT;
  855. case '0':
  856. case '1':
  857. case '2':
  858. case '3':
  859. case '4':
  860. case '5':
  861. case '6':
  862. case '7':
  863. case '8':
  864. case '9':
  865. {
  866. int overflow = 0;
  867. n = 0;
  868. for (;;) {
  869. if (n > (INT_MAX - 9)/10) {
  870. overflow = 1;
  871. break;
  872. }
  873. n *= 10;
  874. n += c - '0';
  875. context_buffer += char(c);
  876. c = input_stack::peek_char();
  877. if (c == EOF || !csdigit(c))
  878. break;
  879. c = input_stack::get_char();
  880. }
  881. token_double = n;
  882. if (overflow) {
  883. for (;;) {
  884. token_double *= 10.0;
  885. token_double += c - '0';
  886. context_buffer += char(c);
  887. c = input_stack::peek_char();
  888. if (c == EOF || !csdigit(c))
  889. break;
  890. c = input_stack::get_char();
  891. }
  892. // if somebody asks for 1000000000000th, we will silently
  893. // give them INT_MAXth
  894. double temp = token_double; // work around gas 1.34/sparc bug
  895. if (token_double > INT_MAX)
  896. n = INT_MAX;
  897. else
  898. n = int(temp);
  899. }
  900. }
  901. switch (c) {
  902. case 'i':
  903. case 'I':
  904. context_buffer += char(c);
  905. input_stack::get_char();
  906. return NUMBER;
  907. case '.':
  908. {
  909. context_buffer += '.';
  910. input_stack::get_char();
  911. got_dot:
  912. double factor = 1.0;
  913. for (;;) {
  914. c = input_stack::peek_char();
  915. if (c == EOF || !csdigit(c))
  916. break;
  917. input_stack::get_char();
  918. context_buffer += char(c);
  919. factor /= 10.0;
  920. if (c != '0')
  921. token_double += factor*(c - '0');
  922. }
  923. if (c != 'e' && c != 'E') {
  924. if (c == 'i' || c == 'I') {
  925. context_buffer += char(c);
  926. input_stack::get_char();
  927. }
  928. return NUMBER;
  929. }
  930. }
  931. // fall through
  932. case 'e':
  933. case 'E':
  934. {
  935. int echar = c;
  936. input_stack::get_char();
  937. c = input_stack::peek_char();
  938. int sign = '+';
  939. if (c == '+' || c == '-') {
  940. sign = c;
  941. input_stack::get_char();
  942. c = input_stack::peek_char();
  943. if (c == EOF || !csdigit(c)) {
  944. input_stack::push_back(sign);
  945. input_stack::push_back(echar);
  946. return NUMBER;
  947. }
  948. context_buffer += char(echar);
  949. context_buffer += char(sign);
  950. }
  951. else {
  952. if (c == EOF || !csdigit(c)) {
  953. input_stack::push_back(echar);
  954. return NUMBER;
  955. }
  956. context_buffer += char(echar);
  957. }
  958. input_stack::get_char();
  959. context_buffer += char(c);
  960. n = c - '0';
  961. for (;;) {
  962. c = input_stack::peek_char();
  963. if (c == EOF || !csdigit(c))
  964. break;
  965. input_stack::get_char();
  966. context_buffer += char(c);
  967. n = n*10 + (c - '0');
  968. }
  969. if (sign == '-')
  970. n = -n;
  971. if (c == 'i' || c == 'I') {
  972. context_buffer += char(c);
  973. input_stack::get_char();
  974. }
  975. token_double *= pow(10.0, n);
  976. return NUMBER;
  977. }
  978. case 'n':
  979. input_stack::get_char();
  980. c = input_stack::peek_char();
  981. if (c == 'd') {
  982. input_stack::get_char();
  983. token_int = n;
  984. context_buffer += "nd";
  985. return ORDINAL;
  986. }
  987. input_stack::push_back('n');
  988. return NUMBER;
  989. case 'r':
  990. input_stack::get_char();
  991. c = input_stack::peek_char();
  992. if (c == 'd') {
  993. input_stack::get_char();
  994. token_int = n;
  995. context_buffer += "rd";
  996. return ORDINAL;
  997. }
  998. input_stack::push_back('r');
  999. return NUMBER;
  1000. case 't':
  1001. input_stack::get_char();
  1002. c = input_stack::peek_char();
  1003. if (c == 'h') {
  1004. input_stack::get_char();
  1005. token_int = n;
  1006. context_buffer += "th";
  1007. return ORDINAL;
  1008. }
  1009. input_stack::push_back('t');
  1010. return NUMBER;
  1011. case 's':
  1012. input_stack::get_char();
  1013. c = input_stack::peek_char();
  1014. if (c == 't') {
  1015. input_stack::get_char();
  1016. token_int = n;
  1017. context_buffer += "st";
  1018. return ORDINAL;
  1019. }
  1020. input_stack::push_back('s');
  1021. return NUMBER;
  1022. default:
  1023. return NUMBER;
  1024. }
  1025. break;
  1026. case '\'':
  1027. {
  1028. c = input_stack::peek_char();
  1029. if (c == 't') {
  1030. input_stack::get_char();
  1031. c = input_stack::peek_char();
  1032. if (c == 'h') {
  1033. input_stack::get_char();
  1034. context_buffer = "'th";
  1035. return TH;
  1036. }
  1037. else
  1038. input_stack::push_back('t');
  1039. }
  1040. context_buffer = "'";
  1041. return '\'';
  1042. }
  1043. case '.':
  1044. {
  1045. c = input_stack::peek_char();
  1046. if (c != EOF && csdigit(c)) {
  1047. n = 0;
  1048. token_double = 0.0;
  1049. context_buffer = '.';
  1050. goto got_dot;
  1051. }
  1052. return get_token_after_dot(c);
  1053. }
  1054. case '<':
  1055. c = input_stack::peek_char();
  1056. if (c == '-') {
  1057. input_stack::get_char();
  1058. c = input_stack::peek_char();
  1059. if (c == '>') {
  1060. input_stack::get_char();
  1061. context_buffer = "<->";
  1062. return DOUBLE_ARROW_HEAD;
  1063. }
  1064. context_buffer = "<-";
  1065. return LEFT_ARROW_HEAD;
  1066. }
  1067. else if (c == '=') {
  1068. input_stack::get_char();
  1069. context_buffer = "<=";
  1070. return LESSEQUAL;
  1071. }
  1072. context_buffer = "<";
  1073. return '<';
  1074. case '-':
  1075. c = input_stack::peek_char();
  1076. if (c == '>') {
  1077. input_stack::get_char();
  1078. context_buffer = "->";
  1079. return RIGHT_ARROW_HEAD;
  1080. }
  1081. context_buffer = "-";
  1082. return '-';
  1083. case '!':
  1084. c = input_stack::peek_char();
  1085. if (c == '=') {
  1086. input_stack::get_char();
  1087. context_buffer = "!=";
  1088. return NOTEQUAL;
  1089. }
  1090. context_buffer = "!";
  1091. return '!';
  1092. case '>':
  1093. c = input_stack::peek_char();
  1094. if (c == '=') {
  1095. input_stack::get_char();
  1096. context_buffer = ">=";
  1097. return GREATEREQUAL;
  1098. }
  1099. context_buffer = ">";
  1100. return '>';
  1101. case '=':
  1102. c = input_stack::peek_char();
  1103. if (c == '=') {
  1104. input_stack::get_char();
  1105. context_buffer = "==";
  1106. return EQUALEQUAL;
  1107. }
  1108. context_buffer = "=";
  1109. return '=';
  1110. case '&':
  1111. c = input_stack::peek_char();
  1112. if (c == '&') {
  1113. input_stack::get_char();
  1114. context_buffer = "&&";
  1115. return ANDAND;
  1116. }
  1117. context_buffer = "&";
  1118. return '&';
  1119. case '|':
  1120. c = input_stack::peek_char();
  1121. if (c == '|') {
  1122. input_stack::get_char();
  1123. context_buffer = "||";
  1124. return OROR;
  1125. }
  1126. context_buffer = "|";
  1127. return '|';
  1128. default:
  1129. if (c != EOF && csalpha(c)) {
  1130. token_buffer.clear();
  1131. token_buffer = c;
  1132. for (;;) {
  1133. c = input_stack::peek_char();
  1134. if (c == EOF || (!csalnum(c) && c != '_'))
  1135. break;
  1136. input_stack::get_char();
  1137. token_buffer += char(c);
  1138. }
  1139. int tok = lookup_keyword(token_buffer.contents(),
  1140. token_buffer.length());
  1141. if (tok != 0) {
  1142. context_buffer = token_buffer;
  1143. return tok;
  1144. }
  1145. char *def = 0;
  1146. if (lookup_flag) {
  1147. token_buffer += '\0';
  1148. def = macro_table.lookup(token_buffer.contents());
  1149. token_buffer.set_length(token_buffer.length() - 1);
  1150. if (def) {
  1151. if (c == '(') {
  1152. input_stack::get_char();
  1153. interpolate_macro_with_args(def);
  1154. }
  1155. else
  1156. input_stack::push(new macro_input(def));
  1157. }
  1158. }
  1159. if (!def) {
  1160. context_buffer = token_buffer;
  1161. if (csupper(token_buffer[0]))
  1162. return LABEL;
  1163. else
  1164. return VARIABLE;
  1165. }
  1166. }
  1167. else {
  1168. context_buffer = char(c);
  1169. return (unsigned char)c;
  1170. }
  1171. break;
  1172. }
  1173. }
  1174. }
  1175. int get_delimited()
  1176. {
  1177. token_buffer.clear();
  1178. int c = input_stack::get_char();
  1179. while (c == ' ' || c == '\t' || c == '\n')
  1180. c = input_stack::get_char();
  1181. if (c == EOF) {
  1182. lex_error("missing delimiter");
  1183. return 0;
  1184. }
  1185. context_buffer = char(c);
  1186. int had_newline = 0;
  1187. int start = c;
  1188. int level = 0;
  1189. enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
  1190. for (;;) {
  1191. c = input_stack::get_char();
  1192. if (c == EOF) {
  1193. lex_error("missing closing delimiter");
  1194. return 0;
  1195. }
  1196. if (c == '\n')
  1197. had_newline = 1;
  1198. else if (!had_newline)
  1199. context_buffer += char(c);
  1200. switch (state) {
  1201. case NORMAL:
  1202. if (start == '{') {
  1203. if (c == '{') {
  1204. level++;
  1205. break;
  1206. }
  1207. if (c == '}') {
  1208. if (--level < 0)
  1209. state = DELIM_END;
  1210. break;
  1211. }
  1212. }
  1213. else {
  1214. if (c == start) {
  1215. state = DELIM_END;
  1216. break;
  1217. }
  1218. }
  1219. if (c == '"')
  1220. state = IN_STRING;
  1221. break;
  1222. case IN_STRING_QUOTED:
  1223. if (c == '\n')
  1224. state = NORMAL;
  1225. else
  1226. state = IN_STRING;
  1227. break;
  1228. case IN_STRING:
  1229. if (c == '"' || c == '\n')
  1230. state = NORMAL;
  1231. else if (c == '\\')
  1232. state = IN_STRING_QUOTED;
  1233. break;
  1234. case DELIM_END:
  1235. // This case it just to shut cfront 2.0 up.
  1236. default:
  1237. assert(0);
  1238. }
  1239. if (state == DELIM_END)
  1240. break;
  1241. token_buffer += c;
  1242. }
  1243. return 1;
  1244. }
  1245. void do_define()
  1246. {
  1247. int t = get_token(0); // do not expand what we are defining
  1248. if (t != VARIABLE && t != LABEL) {
  1249. lex_error("can only define variable or placename");
  1250. return;
  1251. }
  1252. token_buffer += '\0';
  1253. string nm = token_buffer;
  1254. const char *name = nm.contents();
  1255. if (!get_delimited())
  1256. return;
  1257. token_buffer += '\0';
  1258. macro_table.define(name, strsave(token_buffer.contents()));
  1259. }
  1260. void do_undef()
  1261. {
  1262. int t = get_token(0); // do not expand what we are undefining
  1263. if (t != VARIABLE && t != LABEL) {
  1264. lex_error("can only define variable or placename");
  1265. return;
  1266. }
  1267. token_buffer += '\0';
  1268. macro_table.define(token_buffer.contents(), 0);
  1269. }
  1270. class for_input : public input {
  1271. char *var;
  1272. char *body;
  1273. double from;
  1274. double to;
  1275. int by_is_multiplicative;
  1276. double by;
  1277. const char *p;
  1278. int done_newline;
  1279. public:
  1280. for_input(char *, double, double, int, double, char *);
  1281. ~for_input();
  1282. int get();
  1283. int peek();
  1284. };
  1285. for_input::for_input(char *vr, double f, double t,
  1286. int bim, double b, char *bd)
  1287. : var(vr), body(bd), from(f), to(t), by_is_multiplicative(bim), by(b),
  1288. p(body), done_newline(0)
  1289. {
  1290. }
  1291. for_input::~for_input()
  1292. {
  1293. a_delete var;
  1294. a_delete body;
  1295. }
  1296. int for_input::get()
  1297. {
  1298. if (p == 0)
  1299. return EOF;
  1300. for (;;) {
  1301. if (*p != '\0')
  1302. return (unsigned char)*p++;
  1303. if (!done_newline) {
  1304. done_newline = 1;
  1305. return '\n';
  1306. }
  1307. double val;
  1308. if (!lookup_variable(var, &val)) {
  1309. lex_error("body of `for' terminated enclosing block");
  1310. return EOF;
  1311. }
  1312. if (by_is_multiplicative)
  1313. val *= by;
  1314. else
  1315. val += by;
  1316. define_variable(var, val);
  1317. if ((from <= to && val > to)
  1318. || (from >= to && val < to)) {
  1319. p = 0;
  1320. return EOF;
  1321. }
  1322. p = body;
  1323. done_newline = 0;
  1324. }
  1325. }
  1326. int for_input::peek()
  1327. {
  1328. if (p == 0)
  1329. return EOF;
  1330. if (*p != '\0')
  1331. return (unsigned char)*p;
  1332. if (!done_newline)
  1333. return '\n';
  1334. double val;
  1335. if (!lookup_variable(var, &val))
  1336. return EOF;
  1337. if (by_is_multiplicative) {
  1338. if (val * by > to)
  1339. return EOF;
  1340. }
  1341. else {
  1342. if ((from <= to && val + by > to)
  1343. || (from >= to && val + by < to))
  1344. return EOF;
  1345. }
  1346. if (*body == '\0')
  1347. return EOF;
  1348. return (unsigned char)*body;
  1349. }
  1350. void do_for(char *var, double from, double to, int by_is_multiplicative,
  1351. double by, char *body)
  1352. {
  1353. define_variable(var, from);
  1354. if ((by_is_multiplicative && by <= 0)
  1355. || (by > 0 && from > to)
  1356. || (by < 0 && from < to))
  1357. return;
  1358. input_stack::push(new for_input(var, from, to,
  1359. by_is_multiplicative, by, body));
  1360. }
  1361. void do_copy(const char *filename)
  1362. {
  1363. errno = 0;
  1364. FILE *fp = fopen(filename, "r");
  1365. if (fp == 0) {
  1366. lex_error("can't open `%1': %2", filename, strerror(errno));
  1367. return;
  1368. }
  1369. input_stack::push(new file_input(fp, filename));
  1370. }
  1371. class copy_thru_input : public input {
  1372. int done;
  1373. char *body;
  1374. char *until;
  1375. const char *p;
  1376. const char *ap;
  1377. int argv[9];
  1378. int argc;
  1379. string line;
  1380. int get_line();
  1381. virtual int inget() = 0;
  1382. public:
  1383. copy_thru_input(const char *b, const char *u);
  1384. ~copy_thru_input();
  1385. int get();
  1386. int peek();
  1387. };
  1388. class copy_file_thru_input : public copy_thru_input {
  1389. input *in;
  1390. public:
  1391. copy_file_thru_input(input *, const char *b, const char *u);
  1392. ~copy_file_thru_input();
  1393. int inget();
  1394. };
  1395. copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
  1396. const char *u)
  1397. : copy_thru_input(b, u), in(i)
  1398. {
  1399. }
  1400. copy_file_thru_input::~copy_file_thru_input()
  1401. {
  1402. delete in;
  1403. }
  1404. int copy_file_thru_input::inget()
  1405. {
  1406. if (!in)
  1407. return EOF;
  1408. else
  1409. return in->get();
  1410. }
  1411. class copy_rest_thru_input : public copy_thru_input {
  1412. public:
  1413. copy_rest_thru_input(const char *, const char *u);
  1414. int inget();
  1415. };
  1416. copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
  1417. : copy_thru_input(b, u)
  1418. {
  1419. }
  1420. int copy_rest_thru_input::inget()
  1421. {
  1422. while (next != 0) {
  1423. int c = next->get();
  1424. if (c != EOF)
  1425. return c;
  1426. if (next->next == 0)
  1427. return EOF;
  1428. input *tem = next;
  1429. next = next->next;
  1430. delete tem;
  1431. }
  1432. return EOF;
  1433. }
  1434. copy_thru_input::copy_thru_input(const char *b, const char *u)
  1435. : done(0)
  1436. {
  1437. ap = 0;
  1438. body = process_body(b);
  1439. p = 0;
  1440. until = strsave(u);
  1441. }
  1442. copy_thru_input::~copy_thru_input()
  1443. {
  1444. a_delete body;
  1445. a_delete until;
  1446. }
  1447. int copy_thru_input::get()
  1448. {
  1449. if (ap) {
  1450. if (*ap != '\0')
  1451. return (unsigned char)*ap++;
  1452. ap = 0;
  1453. }
  1454. for (;;) {
  1455. if (p == 0) {
  1456. if (!get_line())
  1457. break;
  1458. p = body;
  1459. }
  1460. if (*p == '\0') {
  1461. p = 0;
  1462. return '\n';
  1463. }
  1464. while (*p >= ARG1 && *p <= ARG1 + 8) {
  1465. int i = *p++ - ARG1;
  1466. if (i < argc && line[argv[i]] != '\0') {
  1467. ap = line.contents() + argv[i];
  1468. return (unsigned char)*ap++;
  1469. }
  1470. }
  1471. if (*p != '\0')
  1472. return (unsigned char)*p++;
  1473. }
  1474. return EOF;
  1475. }
  1476. int copy_thru_input::peek()
  1477. {
  1478. if (ap) {
  1479. if (*ap != '\0')
  1480. return (unsigned char)*ap;
  1481. ap = 0;
  1482. }
  1483. for (;;) {
  1484. if (p == 0) {
  1485. if (!get_line())
  1486. break;
  1487. p = body;
  1488. }
  1489. if (*p == '\0')
  1490. return '\n';
  1491. while (*p >= ARG1 && *p <= ARG1 + 8) {
  1492. int i = *p++ - ARG1;
  1493. if (i < argc && line[argv[i]] != '\0') {
  1494. ap = line.contents() + argv[i];
  1495. return (unsigned char)*ap;
  1496. }
  1497. }
  1498. if (*p != '\0')
  1499. return (unsigned char)*p;
  1500. }
  1501. return EOF;
  1502. }
  1503. int copy_thru_input::get_line()
  1504. {
  1505. if (done)
  1506. return 0;
  1507. line.clear();
  1508. argc = 0;
  1509. int c = inget();
  1510. for (;;) {
  1511. while (c == ' ')
  1512. c = inget();
  1513. if (c == EOF || c == '\n')
  1514. break;
  1515. if (argc == 9) {
  1516. do {
  1517. c = inget();
  1518. } while (c != '\n' && c != EOF);
  1519. break;
  1520. }
  1521. argv[argc++] = line.length();
  1522. do {
  1523. line += char(c);
  1524. c = inget();
  1525. } while (c != ' ' && c != '\n');
  1526. line += '\0';
  1527. }
  1528. if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
  1529. done = 1;
  1530. return 0;
  1531. }
  1532. return argc > 0 || c == '\n';
  1533. }
  1534. class simple_file_input : public input {
  1535. const char *filename;
  1536. int lineno;
  1537. FILE *fp;
  1538. public:
  1539. simple_file_input(FILE *, const char *);
  1540. ~simple_file_input();
  1541. int get();
  1542. int peek();
  1543. int get_location(const char **, int *);
  1544. };
  1545. simple_file_input::simple_file_input(FILE *p, const char *s)
  1546. : filename(s), lineno(1), fp(p)
  1547. {
  1548. }
  1549. simple_file_input::~simple_file_input()
  1550. {
  1551. // don't delete the filename
  1552. fclose(fp);
  1553. }
  1554. int simple_file_input::get()
  1555. {
  1556. int c = getc(fp);
  1557. while (invalid_input_char(c)) {
  1558. error("invalid input character code %1", c);
  1559. c = getc(fp);
  1560. }
  1561. if (c == '\n')
  1562. lineno++;
  1563. return c;
  1564. }
  1565. int simple_file_input::peek()
  1566. {
  1567. int c = getc(fp);
  1568. while (invalid_input_char(c)) {
  1569. error("invalid input character code %1", c);
  1570. c = getc(fp);
  1571. }
  1572. if (c != EOF)
  1573. ungetc(c, fp);
  1574. return c;
  1575. }
  1576. int simple_file_input::get_location(const char **fnp, int *lnp)
  1577. {
  1578. *fnp = filename;
  1579. *lnp = lineno;
  1580. return 1;
  1581. }
  1582. void copy_file_thru(const char *filename, const char *body, const char *until)
  1583. {
  1584. errno = 0;
  1585. FILE *fp = fopen(filename, "r");
  1586. if (fp == 0) {
  1587. lex_error("can't open `%1': %2", filename, strerror(errno));
  1588. return;
  1589. }
  1590. input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
  1591. body, until);
  1592. input_stack::push(in);
  1593. }
  1594. void copy_rest_thru(const char *body, const char *until)
  1595. {
  1596. input_stack::push(new copy_rest_thru_input(body, until));
  1597. }
  1598. void push_body(const char *s)
  1599. {
  1600. input_stack::push(new char_input('\n'));
  1601. input_stack::push(new macro_input(s));
  1602. }
  1603. int delim_flag = 0;
  1604. char *get_thru_arg()
  1605. {
  1606. int c = input_stack::peek_char();
  1607. while (c == ' ') {
  1608. input_stack::get_char();
  1609. c = input_stack::peek_char();
  1610. }
  1611. if (c != EOF && csalpha(c)) {
  1612. // looks like a macro
  1613. input_stack::get_char();
  1614. token_buffer = c;
  1615. for (;;) {
  1616. c = input_stack::peek_char();
  1617. if (c == EOF || (!csalnum(c) && c != '_'))
  1618. break;
  1619. input_stack::get_char();
  1620. token_buffer += char(c);
  1621. }
  1622. context_buffer = token_buffer;
  1623. token_buffer += '\0';
  1624. char *def = macro_table.lookup(token_buffer.contents());
  1625. if (def)
  1626. return strsave(def);
  1627. // I guess it wasn't a macro after all; so push the macro name back.
  1628. // -2 because we added a '\0'
  1629. for (int i = token_buffer.length() - 2; i >= 0; i--)
  1630. input_stack::push_back(token_buffer[i]);
  1631. }
  1632. if (get_delimited()) {
  1633. token_buffer += '\0';
  1634. return strsave(token_buffer.contents());
  1635. }
  1636. else
  1637. return 0;
  1638. }
  1639. int lookahead_token = -1;
  1640. string old_context_buffer;
  1641. void do_lookahead()
  1642. {
  1643. if (lookahead_token == -1) {
  1644. old_context_buffer = context_buffer;
  1645. lookahead_token = get_token(1);
  1646. }
  1647. }
  1648. int yylex()
  1649. {
  1650. if (delim_flag) {
  1651. assert(lookahead_token == -1);
  1652. if (delim_flag == 2) {
  1653. if ((yylval.str = get_thru_arg()) != 0)
  1654. return DELIMITED;
  1655. else
  1656. return 0;
  1657. }
  1658. else {
  1659. if (get_delimited()) {
  1660. token_buffer += '\0';
  1661. yylval.str = strsave(token_buffer.contents());
  1662. return DELIMITED;
  1663. }
  1664. else
  1665. return 0;
  1666. }
  1667. }
  1668. for (;;) {
  1669. int t;
  1670. if (lookahead_token >= 0) {
  1671. t = lookahead_token;
  1672. lookahead_token = -1;
  1673. }
  1674. else
  1675. t = get_token(1);
  1676. switch (t) {
  1677. case '\n':
  1678. return ';';
  1679. case EOF:
  1680. return 0;
  1681. case DEFINE:
  1682. do_define();
  1683. break;
  1684. case UNDEF:
  1685. do_undef();
  1686. break;
  1687. case ORDINAL:
  1688. yylval.n = token_int;
  1689. return t;
  1690. case NUMBER:
  1691. yylval.x = token_double;
  1692. return t;
  1693. case COMMAND_LINE:
  1694. case TEXT:
  1695. token_buffer += '\0';
  1696. if (!input_stack::get_location(&yylval.lstr.filename,
  1697. &yylval.lstr.lineno)) {
  1698. yylval.lstr.filename = 0;
  1699. yylval.lstr.lineno = -1;
  1700. }
  1701. yylval.lstr.str = strsave(token_buffer.contents());
  1702. return t;
  1703. case LABEL:
  1704. case VARIABLE:
  1705. token_buffer += '\0';
  1706. yylval.str = strsave(token_buffer.contents());
  1707. return t;
  1708. case LEFT:
  1709. // change LEFT to LEFT_CORNER when followed by OF
  1710. old_context_buffer = context_buffer;
  1711. lookahead_token = get_token(1);
  1712. if (lookahead_token == OF)
  1713. return LEFT_CORNER;
  1714. else
  1715. return t;
  1716. case RIGHT:
  1717. // change RIGHT to RIGHT_CORNER when followed by OF
  1718. old_context_buffer = context_buffer;
  1719. lookahead_token = get_token(1);
  1720. if (lookahead_token == OF)
  1721. return RIGHT_CORNER;
  1722. else
  1723. return t;
  1724. case UPPER:
  1725. // recognise UPPER only before LEFT or RIGHT
  1726. old_context_buffer = context_buffer;
  1727. lookahead_token = get_token(1);
  1728. if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1729. yylval.str = strsave("upper");
  1730. return VARIABLE;
  1731. }
  1732. else
  1733. return t;
  1734. case LOWER:
  1735. // recognise LOWER only before LEFT or RIGHT
  1736. old_context_buffer = context_buffer;
  1737. lookahead_token = get_token(1);
  1738. if (lookahead_token != LEFT && lookahead_token != RIGHT) {
  1739. yylval.str = strsave("lower");
  1740. return VARIABLE;
  1741. }
  1742. else
  1743. return t;
  1744. case NORTH:
  1745. // recognise NORTH only before OF
  1746. old_context_buffer = context_buffer;
  1747. lookahead_token = get_token(1);
  1748. if (lookahead_token != OF) {
  1749. yylval.str = strsave("north");
  1750. return VARIABLE;
  1751. }
  1752. else
  1753. return t;
  1754. case SOUTH:
  1755. // recognise SOUTH only before OF
  1756. old_context_buffer = context_buffer;
  1757. lookahead_token = get_token(1);
  1758. if (lookahead_token != OF) {
  1759. yylval.str = strsave("south");
  1760. return VARIABLE;
  1761. }
  1762. else
  1763. return t;
  1764. case EAST:
  1765. // recognise EAST only before OF
  1766. old_context_buffer = context_buffer;
  1767. lookahead_token = get_token(1);
  1768. if (lookahead_token != OF) {
  1769. yylval.str = strsave("east");
  1770. return VARIABLE;
  1771. }
  1772. else
  1773. return t;
  1774. case WEST:
  1775. // recognise WEST only before OF
  1776. old_context_buffer = context_buffer;
  1777. lookahead_token = get_token(1);
  1778. if (lookahead_token != OF) {
  1779. yylval.str = strsave("west");
  1780. return VARIABLE;
  1781. }
  1782. else
  1783. return t;
  1784. case TOP:
  1785. // recognise TOP only before OF
  1786. old_context_buffer = context_buffer;
  1787. lookahead_token = get_token(1);
  1788. if (lookahead_token != OF) {
  1789. yylval.str = strsave("top");
  1790. return VARIABLE;
  1791. }
  1792. else
  1793. return t;
  1794. case BOTTOM:
  1795. // recognise BOTTOM only before OF
  1796. old_context_buffer = context_buffer;
  1797. lookahead_token = get_token(1);
  1798. if (lookahead_token != OF) {
  1799. yylval.str = strsave("bottom");
  1800. return VARIABLE;
  1801. }
  1802. else
  1803. return t;
  1804. case CENTER:
  1805. // recognise CENTER only before OF
  1806. old_context_buffer = context_buffer;
  1807. lookahead_token = get_token(1);
  1808. if (lookahead_token != OF) {
  1809. yylval.str = strsave("center");
  1810. return VARIABLE;
  1811. }
  1812. else
  1813. return t;
  1814. case START:
  1815. // recognise START only before OF
  1816. old_context_buffer = context_buffer;
  1817. lookahead_token = get_token(1);
  1818. if (lookahead_token != OF) {
  1819. yylval.str = strsave("start");
  1820. return VARIABLE;
  1821. }
  1822. else
  1823. return t;
  1824. case END:
  1825. // recognise END only before OF
  1826. old_context_buffer = context_buffer;
  1827. lookahead_token = get_token(1);
  1828. if (lookahead_token != OF) {
  1829. yylval.str = strsave("end");
  1830. return VARIABLE;
  1831. }
  1832. else
  1833. return t;
  1834. default:
  1835. return t;
  1836. }
  1837. }
  1838. }
  1839. void lex_error(const char *message,
  1840. const errarg &arg1,
  1841. const errarg &arg2,
  1842. const errarg &arg3)
  1843. {
  1844. const char *filename;
  1845. int lineno;
  1846. if (!input_stack::get_location(&filename, &lineno))
  1847. error(message, arg1, arg2, arg3);
  1848. else
  1849. error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1850. }
  1851. void lex_warning(const char *message,
  1852. const errarg &arg1,
  1853. const errarg &arg2,
  1854. const errarg &arg3)
  1855. {
  1856. const char *filename;
  1857. int lineno;
  1858. if (!input_stack::get_location(&filename, &lineno))
  1859. warning(message, arg1, arg2, arg3);
  1860. else
  1861. warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1862. }
  1863. void yyerror(const char *s)
  1864. {
  1865. const char *filename;
  1866. int lineno;
  1867. const char *context = 0;
  1868. if (lookahead_token == -1) {
  1869. if (context_buffer.length() > 0) {
  1870. context_buffer += '\0';
  1871. context = context_buffer.contents();
  1872. }
  1873. }
  1874. else {
  1875. if (old_context_buffer.length() > 0) {
  1876. old_context_buffer += '\0';
  1877. context = old_context_buffer.contents();
  1878. }
  1879. }
  1880. if (!input_stack::get_location(&filename, &lineno)) {
  1881. if (context) {
  1882. if (context[0] == '\n' && context[1] == '\0')
  1883. error("%1 before newline", s);
  1884. else
  1885. error("%1 before `%2'", s, context);
  1886. }
  1887. else
  1888. error("%1 at end of picture", s);
  1889. }
  1890. else {
  1891. if (context) {
  1892. if (context[0] == '\n' && context[1] == '\0')
  1893. error_with_file_and_line(filename, lineno, "%1 before newline", s);
  1894. else
  1895. error_with_file_and_line(filename, lineno, "%1 before `%2'",
  1896. s, context);
  1897. }
  1898. else
  1899. error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
  1900. }
  1901. }