home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / gnu / groff-1.09-src.lha / src / amiga / groff-1.09 / eqn / lex.cc < prev    next >
C/C++ Source or Header  |  1994-02-14  |  25KB  |  1,161 lines

  1. // -*- C++ -*-
  2. /* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  3.      Written by James Clark (jjc@jclark.com)
  4.  
  5. This file is part of groff.
  6.  
  7. groff is free software; you can redistribute it and/or modify it under
  8. the terms of the GNU General Public License as published by the Free
  9. Software Foundation; either version 2, or (at your option) any later
  10. version.
  11.  
  12. groff is distributed in the hope that it will be useful, but WITHOUT ANY
  13. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  15. for more details.
  16.  
  17. You should have received a copy of the GNU General Public License along
  18. with groff; see the file COPYING.  If not, write to the Free Software
  19. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  20.  
  21. #include "eqn.h"
  22. #include "eqn.tab.h"
  23. #include "stringclass.h"
  24. #include "ptable.h"
  25.  
  26. struct definition {
  27.   char is_macro;
  28.   char is_simple;
  29.   union {
  30.     int tok;
  31.     char *contents;
  32.   };
  33.   definition();
  34.   ~definition();
  35. };
  36.  
  37. definition::definition() : is_macro(1), is_simple(0)
  38. {
  39.   contents = 0;
  40. }
  41.  
  42. definition::~definition()
  43. {
  44.   if (is_macro)
  45.     a_delete contents;
  46. }
  47.  
  48. declare_ptable(definition)
  49. implement_ptable(definition)
  50.  
  51. PTABLE(definition) macro_table;
  52.  
  53. static struct {
  54.   const char *name;
  55.   int token;
  56. } token_table[] = {
  57.   { "over", OVER },
  58.   { "smallover", SMALLOVER },
  59.   { "sqrt", SQRT },
  60.   { "sub", SUB },
  61.   { "sup", SUP },
  62.   { "lpile", LPILE },
  63.   { "rpile", RPILE },
  64.   { "cpile", CPILE },
  65.   { "pile", PILE },
  66.   { "left", LEFT },
  67.   { "right", RIGHT },
  68.   { "to", TO },
  69.   { "from", FROM },
  70.   { "size", SIZE },
  71.   { "font", FONT },
  72.   { "roman", ROMAN },
  73.   { "bold", BOLD },
  74.   { "italic", ITALIC },
  75.   { "fat", FAT },
  76.   { "bar", BAR },
  77.   { "under", UNDER },
  78.   { "accent", ACCENT },
  79.   { "uaccent", UACCENT },
  80.   { "above", ABOVE },
  81.   { "fwd", FWD },
  82.   { "back", BACK },
  83.   { "down", DOWN },
  84.   { "up", UP },
  85.   { "matrix", MATRIX },
  86.   { "col", COL },
  87.   { "lcol", LCOL },
  88.   { "rcol", RCOL },
  89.   { "ccol", CCOL },
  90.   { "mark", MARK },
  91.   { "lineup", LINEUP },
  92.   { "space", SPACE },
  93.   { "gfont", GFONT },
  94.   { "gsize", GSIZE },
  95.   { "define", DEFINE },
  96.   { "sdefine", SDEFINE },
  97.   { "ndefine", NDEFINE },
  98.   { "tdefine", TDEFINE },
  99.   { "undef", UNDEF },
  100.   { "ifdef", IFDEF },
  101.   { "include", INCLUDE },
  102.   { "copy", INCLUDE },
  103.   { "delim", DELIM },
  104.   { "chartype", CHARTYPE },
  105.   { "type", TYPE },
  106.   { "vcenter", VCENTER },
  107.   { "set", SET },
  108.   { "opprime", PRIME },
  109.   { "grfont", GRFONT },
  110.   { "gbfont", GBFONT },
  111.   { "split", SPLIT },
  112.   { "nosplit", NOSPLIT },
  113.   { "special", SPECIAL },
  114. };
  115.  
  116. static struct {
  117.   const char *name;
  118.   const char *def;
  119. } def_table[] = {
  120.   { "ALPHA", "\\(*A" },
  121.   { "BETA", "\\(*B" },
  122.   { "CHI", "\\(*X" },
  123.   { "DELTA", "\\(*D" },
  124.   { "EPSILON", "\\(*E" },
  125.   { "ETA", "\\(*Y" },
  126.   { "GAMMA", "\\(*G" },
  127.   { "IOTA", "\\(*I" },
  128.   { "KAPPA", "\\(*K" },
  129.   { "LAMBDA", "\\(*L" },
  130.   { "MU", "\\(*M" },
  131.   { "NU", "\\(*N" },
  132.   { "OMEGA", "\\(*W" },
  133.   { "OMICRON", "\\(*O" },
  134.   { "PHI", "\\(*F" },
  135.   { "PI", "\\(*P" },
  136.   { "PSI", "\\(*Q" },
  137.   { "RHO", "\\(*R" },
  138.   { "SIGMA", "\\(*S" },
  139.   { "TAU", "\\(*T" },
  140.   { "THETA", "\\(*H" },
  141.   { "UPSILON", "\\(*U" },
  142.   { "XI", "\\(*C" },
  143.   { "ZETA", "\\(*Z" },
  144.   { "Alpha", "\\(*A" },
  145.   { "Beta", "\\(*B" },
  146.   { "Chi", "\\(*X" },
  147.   { "Delta", "\\(*D" },
  148.   { "Epsilon", "\\(*E" },
  149.   { "Eta", "\\(*Y" },
  150.   { "Gamma", "\\(*G" },
  151.   { "Iota", "\\(*I" },
  152.   { "Kappa", "\\(*K" },
  153.   { "Lambda", "\\(*L" },
  154.   { "Mu", "\\(*M" },
  155.   { "Nu", "\\(*N" },
  156.   { "Omega", "\\(*W" },
  157.   { "Omicron", "\\(*O" },
  158.   { "Phi", "\\(*F" },
  159.   { "Pi", "\\(*P" },
  160.   { "Psi", "\\(*Q" },
  161.   { "Rho", "\\(*R" },
  162.   { "Sigma", "\\(*S" },
  163.   { "Tau", "\\(*T" },
  164.   { "Theta", "\\(*H" },
  165.   { "Upsilon", "\\(*U" },
  166.   { "Xi", "\\(*C" },
  167.   { "Zeta", "\\(*Z" },
  168.   { "alpha", "\\(*a" },
  169.   { "beta", "\\(*b" },
  170.   { "chi", "\\(*x" },
  171.   { "delta", "\\(*d" },
  172.   { "epsilon", "\\(*e" },
  173.   { "eta", "\\(*y" },
  174.   { "gamma", "\\(*g" },
  175.   { "iota", "\\(*i" },
  176.   { "kappa", "\\(*k" },
  177.   { "lambda", "\\(*l" },
  178.   { "mu", "\\(*m" },
  179.   { "nu", "\\(*n" },
  180.   { "omega", "\\(*w" },
  181.   { "omicron", "\\(*o" },
  182.   { "phi", "\\(*f" },
  183.   { "pi", "\\(*p" },
  184.   { "psi", "\\(*q" },
  185.   { "rho", "\\(*r" },
  186.   { "sigma", "\\(*s" },
  187.   { "tau", "\\(*t" },
  188.   { "theta", "\\(*h" },
  189.   { "upsilon", "\\(*u" },
  190.   { "xi", "\\(*c" },
  191.   { "zeta", "\\(*z" },
  192.   { "max", "{type \"operator\" roman \"max\"}" },
  193.   { "min", "{type \"operator\" roman \"min\"}" },
  194.   { "lim", "{type \"operator\" roman \"lim\"}" },
  195.   { "sin", "{type \"operator\" roman \"sin\"}" },
  196.   { "cos", "{type \"operator\" roman \"cos\"}" },
  197.   { "tan", "{type \"operator\" roman \"tan\"}" },
  198.   { "sinh", "{type \"operator\" roman \"sinh\"}" },
  199.   { "cosh", "{type \"operator\" roman \"cosh\"}" },
  200.   { "tanh", "{type \"operator\" roman \"tanh\"}" },
  201.   { "arc", "{type \"operator\" roman \"arc\"}" },
  202.   { "log", "{type \"operator\" roman \"log\"}" },
  203.   { "ln", "{type \"operator\" roman \"ln\"}" },
  204.   { "exp", "{type \"operator\" roman \"exp\"}" },
  205.   { "Re", "{type \"operator\" roman \"Re\"}" },
  206.   { "Im", "{type \"operator\" roman \"Im\"}" },
  207.   { "det", "{type \"operator\" roman \"det\"}" },
  208.   { "and", "{roman \"and\"}" },
  209.   { "if", "{roman \"if\"}" },
  210.   { "for", "{roman \"for\"}" },
  211.   { "sum", "{type \"operator\" vcenter size +5 \\(*S}" },
  212.   { "prod", "{type \"operator\" vcenter size +5 \\(*P}" },
  213.   { "int", "{type \"operator\" vcenter size +8 \\(is}" },
  214.   { "union", "{type \"operator\" vcenter size +5 \\(cu}" },
  215.   { "inter", "{type \"operator\" vcenter size +5 \\(ca}" },
  216.   { "times", "type \"binary\" \\(mu" },
  217.   { "ldots", "type \"inner\" { . . . }" },
  218.   { "inf", "\\(if" },
  219.   { "partial", "\\(pd" },
  220.   { "nothing", "\"\"" },
  221.   { "half", "{1 smallover 2}" },
  222.   { "hat_def", "roman \"^\"" },
  223.   { "hat", "accent { hat_def }" },
  224.   { "dot_def", "back 15 \"\\v'-52M'.\\v'52M'\"" },
  225.   { "dot", "accent { dot_def }" },
  226.   { "dotdot_def", "back 25 \"\\v'-52M'..\\v'52M'\"" },
  227.   { "dotdot", "accent { dotdot_def }" },
  228.   { "tilde_def", "\"~\"" },
  229.   { "tilde", "accent { tilde_def }" },
  230.   { "utilde_def", "\"\\v'75M'~\\v'-75M'\"" },
  231.   { "utilde", "uaccent { utilde_def }" },
  232.   { "vec_def", "up 52 size -5 \\(->" },
  233.   { "vec", "accent { vec_def }" },
  234.   { "dyad_def", "up 52 size -5 {\\(<- back 60 \\(->}" },
  235.   { "dyad", "accent { dyad_def }" },
  236.   { "==", "type \"relation\" \\(==" },
  237.   { "!=", "type \"relation\" \\(!=" },
  238.   { "+-", "type \"binary\" \\(+-" },
  239.   { "->", "type \"relation\" \\(->" },
  240.   { "<-", "type \"relation\" \\(<-" },
  241.   { "<<", "{ < back 20 < }" },
  242.   { ">>", "{ > back 20 > }" },
  243.   { "...", "type \"inner\" vcenter { . . . }" },
  244.   { "prime", "'" },
  245.   { "approx", "type \"relation\" \"\\(~=\"" },
  246.   { "grad", "\\(gr" },
  247.   { "del", "\\(gr" },
  248.   { "cdot", "type \"binary\" vcenter ." },
  249.   { "dollar", "$" },
  250. };  
  251.  
  252. void init_table(const char *device)
  253. {
  254.   for (int i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) {
  255.     definition *def = new definition;
  256.     def->is_macro = 0;
  257.     def->tok = token_table[i].token;
  258.     macro_table.define(token_table[i].name, def);
  259.   }
  260.   for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) {
  261.     definition *def = new definition;
  262.     def->is_macro = 1;
  263.     def->contents = strsave(def_table[i].def);
  264.     def->is_simple = 1;
  265.     macro_table.define(def_table[i].name, def);
  266.   }
  267.   definition *def = new definition;
  268.   def->is_macro = 1;
  269.   def->contents = strsave("1");
  270.   macro_table.define(device, def);
  271. }
  272.  
  273. class input {
  274.   input *next;
  275. public:
  276.   input(input *p);
  277.   virtual ~input();
  278.   virtual int get() = 0;
  279.   virtual int peek() = 0;
  280.   virtual int get_location(char **, int *);
  281.  
  282.   friend int get_char();
  283.   friend int peek_char();
  284.   friend int get_location(char **, int *);
  285.   friend void init_lex(const char *str, const char *filename, int lineno);
  286. };
  287.  
  288. class file_input : public input {
  289.   FILE *fp;
  290.   char *filename;
  291.   int lineno;
  292.   string line;
  293.   const char *ptr;
  294.   int read_line();
  295. public:
  296.   file_input(FILE *, const char *, input *);
  297.   ~file_input();
  298.   int get();
  299.   int peek();
  300.   int get_location(char **, int *);
  301. };
  302.  
  303.  
  304. class macro_input : public input {
  305.   char *s;
  306.   char *p;
  307. public:
  308.   macro_input(const char *, input *);
  309.   ~macro_input();
  310.   int get();
  311.   int peek();
  312. };
  313.  
  314. class top_input : public macro_input {
  315.   char *filename;
  316.   int lineno;
  317.  public:
  318.   top_input(const char *, const char *, int, input *);
  319.   ~top_input();
  320.   int get();
  321.   int get_location(char **, int *);
  322. };
  323.  
  324. class argument_macro_input: public input {
  325.   char *s;
  326.   char *p;
  327.   char *ap;
  328.   int argc;
  329.   char *argv[9];
  330. public:
  331.   argument_macro_input(const char *, int, char **, input *);
  332.   ~argument_macro_input();
  333.   int get();
  334.   int peek();
  335. };
  336.  
  337. input::input(input *x) : next(x)
  338. {
  339. }
  340.  
  341. input::~input()
  342. {
  343. }
  344.  
  345. int input::get_location(char **, int *)
  346. {
  347.   return 0;
  348. }
  349.  
  350. file_input::file_input(FILE *f, const char *fn, input *p)
  351. : input(p), lineno(0), ptr("")
  352. {
  353.   fp = f;
  354.   filename = strsave(fn);
  355. }
  356.  
  357. file_input::~file_input()
  358. {
  359.   a_delete filename;
  360.   fclose(fp);
  361. }
  362.  
  363. int file_input::read_line()
  364. {
  365.   for (;;) {
  366.     line.clear();
  367.     lineno++;
  368.     for (;;) {
  369.       int c = getc(fp);
  370.       if (c == EOF)
  371.     break;
  372.       else if (illegal_input_char(c))
  373.     lex_error("illegal input character code %1", c);
  374.       else {
  375.     line += char(c);
  376.     if (c == '\n') 
  377.       break;
  378.       }
  379.     }
  380.     if (line.length() == 0)
  381.       return 0;
  382.     if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E'
  383.       && (line[2] == 'Q' || line[2] == 'N')
  384.       && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
  385.           || compatible_flag))) {
  386.       line += '\0';
  387.       ptr = line.contents();
  388.       return 1;
  389.     }
  390.   }
  391. }
  392.  
  393. int file_input::get()
  394. {
  395.   if (*ptr != '\0' || read_line())
  396.     return *ptr++ & 0377;
  397.   else
  398.     return EOF;
  399. }
  400.  
  401. int file_input::peek()
  402. {
  403.   if (*ptr != '\0' || read_line())
  404.     return *ptr;
  405.   else
  406.     return EOF;
  407. }
  408.  
  409. int file_input::get_location(char **fnp, int *lnp)
  410. {
  411.   *fnp = filename;
  412.   *lnp = lineno;
  413.   return 1;
  414. }
  415.  
  416. macro_input::macro_input(const char *str, input *x) : input(x)
  417. {
  418.   p = s = strsave(str);
  419. }
  420.  
  421. macro_input::~macro_input()
  422. {
  423.   a_delete s;
  424. }
  425.  
  426. int macro_input::get()
  427. {
  428.   if (p == 0 || *p == '\0')
  429.     return EOF;
  430.   else
  431.     return *p++ & 0377;
  432. }
  433.  
  434. int macro_input::peek()
  435. {
  436.   if (p == 0 || *p == '\0')
  437.     return EOF;
  438.   else
  439.     return *p & 0377;
  440. }
  441.  
  442. top_input::top_input(const char *str, const char *fn, int ln, input *x)
  443. : macro_input(str, x), lineno(ln)
  444. {
  445.   filename = strsave(fn);
  446. }
  447.  
  448. top_input::~top_input()
  449. {
  450.   a_delete filename;
  451. }
  452.  
  453. int top_input::get()
  454. {
  455.   int c = macro_input::get();
  456.   if (c == '\n')
  457.     lineno++;
  458.   return c;
  459. }
  460.  
  461. int top_input::get_location(char **fnp, int *lnp)
  462. {
  463.   *fnp = filename;
  464.   *lnp = lineno;
  465.   return 1;
  466. }
  467.  
  468. // Character representing $1.  Must be illegal input character.
  469. #define ARG1 14
  470.  
  471. argument_macro_input::argument_macro_input(const char *body, int ac, 
  472.                        char **av, input *x)
  473. : input(x), argc(ac), ap(0)
  474. {
  475.   for (int i = 0; i < argc; i++)
  476.     argv[i] = av[i];
  477.   p = s = strsave(body);
  478.   int j = 0;
  479.   for (i = 0; s[i] != '\0'; i++)
  480.     if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
  481.       if (s[i+1] != '0')
  482.     s[j++] = ARG1 + s[++i] - '1';
  483.     }
  484.     else
  485.       s[j++] = s[i];
  486.   s[j] = '\0';
  487. }
  488.  
  489.  
  490. argument_macro_input::~argument_macro_input()
  491. {
  492.   for (int i = 0; i < argc; i++)
  493.     a_delete argv[i];
  494.   a_delete s;
  495. }
  496.  
  497. int argument_macro_input::get()
  498. {
  499.   if (ap) {
  500.     if (*ap != '\0')
  501.       return *ap++ & 0377;
  502.     ap = 0;
  503.   }
  504.   if (p == 0)
  505.     return EOF;
  506.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  507.     int i = *p++ - ARG1;
  508.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  509.       ap = argv[i];
  510.       return *ap++ & 0377;
  511.     }
  512.   }
  513.   if (*p == '\0')
  514.     return EOF;
  515.   return *p++ & 0377;
  516. }
  517.  
  518. int argument_macro_input::peek()
  519. {
  520.   if (ap) {
  521.     if (*ap != '\0')
  522.       return *ap & 0377;
  523.     ap = 0;
  524.   }
  525.   if (p == 0)
  526.     return EOF;
  527.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  528.     int i = *p++ - ARG1;
  529.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  530.       ap = argv[i];
  531.       return *ap & 0377;
  532.     }
  533.   }
  534.   if (*p == '\0')
  535.     return EOF;
  536.   return *p & 0377;
  537. }
  538.  
  539. static input *current_input = 0;
  540.  
  541. /* we insert a newline between input from different levels */
  542.  
  543. int get_char()
  544. {
  545.   if (current_input == 0)
  546.     return EOF;
  547.   else {
  548.     int c = current_input->get();
  549.     if (c != EOF)
  550.       return c;
  551.     else {
  552.       input *tem = current_input;
  553.       current_input = current_input->next;
  554.       delete tem;
  555.       return '\n';
  556.     }
  557.   }
  558. }
  559.  
  560. int peek_char()
  561. {
  562.   if (current_input == 0)
  563.     return EOF;
  564.   else {
  565.     int c = current_input->peek();
  566.     if (c != EOF)
  567.       return c;
  568.     else
  569.       return '\n';
  570.   }
  571. }
  572.  
  573. int get_location(char **fnp, int *lnp)
  574. {
  575.   for (input *p = current_input; p; p = p->next)
  576.     if (p->get_location(fnp, lnp))
  577.       return 1;
  578.   return 0;
  579. }
  580.  
  581. string token_buffer;
  582. const int NCONTEXT = 4;
  583. string context_ring[NCONTEXT];
  584. int context_index = 0;
  585.  
  586. void flush_context()
  587. {
  588.   for (int i = 0; i < NCONTEXT; i++)
  589.     context_ring[i] = "";
  590.   context_index = 0;
  591. }
  592.  
  593. void show_context()
  594. {
  595.   int i = context_index;
  596.   fputs(" context is\n\t", stderr);
  597.   for (;;) {
  598.     int j = (i + 1) % NCONTEXT;
  599.     if (j == context_index) {
  600.       fputs(">>> ", stderr);
  601.       put_string(context_ring[i], stderr);
  602.       fputs(" <<<", stderr);
  603.       break;
  604.     }
  605.     else if (context_ring[i].length() > 0) {
  606.       put_string(context_ring[i], stderr);
  607.       putc(' ', stderr);
  608.     }
  609.     i = j;
  610.   }
  611.   putc('\n', stderr);
  612. }
  613.  
  614. void add_context(const string &s)
  615. {
  616.   context_ring[context_index] = s;
  617.   context_index = (context_index + 1) % NCONTEXT;
  618. }
  619.  
  620. void add_context(char c)
  621. {
  622.   context_ring[context_index] = c;
  623.   context_index = (context_index + 1) % NCONTEXT;
  624. }
  625.  
  626. void add_quoted_context(const string &s)
  627. {
  628.   string &r = context_ring[context_index];
  629.   r = '"';
  630.   for (int i = 0; i < s.length(); i++)
  631.     if (s[i] == '"')
  632.       r += "\\\"";
  633.     else
  634.       r += s[i];
  635.   r += '"';
  636.   context_index = (context_index + 1) % NCONTEXT;
  637. }
  638.  
  639. void init_lex(const char *str, const char *filename, int lineno)
  640. {
  641.  while (current_input != 0) {
  642.     input *tem = current_input;
  643.     current_input = current_input->next;
  644.     delete tem;
  645.   }
  646.   current_input = new top_input(str, filename, lineno, 0);
  647.   flush_context();
  648. }
  649.  
  650.  
  651. void get_delimited_text()
  652. {
  653.   char *filename;
  654.   int lineno;
  655.   int got_location = get_location(&filename, &lineno);
  656.   int start = get_char();
  657.   while (start == ' ' || start == '\t' || start == '\n')
  658.     start = get_char();
  659.   token_buffer.clear();
  660.   if (start == EOF) {
  661.     if (got_location)
  662.       error_with_file_and_line(filename, lineno,
  663.                    "end of input while defining macro");
  664.     else
  665.       error("end of input while defining macro");
  666.     return;
  667.   }
  668.   for (;;) {
  669.     int c = get_char();
  670.     if (c == EOF) {
  671.       if (got_location)
  672.     error_with_file_and_line(filename, lineno,
  673.                  "end of input while defining macro");
  674.       else
  675.     error("end of input while defining macro");
  676.       add_context(start + token_buffer);
  677.       return;
  678.     }
  679.     if (c == start)
  680.       break;
  681.     token_buffer += char(c);
  682.   }
  683.   add_context(start + token_buffer + start);
  684. }
  685.  
  686. void interpolate_macro_with_args(const char *body)
  687. {
  688.   char *argv[9];
  689.   int argc = 0;
  690.   for (int i = 0; i < 9; i++)
  691.     argv[i] = 0;
  692.   int level = 0;
  693.   int c;
  694.   do {
  695.     token_buffer.clear();
  696.     for (;;) {
  697.       c = get_char();
  698.       if (c == EOF) {
  699.     lex_error("end of input while scanning macro arguments");
  700.     break;
  701.       }
  702.       if (level == 0 && (c == ',' || c == ')')) {
  703.     if (token_buffer.length() > 0) {
  704.       token_buffer +=  '\0';
  705.       argv[argc] = strsave(token_buffer.contents());
  706.     }
  707.     // for `foo()', argc = 0
  708.     if (argc > 0 || c != ')' || i > 0)
  709.       argc++;
  710.     break;
  711.       }
  712.       token_buffer += char(c);
  713.       if (c == '(')
  714.     level++;
  715.       else if (c == ')')
  716.     level--;
  717.     }
  718.   } while (c != ')' && c != EOF);
  719.   current_input = new argument_macro_input(body, argc, argv, current_input);
  720. }
  721.  
  722. /* If lookup flag is non-zero the token will be looked up to see
  723. if it is macro. If it's 1, it will looked up to see if it's a token.
  724. */
  725.  
  726. int get_token(int lookup_flag = 0)
  727. {
  728.   for (;;) {
  729.     int c = get_char();
  730.     while (c == ' ' || c == '\n')
  731.       c = get_char();
  732.     switch (c) {
  733.     case EOF:
  734.       add_context("end of input");
  735.       return 0;
  736.     case '"':
  737.       {
  738.     int quoted = 0;
  739.     token_buffer.clear();
  740.     for (;;) {
  741.       c = get_char();
  742.       if (c == EOF) {
  743.         lex_error("missing \"");
  744.         break;
  745.       }
  746.       else if (c == '\n') {
  747.         lex_error("newline before end of quoted text");
  748.         break;
  749.       }
  750.       else if (c == '"') {
  751.         if (!quoted)
  752.           break;
  753.         token_buffer[token_buffer.length() - 1] = '"';
  754.         quoted = 0;
  755.       }
  756.       else {
  757.         token_buffer += c;
  758.         quoted = quoted ? 0 : c == '\\';
  759.       }
  760.     }
  761.       }
  762.       add_quoted_context(token_buffer);
  763.       return QUOTED_TEXT;
  764.     case '{':
  765.     case '}':
  766.     case '^':
  767.     case '~':
  768.     case '\t':
  769.       add_context(c);
  770.       return c;
  771.     default:
  772.       {
  773.     int break_flag = 0;
  774.     int quoted = 0;
  775.     token_buffer.clear();
  776.     if (c == '\\')
  777.       quoted = 1;
  778.     else
  779.       token_buffer += c;
  780.     int done = 0;
  781.     while (!done) {
  782.       c = peek_char();
  783.       if (!quoted && lookup_flag != 0 && c == '(') {
  784.         token_buffer += '\0';
  785.         definition *def = macro_table.lookup(token_buffer.contents());
  786.         if (def && def->is_macro && !def->is_simple) {
  787.           (void)get_char();    // skip initial '('
  788.           interpolate_macro_with_args(def->contents);
  789.           break_flag = 1;
  790.           break;
  791.         }
  792.         token_buffer.set_length(token_buffer.length() - 1);
  793.       }
  794.       if (quoted) {
  795.         quoted = 0;
  796.         switch (c) {
  797.         case EOF:
  798.           lex_error("`\\' ignored at end of equation");
  799.           done = 1;
  800.           break;
  801.         case '\n':
  802.           lex_error("`\\' ignored because followed by newline");
  803.           done = 1;
  804.           break;
  805.         case '\t':
  806.           lex_error("`\\' ignored because followed by tab");
  807.           done = 1;
  808.           break;
  809.         case '"':
  810.           (void)get_char();
  811.           token_buffer += '"';
  812.           break;
  813.         default:
  814.           (void)get_char();
  815.           token_buffer += '\\';
  816.           token_buffer += c;
  817.           break;
  818.         }
  819.       }
  820.       else {
  821.         switch (c) {
  822.         case EOF:
  823.         case '{':
  824.         case '}':
  825.         case '^':
  826.         case '~':
  827.         case '"':
  828.         case ' ':
  829.         case '\t':
  830.         case '\n':
  831.           done = 1;
  832.           break;
  833.         case '\\':
  834.           (void)get_char();
  835.           quoted = 1;
  836.           break;
  837.         default:
  838.           (void)get_char();
  839.           token_buffer += char(c);
  840.           break;
  841.         }
  842.       }
  843.     }
  844.     if (break_flag || token_buffer.length() == 0)
  845.       break;
  846.     if (lookup_flag != 0) {
  847.       token_buffer += '\0';
  848.       definition *def = macro_table.lookup(token_buffer.contents());
  849.       token_buffer.set_length(token_buffer.length() - 1);
  850.       if (def) {
  851.         if (def->is_macro) {
  852.           current_input = new macro_input(def->contents, current_input);
  853.           break;
  854.         }
  855.         else if (lookup_flag == 1) {
  856.           add_context(token_buffer);
  857.           return def->tok;
  858.         }
  859.       }
  860.     }
  861.     add_context(token_buffer);
  862.     return TEXT;
  863.       }
  864.     }
  865.   }
  866. }
  867.  
  868. void do_include()
  869. {
  870.   int t = get_token(2);
  871.   if (t != TEXT && t != QUOTED_TEXT) {
  872.     lex_error("bad filename for include");
  873.     return;
  874.   }
  875.   token_buffer += '\0';
  876.   const char *filename = token_buffer.contents();
  877.   errno = 0;
  878.   FILE *fp = fopen(filename, "r");
  879.   if (fp == 0) {
  880.     lex_error("can't open included file `%1'", filename);
  881.     return;
  882.   }
  883.   current_input = new file_input(fp, filename, current_input);
  884. }
  885.  
  886. void ignore_definition()
  887. {
  888.   int t = get_token();
  889.   if (t != TEXT) {
  890.     lex_error("bad definition");
  891.     return;
  892.   }
  893.   get_delimited_text();
  894. }
  895.  
  896. void do_definition(int is_simple)
  897. {
  898.   int t = get_token();
  899.   if (t != TEXT) {
  900.     lex_error("bad definition");
  901.     return;
  902.   }
  903.   token_buffer += '\0';
  904.   const char *name = token_buffer.contents();
  905.   definition *def = macro_table.lookup(name);
  906.   if (def == 0) {
  907.     def = new definition;
  908.     macro_table.define(name, def);
  909.   }
  910.   else if (def->is_macro) {
  911.     a_delete def->contents;
  912.   }
  913.   get_delimited_text();
  914.   token_buffer += '\0';
  915.   def->is_macro = 1;
  916.   def->contents = strsave(token_buffer.contents());
  917.   def->is_simple = is_simple;
  918. }
  919.  
  920. void do_undef()
  921. {
  922.   int t = get_token();
  923.   if (t != TEXT) {
  924.     lex_error("bad undef command");
  925.     return;
  926.   }
  927.   token_buffer += '\0';
  928.   macro_table.define(token_buffer.contents(), 0);
  929. }
  930.  
  931. void do_gsize()
  932. {
  933.   int t = get_token(2);
  934.   if (t != TEXT && t != QUOTED_TEXT) {
  935.     lex_error("bad argument to gsize command");
  936.     return;
  937.   }
  938.   token_buffer += '\0';
  939.   if (!set_gsize(token_buffer.contents()))
  940.     lex_error("invalid size `%1'", token_buffer.contents());
  941. }
  942.  
  943. void do_gfont()
  944. {
  945.   int t = get_token(2);
  946.   if (t != TEXT && t != QUOTED_TEXT) {
  947.     lex_error("bad argument to gfont command");
  948.     return;
  949.   }
  950.   token_buffer += '\0';
  951.   set_gfont(token_buffer.contents());
  952. }
  953.  
  954. void do_grfont()
  955. {
  956.   int t = get_token(2);
  957.   if (t != TEXT && t != QUOTED_TEXT) {
  958.     lex_error("bad argument to grfont command");
  959.     return;
  960.   }
  961.   token_buffer += '\0';
  962.   set_grfont(token_buffer.contents());
  963. }
  964.  
  965. void do_gbfont()
  966. {
  967.   int t = get_token(2);
  968.   if (t != TEXT && t != QUOTED_TEXT) {
  969.     lex_error("bad argument to gbfont command");
  970.     return;
  971.   }
  972.   token_buffer += '\0';
  973.   set_gbfont(token_buffer.contents());
  974. }
  975.  
  976. void do_space()
  977. {
  978.   int t = get_token(2);
  979.   if (t != TEXT && t != QUOTED_TEXT) {
  980.     lex_error("bad argument to space command");
  981.     return;
  982.   }
  983.   token_buffer += '\0';
  984.   char *ptr;
  985.   long n = strtol(token_buffer.contents(), &ptr, 10);
  986.   if (n == 0 && ptr == token_buffer.contents())
  987.     lex_error("bad argument `%1' to space command");
  988.   else
  989.     set_space(int(n));
  990. }
  991.  
  992. void do_ifdef()
  993. {
  994.   int t = get_token();
  995.   if (t != TEXT) {
  996.     lex_error("bad ifdef");
  997.     return;
  998.   }
  999.   token_buffer += '\0';
  1000.   definition *def = macro_table.lookup(token_buffer.contents());
  1001.   int result = def && def->is_macro && !def->is_simple;
  1002.   get_delimited_text();
  1003.   if (result) {
  1004.     token_buffer += '\0';
  1005.     current_input = new macro_input(token_buffer.contents(), current_input);
  1006.   }
  1007. }
  1008.  
  1009. void do_delim()
  1010. {
  1011.   int c = get_char();
  1012.   while (c == ' ' || c == '\n')
  1013.     c = get_char();
  1014.   int d;
  1015.   if (c == EOF || (d = get_char()) == EOF)
  1016.     lex_error("end of file while reading argument to `delim'");
  1017.   else {
  1018.     if (c == 'o' && d == 'f' && peek_char() == 'f') {
  1019.       (void)get_char();
  1020.       start_delim = end_delim = '\0';
  1021.     }
  1022.     else {
  1023.       start_delim = c;
  1024.       end_delim = d;
  1025.     }
  1026.   }
  1027. }
  1028.  
  1029. void do_chartype()
  1030. {
  1031.   int t = get_token(2);
  1032.   if (t != TEXT && t != QUOTED_TEXT) {
  1033.     lex_error("bad chartype");
  1034.     return;
  1035.   }
  1036.   token_buffer += '\0';
  1037.   string type = token_buffer;
  1038.   t = get_token();
  1039.   if (t != TEXT && t != QUOTED_TEXT) {
  1040.     lex_error("bad chartype");
  1041.     return;
  1042.   }
  1043.   token_buffer += '\0';
  1044.   set_char_type(type.contents(), strsave(token_buffer.contents()));
  1045. }
  1046.  
  1047. void do_set()
  1048. {
  1049.   int t = get_token(2);
  1050.   if (t != TEXT && t != QUOTED_TEXT) {
  1051.     lex_error("bad set");
  1052.     return;
  1053.   }
  1054.   token_buffer += '\0';
  1055.   string param = token_buffer;
  1056.   t = get_token();
  1057.   if (t != TEXT && t != QUOTED_TEXT) {
  1058.     lex_error("bad set");
  1059.     return;
  1060.   }
  1061.   token_buffer += '\0';
  1062.   int n;
  1063.   if (sscanf(&token_buffer[0], "%d", &n) != 1) {
  1064.     lex_error("bad number `%1'", token_buffer.contents());
  1065.     return;
  1066.   }
  1067.   set_param(param.contents(), n);
  1068. }
  1069.  
  1070. int yylex()
  1071. {
  1072.   for (;;) {
  1073.     int tk = get_token(1);
  1074.     switch(tk) {
  1075.     case UNDEF:
  1076.       do_undef();
  1077.       break;
  1078.     case SDEFINE:
  1079.       do_definition(1);
  1080.       break;
  1081.     case DEFINE:
  1082.       do_definition(0);
  1083.       break;
  1084.     case TDEFINE:
  1085.       if (!nroff)
  1086.     do_definition(0);
  1087.       else
  1088.     ignore_definition();
  1089.       break;
  1090.     case NDEFINE:
  1091.       if (nroff)
  1092.     do_definition(0);
  1093.       else
  1094.     ignore_definition();
  1095.       break;
  1096.     case GSIZE:
  1097.       do_gsize();
  1098.       break;
  1099.     case GFONT:
  1100.       do_gfont();
  1101.       break;
  1102.     case GRFONT:
  1103.       do_grfont();
  1104.       break;
  1105.     case GBFONT:
  1106.       do_gbfont();
  1107.       break;
  1108.     case SPACE:
  1109.       do_space();
  1110.       break;
  1111.     case INCLUDE:
  1112.       do_include();
  1113.       break;
  1114.     case IFDEF:
  1115.       do_ifdef();
  1116.       break;
  1117.     case DELIM:
  1118.       do_delim();
  1119.       break;
  1120.     case CHARTYPE:
  1121.       do_chartype();
  1122.       break;
  1123.     case SET:
  1124.       do_set();
  1125.       break;
  1126.     case QUOTED_TEXT:
  1127.     case TEXT:
  1128.       token_buffer += '\0';
  1129.       yylval.str = strsave(token_buffer.contents());
  1130.       // fall through
  1131.     default:
  1132.       return tk;
  1133.     }
  1134.   }
  1135. }
  1136.  
  1137. void lex_error(const char *message,
  1138.            const errarg &arg1,
  1139.            const errarg &arg2,
  1140.            const errarg &arg3)
  1141. {
  1142.   char *filename;
  1143.   int lineno;
  1144.   if (!get_location(&filename, &lineno))
  1145.     error(message, arg1, arg2, arg3);
  1146.   else
  1147.     error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1148. }
  1149.  
  1150. void yyerror(const char *s)
  1151. {
  1152.   char *filename;
  1153.   int lineno;
  1154.   if (!get_location(&filename, &lineno))
  1155.     error(s);
  1156.   else
  1157.     error_with_file_and_line(filename, lineno, s);
  1158.   show_context();
  1159. }
  1160.  
  1161.