home *** CD-ROM | disk | FTP | other *** search
/ Aminet 10 / aminetcdnumber101996.iso / Aminet / util / gnu / groff_src.lha / groff-1.10src / eqn / lex.cc < prev    next >
C/C++ Source or Header  |  1995-06-22  |  25KB  |  1,166 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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.   int i;
  255.   for (i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) {
  256.     definition *def = new definition;
  257.     def->is_macro = 0;
  258.     def->tok = token_table[i].token;
  259.     macro_table.define(token_table[i].name, def);
  260.   }
  261.   for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) {
  262.     definition *def = new definition;
  263.     def->is_macro = 1;
  264.     def->contents = strsave(def_table[i].def);
  265.     def->is_simple = 1;
  266.     macro_table.define(def_table[i].name, def);
  267.   }
  268.   definition *def = new definition;
  269.   def->is_macro = 1;
  270.   def->contents = strsave("1");
  271.   macro_table.define(device, def);
  272. }
  273.  
  274. class input {
  275.   input *next;
  276. public:
  277.   input(input *p);
  278.   virtual ~input();
  279.   virtual int get() = 0;
  280.   virtual int peek() = 0;
  281.   virtual int get_location(char **, int *);
  282.  
  283.   friend int get_char();
  284.   friend int peek_char();
  285.   friend int get_location(char **, int *);
  286.   friend void init_lex(const char *str, const char *filename, int lineno);
  287. };
  288.  
  289. class file_input : public input {
  290.   FILE *fp;
  291.   char *filename;
  292.   int lineno;
  293.   string line;
  294.   const char *ptr;
  295.   int read_line();
  296. public:
  297.   file_input(FILE *, const char *, input *);
  298.   ~file_input();
  299.   int get();
  300.   int peek();
  301.   int get_location(char **, int *);
  302. };
  303.  
  304.  
  305. class macro_input : public input {
  306.   char *s;
  307.   char *p;
  308. public:
  309.   macro_input(const char *, input *);
  310.   ~macro_input();
  311.   int get();
  312.   int peek();
  313. };
  314.  
  315. class top_input : public macro_input {
  316.   char *filename;
  317.   int lineno;
  318.  public:
  319.   top_input(const char *, const char *, int, input *);
  320.   ~top_input();
  321.   int get();
  322.   int get_location(char **, int *);
  323. };
  324.  
  325. class argument_macro_input: public input {
  326.   char *s;
  327.   char *p;
  328.   char *ap;
  329.   int argc;
  330.   char *argv[9];
  331. public:
  332.   argument_macro_input(const char *, int, char **, input *);
  333.   ~argument_macro_input();
  334.   int get();
  335.   int peek();
  336. };
  337.  
  338. input::input(input *x) : next(x)
  339. {
  340. }
  341.  
  342. input::~input()
  343. {
  344. }
  345.  
  346. int input::get_location(char **, int *)
  347. {
  348.   return 0;
  349. }
  350.  
  351. file_input::file_input(FILE *f, const char *fn, input *p)
  352. : input(p), lineno(0), ptr("")
  353. {
  354.   fp = f;
  355.   filename = strsave(fn);
  356. }
  357.  
  358. file_input::~file_input()
  359. {
  360.   a_delete filename;
  361.   fclose(fp);
  362. }
  363.  
  364. int file_input::read_line()
  365. {
  366.   for (;;) {
  367.     line.clear();
  368.     lineno++;
  369.     for (;;) {
  370.       int c = getc(fp);
  371.       if (c == EOF)
  372.     break;
  373.       else if (illegal_input_char(c))
  374.     lex_error("illegal input character code %1", c);
  375.       else {
  376.     line += char(c);
  377.     if (c == '\n') 
  378.       break;
  379.       }
  380.     }
  381.     if (line.length() == 0)
  382.       return 0;
  383.     if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E'
  384.       && (line[2] == 'Q' || line[2] == 'N')
  385.       && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
  386.           || compatible_flag))) {
  387.       line += '\0';
  388.       ptr = line.contents();
  389.       return 1;
  390.     }
  391.   }
  392. }
  393.  
  394. int file_input::get()
  395. {
  396.   if (*ptr != '\0' || read_line())
  397.     return *ptr++ & 0377;
  398.   else
  399.     return EOF;
  400. }
  401.  
  402. int file_input::peek()
  403. {
  404.   if (*ptr != '\0' || read_line())
  405.     return *ptr;
  406.   else
  407.     return EOF;
  408. }
  409.  
  410. int file_input::get_location(char **fnp, int *lnp)
  411. {
  412.   *fnp = filename;
  413.   *lnp = lineno;
  414.   return 1;
  415. }
  416.  
  417. macro_input::macro_input(const char *str, input *x) : input(x)
  418. {
  419.   p = s = strsave(str);
  420. }
  421.  
  422. macro_input::~macro_input()
  423. {
  424.   a_delete s;
  425. }
  426.  
  427. int macro_input::get()
  428. {
  429.   if (p == 0 || *p == '\0')
  430.     return EOF;
  431.   else
  432.     return *p++ & 0377;
  433. }
  434.  
  435. int macro_input::peek()
  436. {
  437.   if (p == 0 || *p == '\0')
  438.     return EOF;
  439.   else
  440.     return *p & 0377;
  441. }
  442.  
  443. top_input::top_input(const char *str, const char *fn, int ln, input *x)
  444. : macro_input(str, x), lineno(ln)
  445. {
  446.   filename = strsave(fn);
  447. }
  448.  
  449. top_input::~top_input()
  450. {
  451.   a_delete filename;
  452. }
  453.  
  454. int top_input::get()
  455. {
  456.   int c = macro_input::get();
  457.   if (c == '\n')
  458.     lineno++;
  459.   return c;
  460. }
  461.  
  462. int top_input::get_location(char **fnp, int *lnp)
  463. {
  464.   *fnp = filename;
  465.   *lnp = lineno;
  466.   return 1;
  467. }
  468.  
  469. // Character representing $1.  Must be illegal input character.
  470. #define ARG1 14
  471.  
  472. argument_macro_input::argument_macro_input(const char *body, int ac, 
  473.                        char **av, input *x)
  474. : input(x), argc(ac), ap(0)
  475. {
  476.   int i;
  477.   for (i = 0; i < argc; i++)
  478.     argv[i] = av[i];
  479.   p = s = strsave(body);
  480.   int j = 0;
  481.   for (i = 0; s[i] != '\0'; i++)
  482.     if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
  483.       if (s[i+1] != '0')
  484.     s[j++] = ARG1 + s[++i] - '1';
  485.     }
  486.     else
  487.       s[j++] = s[i];
  488.   s[j] = '\0';
  489. }
  490.  
  491.  
  492. argument_macro_input::~argument_macro_input()
  493. {
  494.   for (int i = 0; i < argc; i++)
  495.     a_delete argv[i];
  496.   a_delete s;
  497. }
  498.  
  499. int argument_macro_input::get()
  500. {
  501.   if (ap) {
  502.     if (*ap != '\0')
  503.       return *ap++ & 0377;
  504.     ap = 0;
  505.   }
  506.   if (p == 0)
  507.     return EOF;
  508.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  509.     int i = *p++ - ARG1;
  510.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  511.       ap = argv[i];
  512.       return *ap++ & 0377;
  513.     }
  514.   }
  515.   if (*p == '\0')
  516.     return EOF;
  517.   return *p++ & 0377;
  518. }
  519.  
  520. int argument_macro_input::peek()
  521. {
  522.   if (ap) {
  523.     if (*ap != '\0')
  524.       return *ap & 0377;
  525.     ap = 0;
  526.   }
  527.   if (p == 0)
  528.     return EOF;
  529.   while (*p >= ARG1 && *p <= ARG1 + 8) {
  530.     int i = *p++ - ARG1;
  531.     if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
  532.       ap = argv[i];
  533.       return *ap & 0377;
  534.     }
  535.   }
  536.   if (*p == '\0')
  537.     return EOF;
  538.   return *p & 0377;
  539. }
  540.  
  541. static input *current_input = 0;
  542.  
  543. /* we insert a newline between input from different levels */
  544.  
  545. int get_char()
  546. {
  547.   if (current_input == 0)
  548.     return EOF;
  549.   else {
  550.     int c = current_input->get();
  551.     if (c != EOF)
  552.       return c;
  553.     else {
  554.       input *tem = current_input;
  555.       current_input = current_input->next;
  556.       delete tem;
  557.       return '\n';
  558.     }
  559.   }
  560. }
  561.  
  562. int peek_char()
  563. {
  564.   if (current_input == 0)
  565.     return EOF;
  566.   else {
  567.     int c = current_input->peek();
  568.     if (c != EOF)
  569.       return c;
  570.     else
  571.       return '\n';
  572.   }
  573. }
  574.  
  575. int get_location(char **fnp, int *lnp)
  576. {
  577.   for (input *p = current_input; p; p = p->next)
  578.     if (p->get_location(fnp, lnp))
  579.       return 1;
  580.   return 0;
  581. }
  582.  
  583. string token_buffer;
  584. const int NCONTEXT = 4;
  585. string context_ring[NCONTEXT];
  586. int context_index = 0;
  587.  
  588. void flush_context()
  589. {
  590.   for (int i = 0; i < NCONTEXT; i++)
  591.     context_ring[i] = "";
  592.   context_index = 0;
  593. }
  594.  
  595. void show_context()
  596. {
  597.   int i = context_index;
  598.   fputs(" context is\n\t", stderr);
  599.   for (;;) {
  600.     int j = (i + 1) % NCONTEXT;
  601.     if (j == context_index) {
  602.       fputs(">>> ", stderr);
  603.       put_string(context_ring[i], stderr);
  604.       fputs(" <<<", stderr);
  605.       break;
  606.     }
  607.     else if (context_ring[i].length() > 0) {
  608.       put_string(context_ring[i], stderr);
  609.       putc(' ', stderr);
  610.     }
  611.     i = j;
  612.   }
  613.   putc('\n', stderr);
  614. }
  615.  
  616. void add_context(const string &s)
  617. {
  618.   context_ring[context_index] = s;
  619.   context_index = (context_index + 1) % NCONTEXT;
  620. }
  621.  
  622. void add_context(char c)
  623. {
  624.   context_ring[context_index] = c;
  625.   context_index = (context_index + 1) % NCONTEXT;
  626. }
  627.  
  628. void add_quoted_context(const string &s)
  629. {
  630.   string &r = context_ring[context_index];
  631.   r = '"';
  632.   for (int i = 0; i < s.length(); i++)
  633.     if (s[i] == '"')
  634.       r += "\\\"";
  635.     else
  636.       r += s[i];
  637.   r += '"';
  638.   context_index = (context_index + 1) % NCONTEXT;
  639. }
  640.  
  641. void init_lex(const char *str, const char *filename, int lineno)
  642. {
  643.  while (current_input != 0) {
  644.     input *tem = current_input;
  645.     current_input = current_input->next;
  646.     delete tem;
  647.   }
  648.   current_input = new top_input(str, filename, lineno, 0);
  649.   flush_context();
  650. }
  651.  
  652.  
  653. void get_delimited_text()
  654. {
  655.   char *filename;
  656.   int lineno;
  657.   int got_location = get_location(&filename, &lineno);
  658.   int start = get_char();
  659.   while (start == ' ' || start == '\t' || start == '\n')
  660.     start = get_char();
  661.   token_buffer.clear();
  662.   if (start == EOF) {
  663.     if (got_location)
  664.       error_with_file_and_line(filename, lineno,
  665.                    "end of input while defining macro");
  666.     else
  667.       error("end of input while defining macro");
  668.     return;
  669.   }
  670.   for (;;) {
  671.     int c = get_char();
  672.     if (c == EOF) {
  673.       if (got_location)
  674.     error_with_file_and_line(filename, lineno,
  675.                  "end of input while defining macro");
  676.       else
  677.     error("end of input while defining macro");
  678.       add_context(start + token_buffer);
  679.       return;
  680.     }
  681.     if (c == start)
  682.       break;
  683.     token_buffer += char(c);
  684.   }
  685.   add_context(start + token_buffer + start);
  686. }
  687.  
  688. void interpolate_macro_with_args(const char *body)
  689. {
  690.   char *argv[9];
  691.   int argc = 0;
  692.   int i;
  693.   for (i = 0; i < 9; i++)
  694.     argv[i] = 0;
  695.   int level = 0;
  696.   int c;
  697.   do {
  698.     token_buffer.clear();
  699.     for (;;) {
  700.       c = get_char();
  701.       if (c == EOF) {
  702.     lex_error("end of input while scanning macro arguments");
  703.     break;
  704.       }
  705.       if (level == 0 && (c == ',' || c == ')')) {
  706.     if (token_buffer.length() > 0) {
  707.       token_buffer +=  '\0';
  708.       argv[argc] = strsave(token_buffer.contents());
  709.     }
  710.     // for `foo()', argc = 0
  711.     if (argc > 0 || c != ')' || i > 0)
  712.       argc++;
  713.     break;
  714.       }
  715.       token_buffer += char(c);
  716.       if (c == '(')
  717.     level++;
  718.       else if (c == ')')
  719.     level--;
  720.     }
  721.   } while (c != ')' && c != EOF);
  722.   current_input = new argument_macro_input(body, argc, argv, current_input);
  723. }
  724.  
  725. /* If lookup flag is non-zero the token will be looked up to see
  726. if it is macro. If it's 1, it will looked up to see if it's a token.
  727. */
  728.  
  729. int get_token(int lookup_flag = 0)
  730. {
  731.   for (;;) {
  732.     int c = get_char();
  733.     while (c == ' ' || c == '\n')
  734.       c = get_char();
  735.     switch (c) {
  736.     case EOF:
  737.       {
  738.     add_context("end of input");
  739.       }
  740.       return 0;
  741.     case '"':
  742.       {
  743.     int quoted = 0;
  744.     token_buffer.clear();
  745.     for (;;) {
  746.       c = get_char();
  747.       if (c == EOF) {
  748.         lex_error("missing \"");
  749.         break;
  750.       }
  751.       else if (c == '\n') {
  752.         lex_error("newline before end of quoted text");
  753.         break;
  754.       }
  755.       else if (c == '"') {
  756.         if (!quoted)
  757.           break;
  758.         token_buffer[token_buffer.length() - 1] = '"';
  759.         quoted = 0;
  760.       }
  761.       else {
  762.         token_buffer += c;
  763.         quoted = quoted ? 0 : c == '\\';
  764.       }
  765.     }
  766.       }
  767.       add_quoted_context(token_buffer);
  768.       return QUOTED_TEXT;
  769.     case '{':
  770.     case '}':
  771.     case '^':
  772.     case '~':
  773.     case '\t':
  774.       add_context(c);
  775.       return c;
  776.     default:
  777.       {
  778.     int break_flag = 0;
  779.     int quoted = 0;
  780.     token_buffer.clear();
  781.     if (c == '\\')
  782.       quoted = 1;
  783.     else
  784.       token_buffer += c;
  785.     int done = 0;
  786.     while (!done) {
  787.       c = peek_char();
  788.       if (!quoted && lookup_flag != 0 && c == '(') {
  789.         token_buffer += '\0';
  790.         definition *def = macro_table.lookup(token_buffer.contents());
  791.         if (def && def->is_macro && !def->is_simple) {
  792.           (void)get_char();    // skip initial '('
  793.           interpolate_macro_with_args(def->contents);
  794.           break_flag = 1;
  795.           break;
  796.         }
  797.         token_buffer.set_length(token_buffer.length() - 1);
  798.       }
  799.       if (quoted) {
  800.         quoted = 0;
  801.         switch (c) {
  802.         case EOF:
  803.           lex_error("`\\' ignored at end of equation");
  804.           done = 1;
  805.           break;
  806.         case '\n':
  807.           lex_error("`\\' ignored because followed by newline");
  808.           done = 1;
  809.           break;
  810.         case '\t':
  811.           lex_error("`\\' ignored because followed by tab");
  812.           done = 1;
  813.           break;
  814.         case '"':
  815.           (void)get_char();
  816.           token_buffer += '"';
  817.           break;
  818.         default:
  819.           (void)get_char();
  820.           token_buffer += '\\';
  821.           token_buffer += c;
  822.           break;
  823.         }
  824.       }
  825.       else {
  826.         switch (c) {
  827.         case EOF:
  828.         case '{':
  829.         case '}':
  830.         case '^':
  831.         case '~':
  832.         case '"':
  833.         case ' ':
  834.         case '\t':
  835.         case '\n':
  836.           done = 1;
  837.           break;
  838.         case '\\':
  839.           (void)get_char();
  840.           quoted = 1;
  841.           break;
  842.         default:
  843.           (void)get_char();
  844.           token_buffer += char(c);
  845.           break;
  846.         }
  847.       }
  848.     }
  849.     if (break_flag || token_buffer.length() == 0)
  850.       break;
  851.     if (lookup_flag != 0) {
  852.       token_buffer += '\0';
  853.       definition *def = macro_table.lookup(token_buffer.contents());
  854.       token_buffer.set_length(token_buffer.length() - 1);
  855.       if (def) {
  856.         if (def->is_macro) {
  857.           current_input = new macro_input(def->contents, current_input);
  858.           break;
  859.         }
  860.         else if (lookup_flag == 1) {
  861.           add_context(token_buffer);
  862.           return def->tok;
  863.         }
  864.       }
  865.     }
  866.     add_context(token_buffer);
  867.     return TEXT;
  868.       }
  869.     }
  870.   }
  871. }
  872.  
  873. void do_include()
  874. {
  875.   int t = get_token(2);
  876.   if (t != TEXT && t != QUOTED_TEXT) {
  877.     lex_error("bad filename for include");
  878.     return;
  879.   }
  880.   token_buffer += '\0';
  881.   const char *filename = token_buffer.contents();
  882.   errno = 0;
  883.   FILE *fp = fopen(filename, "r");
  884.   if (fp == 0) {
  885.     lex_error("can't open included file `%1'", filename);
  886.     return;
  887.   }
  888.   current_input = new file_input(fp, filename, current_input);
  889. }
  890.  
  891. void ignore_definition()
  892. {
  893.   int t = get_token();
  894.   if (t != TEXT) {
  895.     lex_error("bad definition");
  896.     return;
  897.   }
  898.   get_delimited_text();
  899. }
  900.  
  901. void do_definition(int is_simple)
  902. {
  903.   int t = get_token();
  904.   if (t != TEXT) {
  905.     lex_error("bad definition");
  906.     return;
  907.   }
  908.   token_buffer += '\0';
  909.   const char *name = token_buffer.contents();
  910.   definition *def = macro_table.lookup(name);
  911.   if (def == 0) {
  912.     def = new definition;
  913.     macro_table.define(name, def);
  914.   }
  915.   else if (def->is_macro) {
  916.     a_delete def->contents;
  917.   }
  918.   get_delimited_text();
  919.   token_buffer += '\0';
  920.   def->is_macro = 1;
  921.   def->contents = strsave(token_buffer.contents());
  922.   def->is_simple = is_simple;
  923. }
  924.  
  925. void do_undef()
  926. {
  927.   int t = get_token();
  928.   if (t != TEXT) {
  929.     lex_error("bad undef command");
  930.     return;
  931.   }
  932.   token_buffer += '\0';
  933.   macro_table.define(token_buffer.contents(), 0);
  934. }
  935.  
  936. void do_gsize()
  937. {
  938.   int t = get_token(2);
  939.   if (t != TEXT && t != QUOTED_TEXT) {
  940.     lex_error("bad argument to gsize command");
  941.     return;
  942.   }
  943.   token_buffer += '\0';
  944.   if (!set_gsize(token_buffer.contents()))
  945.     lex_error("invalid size `%1'", token_buffer.contents());
  946. }
  947.  
  948. void do_gfont()
  949. {
  950.   int t = get_token(2);
  951.   if (t != TEXT && t != QUOTED_TEXT) {
  952.     lex_error("bad argument to gfont command");
  953.     return;
  954.   }
  955.   token_buffer += '\0';
  956.   set_gfont(token_buffer.contents());
  957. }
  958.  
  959. void do_grfont()
  960. {
  961.   int t = get_token(2);
  962.   if (t != TEXT && t != QUOTED_TEXT) {
  963.     lex_error("bad argument to grfont command");
  964.     return;
  965.   }
  966.   token_buffer += '\0';
  967.   set_grfont(token_buffer.contents());
  968. }
  969.  
  970. void do_gbfont()
  971. {
  972.   int t = get_token(2);
  973.   if (t != TEXT && t != QUOTED_TEXT) {
  974.     lex_error("bad argument to gbfont command");
  975.     return;
  976.   }
  977.   token_buffer += '\0';
  978.   set_gbfont(token_buffer.contents());
  979. }
  980.  
  981. void do_space()
  982. {
  983.   int t = get_token(2);
  984.   if (t != TEXT && t != QUOTED_TEXT) {
  985.     lex_error("bad argument to space command");
  986.     return;
  987.   }
  988.   token_buffer += '\0';
  989.   char *ptr;
  990.   long n = strtol(token_buffer.contents(), &ptr, 10);
  991.   if (n == 0 && ptr == token_buffer.contents())
  992.     lex_error("bad argument `%1' to space command", token_buffer.contents());
  993.   else
  994.     set_space(int(n));
  995. }
  996.  
  997. void do_ifdef()
  998. {
  999.   int t = get_token();
  1000.   if (t != TEXT) {
  1001.     lex_error("bad ifdef");
  1002.     return;
  1003.   }
  1004.   token_buffer += '\0';
  1005.   definition *def = macro_table.lookup(token_buffer.contents());
  1006.   int result = def && def->is_macro && !def->is_simple;
  1007.   get_delimited_text();
  1008.   if (result) {
  1009.     token_buffer += '\0';
  1010.     current_input = new macro_input(token_buffer.contents(), current_input);
  1011.   }
  1012. }
  1013.  
  1014. void do_delim()
  1015. {
  1016.   int c = get_char();
  1017.   while (c == ' ' || c == '\n')
  1018.     c = get_char();
  1019.   int d;
  1020.   if (c == EOF || (d = get_char()) == EOF)
  1021.     lex_error("end of file while reading argument to `delim'");
  1022.   else {
  1023.     if (c == 'o' && d == 'f' && peek_char() == 'f') {
  1024.       (void)get_char();
  1025.       start_delim = end_delim = '\0';
  1026.     }
  1027.     else {
  1028.       start_delim = c;
  1029.       end_delim = d;
  1030.     }
  1031.   }
  1032. }
  1033.  
  1034. void do_chartype()
  1035. {
  1036.   int t = get_token(2);
  1037.   if (t != TEXT && t != QUOTED_TEXT) {
  1038.     lex_error("bad chartype");
  1039.     return;
  1040.   }
  1041.   token_buffer += '\0';
  1042.   string type = token_buffer;
  1043.   t = get_token();
  1044.   if (t != TEXT && t != QUOTED_TEXT) {
  1045.     lex_error("bad chartype");
  1046.     return;
  1047.   }
  1048.   token_buffer += '\0';
  1049.   set_char_type(type.contents(), strsave(token_buffer.contents()));
  1050. }
  1051.  
  1052. void do_set()
  1053. {
  1054.   int t = get_token(2);
  1055.   if (t != TEXT && t != QUOTED_TEXT) {
  1056.     lex_error("bad set");
  1057.     return;
  1058.   }
  1059.   token_buffer += '\0';
  1060.   string param = token_buffer;
  1061.   t = get_token();
  1062.   if (t != TEXT && t != QUOTED_TEXT) {
  1063.     lex_error("bad set");
  1064.     return;
  1065.   }
  1066.   token_buffer += '\0';
  1067.   int n;
  1068.   if (sscanf(&token_buffer[0], "%d", &n) != 1) {
  1069.     lex_error("bad number `%1'", token_buffer.contents());
  1070.     return;
  1071.   }
  1072.   set_param(param.contents(), n);
  1073. }
  1074.  
  1075. int yylex()
  1076. {
  1077.   for (;;) {
  1078.     int tk = get_token(1);
  1079.     switch(tk) {
  1080.     case UNDEF:
  1081.       do_undef();
  1082.       break;
  1083.     case SDEFINE:
  1084.       do_definition(1);
  1085.       break;
  1086.     case DEFINE:
  1087.       do_definition(0);
  1088.       break;
  1089.     case TDEFINE:
  1090.       if (!nroff)
  1091.     do_definition(0);
  1092.       else
  1093.     ignore_definition();
  1094.       break;
  1095.     case NDEFINE:
  1096.       if (nroff)
  1097.     do_definition(0);
  1098.       else
  1099.     ignore_definition();
  1100.       break;
  1101.     case GSIZE:
  1102.       do_gsize();
  1103.       break;
  1104.     case GFONT:
  1105.       do_gfont();
  1106.       break;
  1107.     case GRFONT:
  1108.       do_grfont();
  1109.       break;
  1110.     case GBFONT:
  1111.       do_gbfont();
  1112.       break;
  1113.     case SPACE:
  1114.       do_space();
  1115.       break;
  1116.     case INCLUDE:
  1117.       do_include();
  1118.       break;
  1119.     case IFDEF:
  1120.       do_ifdef();
  1121.       break;
  1122.     case DELIM:
  1123.       do_delim();
  1124.       break;
  1125.     case CHARTYPE:
  1126.       do_chartype();
  1127.       break;
  1128.     case SET:
  1129.       do_set();
  1130.       break;
  1131.     case QUOTED_TEXT:
  1132.     case TEXT:
  1133.       token_buffer += '\0';
  1134.       yylval.str = strsave(token_buffer.contents());
  1135.       // fall through
  1136.     default:
  1137.       return tk;
  1138.     }
  1139.   }
  1140. }
  1141.  
  1142. void lex_error(const char *message,
  1143.            const errarg &arg1,
  1144.            const errarg &arg2,
  1145.            const errarg &arg3)
  1146. {
  1147.   char *filename;
  1148.   int lineno;
  1149.   if (!get_location(&filename, &lineno))
  1150.     error(message, arg1, arg2, arg3);
  1151.   else
  1152.     error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
  1153. }
  1154.  
  1155. void yyerror(const char *s)
  1156. {
  1157.   char *filename;
  1158.   int lineno;
  1159.   if (!get_location(&filename, &lineno))
  1160.     error(s);
  1161.   else
  1162.     error_with_file_and_line(filename, lineno, s);
  1163.   show_context();
  1164. }
  1165.  
  1166.