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