Sync-to-go: update copyright for 2015
[s-roff.git] / src / pre-eqn / lex.cpp
blobcff08ac705758bfddc58162475b3fdcc0fe4e102
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 1989 - 1992, 2000 - 2003, 2005, 2007, 2008
5 * Free Software Foundation, Inc.
6 * Written by James Clark (jjc@jclark.com)
8 * This 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 * This 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.
23 #include "config.h"
24 #include "eqn-config.h"
26 #include "eqn.h"
27 #include "eqn_tab.h"
28 #include "file_case.h"
29 #include "ptable.h"
30 #include "stringclass.h"
32 // declarations to avoid friend name injection problems
33 int get_char();
34 int peek_char();
35 int get_location(char **, int *);
37 class definition
39 public:
40 char is_macro;
41 char is_simple;
42 union {
43 int tok;
44 char *contents;
46 definition();
47 ~definition();
50 definition::definition() : is_macro(1), is_simple(0)
52 contents = 0;
55 definition::~definition()
57 if (is_macro)
58 a_delete contents;
61 declare_ptable(definition)
62 implement_ptable(definition)
64 PTABLE(definition) macro_table;
66 static struct {
67 const char *name;
68 int token;
69 } token_table[] = { // FIXME const
70 { "over", OVER },
71 { "smallover", SMALLOVER },
72 { "sqrt", SQRT },
73 { "sub", SUB },
74 { "sup", SUP },
75 { "lpile", LPILE },
76 { "rpile", RPILE },
77 { "cpile", CPILE },
78 { "pile", PILE },
79 { "left", LEFT },
80 { "right", RIGHT },
81 { "to", TO },
82 { "from", FROM },
83 { "size", SIZE },
84 { "font", FONT },
85 { "roman", ROMAN },
86 { "bold", BOLD },
87 { "italic", ITALIC },
88 { "fat", FAT },
89 { "bar", BAR },
90 { "under", UNDER },
91 { "accent", ACCENT },
92 { "uaccent", UACCENT },
93 { "above", ABOVE },
94 { "fwd", FWD },
95 { "back", BACK },
96 { "down", DOWN },
97 { "up", UP },
98 { "matrix", MATRIX },
99 { "col", COL },
100 { "lcol", LCOL },
101 { "rcol", RCOL },
102 { "ccol", CCOL },
103 { "mark", MARK },
104 { "lineup", LINEUP },
105 { "space", SPACE },
106 { "gfont", GFONT },
107 { "gsize", GSIZE },
108 { "define", DEFINE },
109 { "sdefine", SDEFINE },
110 { "ndefine", NDEFINE },
111 { "tdefine", TDEFINE },
112 { "undef", UNDEF },
113 { "ifdef", IFDEF },
114 { "include", INCLUDE },
115 { "copy", INCLUDE },
116 { "delim", DELIM },
117 { "chartype", CHARTYPE },
118 { "type", TYPE },
119 { "vcenter", VCENTER },
120 { "set", SET },
121 { "opprime", PRIME },
122 { "grfont", GRFONT },
123 { "gbfont", GBFONT },
124 { "split", SPLIT },
125 { "nosplit", NOSPLIT },
126 { "special", SPECIAL },
129 struct builtin_def {
130 const char *name;
131 const char *def;
134 static struct builtin_def common_defs[] = { // FIXME const
135 { "ALPHA", "\\(*A" },
136 { "BETA", "\\(*B" },
137 { "CHI", "\\(*X" },
138 { "DELTA", "\\(*D" },
139 { "EPSILON", "\\(*E" },
140 { "ETA", "\\(*Y" },
141 { "GAMMA", "\\(*G" },
142 { "IOTA", "\\(*I" },
143 { "KAPPA", "\\(*K" },
144 { "LAMBDA", "\\(*L" },
145 { "MU", "\\(*M" },
146 { "NU", "\\(*N" },
147 { "OMEGA", "\\(*W" },
148 { "OMICRON", "\\(*O" },
149 { "PHI", "\\(*F" },
150 { "PI", "\\(*P" },
151 { "PSI", "\\(*Q" },
152 { "RHO", "\\(*R" },
153 { "SIGMA", "\\(*S" },
154 { "TAU", "\\(*T" },
155 { "THETA", "\\(*H" },
156 { "UPSILON", "\\(*U" },
157 { "XI", "\\(*C" },
158 { "ZETA", "\\(*Z" },
159 { "Alpha", "\\(*A" },
160 { "Beta", "\\(*B" },
161 { "Chi", "\\(*X" },
162 { "Delta", "\\(*D" },
163 { "Epsilon", "\\(*E" },
164 { "Eta", "\\(*Y" },
165 { "Gamma", "\\(*G" },
166 { "Iota", "\\(*I" },
167 { "Kappa", "\\(*K" },
168 { "Lambda", "\\(*L" },
169 { "Mu", "\\(*M" },
170 { "Nu", "\\(*N" },
171 { "Omega", "\\(*W" },
172 { "Omicron", "\\(*O" },
173 { "Phi", "\\(*F" },
174 { "Pi", "\\(*P" },
175 { "Psi", "\\(*Q" },
176 { "Rho", "\\(*R" },
177 { "Sigma", "\\(*S" },
178 { "Tau", "\\(*T" },
179 { "Theta", "\\(*H" },
180 { "Upsilon", "\\(*U" },
181 { "Xi", "\\(*C" },
182 { "Zeta", "\\(*Z" },
183 { "alpha", "\\(*a" },
184 { "beta", "\\(*b" },
185 { "chi", "\\(*x" },
186 { "delta", "\\(*d" },
187 { "epsilon", "\\(*e" },
188 { "eta", "\\(*y" },
189 { "gamma", "\\(*g" },
190 { "iota", "\\(*i" },
191 { "kappa", "\\(*k" },
192 { "lambda", "\\(*l" },
193 { "mu", "\\(*m" },
194 { "nu", "\\(*n" },
195 { "omega", "\\(*w" },
196 { "omicron", "\\(*o" },
197 { "phi", "\\(*f" },
198 { "pi", "\\(*p" },
199 { "psi", "\\(*q" },
200 { "rho", "\\(*r" },
201 { "sigma", "\\(*s" },
202 { "tau", "\\(*t" },
203 { "theta", "\\(*h" },
204 { "upsilon", "\\(*u" },
205 { "xi", "\\(*c" },
206 { "zeta", "\\(*z" },
207 { "max", "{type \"operator\" roman \"max\"}" },
208 { "min", "{type \"operator\" roman \"min\"}" },
209 { "lim", "{type \"operator\" roman \"lim\"}" },
210 { "sin", "{type \"operator\" roman \"sin\"}" },
211 { "cos", "{type \"operator\" roman \"cos\"}" },
212 { "tan", "{type \"operator\" roman \"tan\"}" },
213 { "sinh", "{type \"operator\" roman \"sinh\"}" },
214 { "cosh", "{type \"operator\" roman \"cosh\"}" },
215 { "tanh", "{type \"operator\" roman \"tanh\"}" },
216 { "arc", "{type \"operator\" roman \"arc\"}" },
217 { "log", "{type \"operator\" roman \"log\"}" },
218 { "ln", "{type \"operator\" roman \"ln\"}" },
219 { "exp", "{type \"operator\" roman \"exp\"}" },
220 { "Re", "{type \"operator\" roman \"Re\"}" },
221 { "Im", "{type \"operator\" roman \"Im\"}" },
222 { "det", "{type \"operator\" roman \"det\"}" },
223 { "and", "{roman \"and\"}" },
224 { "if", "{roman \"if\"}" },
225 { "for", "{roman \"for\"}" },
226 { "times", "type \"binary\" \\(mu" },
227 { "ldots", "type \"inner\" { . . . }" },
228 { "inf", "\\(if" },
229 { "partial", "\\(pd" },
230 { "nothing", "\"\"" },
231 { "half", "{1 smallover 2}" },
232 { "hat_def", "roman \"^\"" },
233 { "hat", "accent { hat_def }" },
234 { "tilde_def", "\"~\"" },
235 { "tilde", "accent { tilde_def }" },
236 { "==", "type \"relation\" \\(==" },
237 { "!=", "type \"relation\" \\(!=" },
238 { "+-", "type \"binary\" \\(+-" },
239 { "->", "type \"relation\" \\(->" },
240 { "<-", "type \"relation\" \\(<-" },
241 { "<<", "type \"relation\" \\(<<" },
242 { ">>", "type \"relation\" \\(>>" },
243 { "prime", "'" },
244 { "approx", "type \"relation\" \"\\(~=\"" },
245 { "grad", "\\(gr" },
246 { "del", "\\(gr" },
247 { "cdot", "type \"binary\" \\(md" },
248 { "cdots", "type \"inner\" { \\(md \\(md \\(md }" },
249 { "dollar", "$" },
252 /* composite definitions that require troff size and motion operators */
253 static struct builtin_def troff_defs[] = { // FIXME const
254 { "sum", "{type \"operator\" vcenter size +5 \\(*S}" },
255 { "prod", "{type \"operator\" vcenter size +5 \\(*P}" },
256 { "int", "{type \"operator\" vcenter size +8 \\(is}" },
257 { "union", "{type \"operator\" vcenter size +5 \\(cu}" },
258 { "inter", "{type \"operator\" vcenter size +5 \\(ca}" },
259 { "dot_def", "up 52 back 15 \".\"" },
260 { "dot", "accent { dot_def }" },
261 { "dotdot_def", "up 52 back 25 \"..\"" },
262 { "dotdot", "accent { dotdot_def }" },
263 { "utilde_def", "down 75 \"~\"" },
264 { "utilde", "uaccent { utilde_def }" },
265 { "vec_def", "up 52 size -5 \\(->" },
266 { "vec", "accent { vec_def }" },
267 { "dyad_def", "up 52 size -5 { \\(<> }" },
268 { "dyad", "accent { dyad_def }" },
269 { "...", "type \"inner\" vcenter { . . . }" },
272 /* equivalent definitions for MathML mode */
273 static struct builtin_def mathml_defs[] = { // FIXME const
274 { "sum", "{type \"operator\" size big \\(*S}" },
275 { "prod", "{type \"operator\" size big \\(*P}" },
276 { "int", "{type \"operator\" size big \\(is}" },
277 { "union", "{type \"operator\" size big \\(cu}" },
278 { "inter", "{type \"operator\" size big \\(ca}" },
279 { "dot", "accent { \".\" }" },
280 { "dotdot", "accent { \"..\" }" },
281 { "utilde", "uaccent { \"~\" }" },
282 { "vec", "accent { \\(-> }" },
283 { "dyad", "accent { \\(<> }" },
284 { "...", "type \"inner\" { . . . }" },
287 void init_table(const char *device)
289 unsigned int i;
290 for (i = 0; i < NELEM(token_table); i++) {
291 definition *def = new definition[1];
292 def->is_macro = 0;
293 def->tok = token_table[i].token;
294 macro_table.define(token_table[i].name, def);
296 for (i = 0; i < NELEM(common_defs); i++) {
297 definition *def = new definition[1];
298 def->is_macro = 1;
299 def->contents = strsave(common_defs[i].def);
300 def->is_simple = 1;
301 macro_table.define(common_defs[i].name, def);
303 if (output_format == troff) {
304 for (i = 0; i < NELEM(troff_defs); i++) {
305 definition *def = new definition[1];
306 def->is_macro = 1;
307 def->contents = strsave(troff_defs[i].def);
308 def->is_simple = 1;
309 macro_table.define(troff_defs[i].name, def);
312 else if (output_format == mathml) {
313 for (i = 0; i < NELEM(mathml_defs); i++) {
314 definition *def = new definition[1];
315 def->is_macro = 1;
316 def->contents = strsave(mathml_defs[i].def);
317 def->is_simple = 1;
318 macro_table.define(mathml_defs[i].name, def);
321 definition *def = new definition[1];
322 def->is_macro = 1;
323 def->contents = strsave("1");
324 macro_table.define(device, def);
327 class input
329 friend int get_char();
330 friend int peek_char();
331 friend int get_location(char **, int *);
332 friend void init_lex(const char *str, const char *filename, int lineno);
334 input *next;
336 public:
337 input(input *p);
338 virtual ~input();
339 virtual int get() = 0;
340 virtual int peek() = 0;
341 virtual int get_location(char **, int *);
344 class file_input
345 : public input
347 file_case *_fcp;
348 char *filename;
349 int lineno;
350 string line;
351 const char *ptr;
353 int read_line();
355 public:
356 file_input(file_case *, const char *, input *);
357 ~file_input();
358 int get();
359 int peek();
360 int get_location(char **, int *);
363 class macro_input
364 : public input
366 char *s;
367 char *p;
369 public:
370 macro_input(const char *, input *);
371 ~macro_input();
372 int get();
373 int peek();
376 class top_input
377 : public macro_input
379 char *filename;
380 int lineno;
382 public:
383 top_input(const char *, const char *, int, input *);
384 ~top_input();
385 int get();
386 int get_location(char **, int *);
389 class argument_macro_input
390 : public input
392 char *s;
393 char *p;
394 char *ap;
395 int argc;
396 char *argv[9];
398 public:
399 argument_macro_input(const char *, int, char **, input *);
400 ~argument_macro_input();
401 int get();
402 int peek();
405 input::input(input *x) : next(x)
409 input::~input()
413 int input::get_location(char **, int *)
415 return 0;
418 file_input::file_input(file_case *fcp, const char *fn, input *p)
419 : input(p), _fcp(fcp), lineno(0), ptr("")
421 filename = strsave(fn);
424 file_input::~file_input()
426 a_delete filename;
427 delete _fcp;
430 int file_input::read_line()
432 for (;;) {
433 line.clear();
434 lineno++;
435 for (;;) {
436 int c = _fcp->get_c();
437 if (c == EOF)
438 break;
439 else if (invalid_input_char(c))
440 lex_error("invalid input character code %1", c);
441 else {
442 line += char(c);
443 if (c == '\n')
444 break;
447 if (line.length() == 0)
448 return 0;
449 if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'E'
450 && (line[2] == 'Q' || line[2] == 'N')
451 && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
452 || compatible_flag))) {
453 line += '\0';
454 ptr = line.contents();
455 return 1;
460 int file_input::get()
462 if (*ptr != '\0' || read_line())
463 return *ptr++ & 0377;
464 else
465 return EOF;
468 int file_input::peek()
470 if (*ptr != '\0' || read_line())
471 return *ptr;
472 else
473 return EOF;
476 int file_input::get_location(char **fnp, int *lnp)
478 *fnp = filename;
479 *lnp = lineno;
480 return 1;
483 macro_input::macro_input(const char *str, input *x) : input(x)
485 p = s = strsave(str);
488 macro_input::~macro_input()
490 a_delete s;
493 int macro_input::get()
495 if (p == 0 || *p == '\0')
496 return EOF;
497 else
498 return *p++ & 0377;
501 int macro_input::peek()
503 if (p == 0 || *p == '\0')
504 return EOF;
505 else
506 return *p & 0377;
509 top_input::top_input(const char *str, const char *fn, int ln, input *x)
510 : macro_input(str, x), lineno(ln)
512 filename = strsave(fn);
515 top_input::~top_input()
517 a_delete filename;
520 int top_input::get()
522 int c = macro_input::get();
523 if (c == '\n')
524 lineno++;
525 return c;
528 int top_input::get_location(char **fnp, int *lnp)
530 *fnp = filename;
531 *lnp = lineno;
532 return 1;
535 argument_macro_input::argument_macro_input(const char *body, int ac,
536 char **av, input *x)
537 : input(x), ap(0), argc(ac)
539 int i;
540 for (i = 0; i < argc; i++)
541 argv[i] = av[i];
542 p = s = strsave(body);
543 int j = 0;
544 for (i = 0; s[i] != '\0'; i++)
545 if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
546 if (s[i+1] != '0')
547 s[j++] = ARG1 + s[++i] - '1';
549 else
550 s[j++] = s[i];
551 s[j] = '\0';
554 argument_macro_input::~argument_macro_input()
556 for (int i = 0; i < argc; i++)
557 a_delete argv[i];
558 a_delete s;
561 int argument_macro_input::get()
563 if (ap) {
564 if (*ap != '\0')
565 return *ap++ & 0377;
566 ap = 0;
568 if (p == 0)
569 return EOF;
570 while (*p >= ARG1 && *p <= ARG1 + 8) {
571 int i = *p++ - ARG1;
572 if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
573 ap = argv[i];
574 return *ap++ & 0377;
577 if (*p == '\0')
578 return EOF;
579 return *p++ & 0377;
582 int argument_macro_input::peek()
584 if (ap) {
585 if (*ap != '\0')
586 return *ap & 0377;
587 ap = 0;
589 if (p == 0)
590 return EOF;
591 while (*p >= ARG1 && *p <= ARG1 + 8) {
592 int i = *p++ - ARG1;
593 if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
594 ap = argv[i];
595 return *ap & 0377;
598 if (*p == '\0')
599 return EOF;
600 return *p & 0377;
603 static input *current_input = 0;
605 /* we insert a newline between input from different levels */
607 int get_char()
609 if (current_input == 0)
610 return EOF;
611 else {
612 int c = current_input->get();
613 if (c != EOF)
614 return c;
615 else {
616 input *tem = current_input;
617 current_input = current_input->next;
618 delete tem;
619 return '\n';
624 int peek_char()
626 if (current_input == 0)
627 return EOF;
628 else {
629 int c = current_input->peek();
630 if (c != EOF)
631 return c;
632 else
633 return '\n';
637 int get_location(char **fnp, int *lnp)
639 for (input *p = current_input; p; p = p->next)
640 if (p->get_location(fnp, lnp))
641 return 1;
642 return 0;
645 string token_buffer;
646 const int NCONTEXT = 4;
647 string context_ring[NCONTEXT];
648 int context_index = 0;
650 void flush_context()
652 for (int i = 0; i < NCONTEXT; i++)
653 context_ring[i] = "";
654 context_index = 0;
657 void show_context()
659 int i = context_index;
660 fputs(" context is\n\t", stderr);
661 for (;;) {
662 int j = (i + 1) % NCONTEXT;
663 if (j == context_index) {
664 fputs(">>> ", stderr);
665 put_string(context_ring[i], stderr);
666 fputs(" <<<", stderr);
667 break;
669 else if (context_ring[i].length() > 0) {
670 put_string(context_ring[i], stderr);
671 putc(' ', stderr);
673 i = j;
675 putc('\n', stderr);
678 void add_context(const string &s)
680 context_ring[context_index] = s;
681 context_index = (context_index + 1) % NCONTEXT;
684 void add_context(char c)
686 context_ring[context_index] = c;
687 context_index = (context_index + 1) % NCONTEXT;
690 void add_quoted_context(const string &s)
692 string &r = context_ring[context_index];
693 r = '"';
694 for (int i = 0; i < s.length(); i++)
695 if (s[i] == '"')
696 r += "\\\"";
697 else
698 r += s[i];
699 r += '"';
700 context_index = (context_index + 1) % NCONTEXT;
703 void init_lex(const char *str, const char *filename, int lineno)
705 while (current_input != 0) {
706 input *tem = current_input;
707 current_input = current_input->next;
708 delete tem;
710 current_input = new top_input(str, filename, lineno, 0);
711 flush_context();
714 void get_delimited_text()
716 char *filename;
717 int lineno;
718 int got_location = get_location(&filename, &lineno);
719 int start = get_char();
720 while (start == ' ' || start == '\t' || start == '\n')
721 start = get_char();
722 token_buffer.clear();
723 if (start == EOF) {
724 if (got_location)
725 error_with_file_and_line(filename, lineno,
726 "end of input while defining macro");
727 else
728 error("end of input while defining macro");
729 return;
731 for (;;) {
732 int c = get_char();
733 if (c == EOF) {
734 if (got_location)
735 error_with_file_and_line(filename, lineno,
736 "end of input while defining macro");
737 else
738 error("end of input while defining macro");
739 add_context(start + token_buffer);
740 return;
742 if (c == start)
743 break;
744 token_buffer += char(c);
746 add_context(start + token_buffer + start);
749 void interpolate_macro_with_args(const char *body)
751 char *argv[9];
752 int argc = 0;
753 int i;
754 for (i = 0; i < 9; i++)
755 argv[i] = 0;
756 int level = 0;
757 int c;
758 do {
759 token_buffer.clear();
760 for (;;) {
761 c = get_char();
762 if (c == EOF) {
763 lex_error("end of input while scanning macro arguments");
764 break;
766 if (level == 0 && (c == ',' || c == ')')) {
767 if (token_buffer.length() > 0) {
768 token_buffer += '\0';
769 argv[argc] = strsave(token_buffer.contents());
771 // for `foo()', argc = 0
772 if (argc > 0 || c != ')' || i > 0)
773 argc++;
774 break;
776 token_buffer += char(c);
777 if (c == '(')
778 level++;
779 else if (c == ')')
780 level--;
782 } while (c != ')' && c != EOF);
783 current_input = new argument_macro_input(body, argc, argv, current_input);
786 /* If lookup flag is non-zero the token will be looked up to see
787 if it is macro. If it's 1, it will looked up to see if it's a token.
790 int get_token(int lookup_flag = 0)
792 for (;;) {
793 int c = get_char();
794 while (c == ' ' || c == '\n')
795 c = get_char();
796 switch (c) {
797 case EOF:
799 add_context("end of input");
801 return 0;
802 case '"':
804 int quoted = 0;
805 token_buffer.clear();
806 for (;;) {
807 c = get_char();
808 if (c == EOF) {
809 lex_error("missing \"");
810 break;
812 else if (c == '\n') {
813 lex_error("newline before end of quoted text");
814 break;
816 else if (c == '"') {
817 if (!quoted)
818 break;
819 token_buffer[token_buffer.length() - 1] = '"';
820 quoted = 0;
822 else {
823 token_buffer += c;
824 quoted = quoted ? 0 : c == '\\';
828 add_quoted_context(token_buffer);
829 return QUOTED_TEXT;
830 case '{':
831 case '}':
832 case '^':
833 case '~':
834 case '\t':
835 add_context(c);
836 return c;
837 default:
839 int break_flag = 0;
840 int quoted = 0;
841 token_buffer.clear();
842 if (c == '\\')
843 quoted = 1;
844 else
845 token_buffer += c;
846 int done = 0;
847 while (!done) {
848 c = peek_char();
849 if (!quoted && lookup_flag != 0 && c == '(') {
850 token_buffer += '\0';
851 definition *def = macro_table.lookup(token_buffer.contents());
852 if (def && def->is_macro && !def->is_simple) {
853 (void)get_char(); // skip initial '('
854 interpolate_macro_with_args(def->contents);
855 break_flag = 1;
856 break;
858 token_buffer.set_length(token_buffer.length() - 1);
860 if (quoted) {
861 quoted = 0;
862 switch (c) {
863 case EOF:
864 lex_error("`\\' ignored at end of equation");
865 done = 1;
866 break;
867 case '\n':
868 lex_error("`\\' ignored because followed by newline");
869 done = 1;
870 break;
871 case '\t':
872 lex_error("`\\' ignored because followed by tab");
873 done = 1;
874 break;
875 case '"':
876 (void)get_char();
877 token_buffer += '"';
878 break;
879 default:
880 (void)get_char();
881 token_buffer += '\\';
882 token_buffer += c;
883 break;
886 else {
887 switch (c) {
888 case EOF:
889 case '{':
890 case '}':
891 case '^':
892 case '~':
893 case '"':
894 case ' ':
895 case '\t':
896 case '\n':
897 done = 1;
898 break;
899 case '\\':
900 (void)get_char();
901 quoted = 1;
902 break;
903 default:
904 (void)get_char();
905 token_buffer += char(c);
906 break;
910 if (break_flag || token_buffer.length() == 0)
911 break;
912 if (lookup_flag != 0) {
913 token_buffer += '\0';
914 definition *def = macro_table.lookup(token_buffer.contents());
915 token_buffer.set_length(token_buffer.length() - 1);
916 if (def) {
917 if (def->is_macro) {
918 current_input = new macro_input(def->contents, current_input);
919 break;
921 else if (lookup_flag == 1) {
922 add_context(token_buffer);
923 return def->tok;
927 add_context(token_buffer);
928 return TEXT;
934 void do_include()
936 int t = get_token(2);
937 if (t != TEXT && t != QUOTED_TEXT) {
938 lex_error("bad filename for include");
939 return;
941 token_buffer += '\0';
942 const char *filename = token_buffer.contents();
943 file_case *fcp = file_case::muxer(filename);
944 if (fcp == NULL) {
945 lex_error("can't open included file `%1'", filename);
946 return;
948 current_input = new file_input(fcp, filename, current_input);
951 void ignore_definition()
953 int t = get_token();
954 if (t != TEXT) {
955 lex_error("bad definition");
956 return;
958 get_delimited_text();
961 void do_definition(int is_simple)
963 int t = get_token();
964 if (t != TEXT) {
965 lex_error("bad definition");
966 return;
968 token_buffer += '\0';
969 const char *name = token_buffer.contents();
970 definition *def = macro_table.lookup(name);
971 if (def == 0) {
972 def = new definition[1];
973 macro_table.define(name, def);
975 else if (def->is_macro) {
976 a_delete def->contents;
978 get_delimited_text();
979 token_buffer += '\0';
980 def->is_macro = 1;
981 def->contents = strsave(token_buffer.contents());
982 def->is_simple = is_simple;
985 void do_undef()
987 int t = get_token();
988 if (t != TEXT) {
989 lex_error("bad undef command");
990 return;
992 token_buffer += '\0';
993 macro_table.define(token_buffer.contents(), 0);
996 void do_gsize()
998 int t = get_token(2);
999 if (t != TEXT && t != QUOTED_TEXT) {
1000 lex_error("bad argument to gsize command");
1001 return;
1003 token_buffer += '\0';
1004 if (!set_gsize(token_buffer.contents()))
1005 lex_error("invalid size `%1'", token_buffer.contents());
1008 void do_gfont()
1010 int t = get_token(2);
1011 if (t != TEXT && t != QUOTED_TEXT) {
1012 lex_error("bad argument to gfont command");
1013 return;
1015 token_buffer += '\0';
1016 set_gfont(token_buffer.contents());
1019 void do_grfont()
1021 int t = get_token(2);
1022 if (t != TEXT && t != QUOTED_TEXT) {
1023 lex_error("bad argument to grfont command");
1024 return;
1026 token_buffer += '\0';
1027 set_grfont(token_buffer.contents());
1030 void do_gbfont()
1032 int t = get_token(2);
1033 if (t != TEXT && t != QUOTED_TEXT) {
1034 lex_error("bad argument to gbfont command");
1035 return;
1037 token_buffer += '\0';
1038 set_gbfont(token_buffer.contents());
1041 void do_space()
1043 int t = get_token(2);
1044 if (t != TEXT && t != QUOTED_TEXT) {
1045 lex_error("bad argument to space command");
1046 return;
1048 token_buffer += '\0';
1049 char *ptr;
1050 long n = strtol(token_buffer.contents(), &ptr, 10);
1051 if (n == 0 && ptr == token_buffer.contents())
1052 lex_error("bad argument `%1' to space command", token_buffer.contents());
1053 else
1054 set_space(int(n));
1057 void do_ifdef()
1059 int t = get_token();
1060 if (t != TEXT) {
1061 lex_error("bad ifdef");
1062 return;
1064 token_buffer += '\0';
1065 definition *def = macro_table.lookup(token_buffer.contents());
1066 int result = def && def->is_macro && !def->is_simple;
1067 get_delimited_text();
1068 if (result) {
1069 token_buffer += '\0';
1070 current_input = new macro_input(token_buffer.contents(), current_input);
1074 void do_delim()
1076 int c = get_char();
1077 while (c == ' ' || c == '\n')
1078 c = get_char();
1079 int d;
1080 if (c == EOF || (d = get_char()) == EOF)
1081 lex_error("end of file while reading argument to `delim'");
1082 else {
1083 if (c == 'o' && d == 'f' && peek_char() == 'f') {
1084 (void)get_char();
1085 start_delim = end_delim = '\0';
1087 else {
1088 start_delim = c;
1089 end_delim = d;
1094 void do_chartype()
1096 int t = get_token(2);
1097 if (t != TEXT && t != QUOTED_TEXT) {
1098 lex_error("bad chartype");
1099 return;
1101 token_buffer += '\0';
1102 string type = token_buffer;
1103 t = get_token();
1104 if (t != TEXT && t != QUOTED_TEXT) {
1105 lex_error("bad chartype");
1106 return;
1108 token_buffer += '\0';
1109 set_char_type(type.contents(), strsave(token_buffer.contents()));
1112 void do_set()
1114 int t = get_token(2);
1115 if (t != TEXT && t != QUOTED_TEXT) {
1116 lex_error("bad set");
1117 return;
1119 token_buffer += '\0';
1120 string param = token_buffer;
1121 t = get_token();
1122 if (t != TEXT && t != QUOTED_TEXT) {
1123 lex_error("bad set");
1124 return;
1126 token_buffer += '\0';
1127 int n;
1128 if (sscanf(&token_buffer[0], "%d", &n) != 1) {
1129 lex_error("bad number `%1'", token_buffer.contents());
1130 return;
1132 set_param(param.contents(), n);
1135 int yylex()
1137 for (;;) {
1138 int tk = get_token(1);
1139 switch(tk) {
1140 case UNDEF:
1141 do_undef();
1142 break;
1143 case SDEFINE:
1144 do_definition(1);
1145 break;
1146 case DEFINE:
1147 do_definition(0);
1148 break;
1149 case TDEFINE:
1150 if (!nroff)
1151 do_definition(0);
1152 else
1153 ignore_definition();
1154 break;
1155 case NDEFINE:
1156 if (nroff)
1157 do_definition(0);
1158 else
1159 ignore_definition();
1160 break;
1161 case GSIZE:
1162 do_gsize();
1163 break;
1164 case GFONT:
1165 do_gfont();
1166 break;
1167 case GRFONT:
1168 do_grfont();
1169 break;
1170 case GBFONT:
1171 do_gbfont();
1172 break;
1173 case SPACE:
1174 do_space();
1175 break;
1176 case INCLUDE:
1177 do_include();
1178 break;
1179 case IFDEF:
1180 do_ifdef();
1181 break;
1182 case DELIM:
1183 do_delim();
1184 break;
1185 case CHARTYPE:
1186 do_chartype();
1187 break;
1188 case SET:
1189 do_set();
1190 break;
1191 case QUOTED_TEXT:
1192 case TEXT:
1193 token_buffer += '\0';
1194 yylval.str = strsave(token_buffer.contents());
1195 // fall through
1196 default:
1197 return tk;
1202 void lex_error(const char *message,
1203 const errarg &arg1,
1204 const errarg &arg2,
1205 const errarg &arg3)
1207 char *filename;
1208 int lineno;
1209 if (!get_location(&filename, &lineno))
1210 error(message, arg1, arg2, arg3);
1211 else
1212 error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
1215 void yyerror(const char *s)
1217 char *filename;
1218 int lineno;
1219 if (!get_location(&filename, &lineno))
1220 error(s);
1221 else
1222 error_with_file_and_line(filename, lineno, s);
1223 show_context();
1226 // s-it2-mode