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