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