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