1 /* $NetBSD: lex.cpp,v 1.1.1.1 2016/01/13 18:41:49 christos Exp $ */ 2 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 (at) jclark.com) 7 8 This file is part of groff. 9 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. 14 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. 19 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. */ 23 24 #include "eqn.h" 25 #include "eqn_tab.h" 26 #include "stringclass.h" 27 #include "ptable.h" 28 29 30 // declarations to avoid friend name injection problems 31 int get_char(); 32 int peek_char(); 33 int get_location(char **, int *); 34 35 struct definition { 36 char is_macro; 37 char is_simple; 38 union { 39 int tok; 40 char *contents; 41 }; 42 definition(); 43 ~definition(); 44 }; 45 46 definition::definition() : is_macro(1), is_simple(0) 47 { 48 contents = 0; 49 } 50 51 definition::~definition() 52 { 53 if (is_macro) 54 a_delete contents; 55 } 56 57 declare_ptable(definition) 58 implement_ptable(definition) 59 60 PTABLE(definition) macro_table; 61 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 }, 123 }; 124 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", "$" }, 259 }; 260 261 void init_table(const char *device) 262 { 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); 269 } 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); 276 } 277 definition *def = new definition[1]; 278 def->is_macro = 1; 279 def->contents = strsave("1"); 280 macro_table.define(device, def); 281 } 282 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 *); 291 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); 296 }; 297 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 *); 311 }; 312 313 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(); 322 }; 323 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 *); 332 }; 333 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(); 345 }; 346 347 input::input(input *x) : next(x) 348 { 349 } 350 351 input::~input() 352 { 353 } 354 355 int input::get_location(char **, int *) 356 { 357 return 0; 358 } 359 360 file_input::file_input(FILE *f, const char *fn, input *p) 361 : input(p), lineno(0), ptr("") 362 { 363 fp = f; 364 filename = strsave(fn); 365 } 366 367 file_input::~file_input() 368 { 369 a_delete filename; 370 fclose(fp); 371 } 372 373 int file_input::read_line() 374 { 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; 388 } 389 } 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; 399 } 400 } 401 } 402 403 int file_input::get() 404 { 405 if (*ptr != '\0' || read_line()) 406 return *ptr++ & 0377; 407 else 408 return EOF; 409 } 410 411 int file_input::peek() 412 { 413 if (*ptr != '\0' || read_line()) 414 return *ptr; 415 else 416 return EOF; 417 } 418 419 int file_input::get_location(char **fnp, int *lnp) 420 { 421 *fnp = filename; 422 *lnp = lineno; 423 return 1; 424 } 425 426 macro_input::macro_input(const char *str, input *x) : input(x) 427 { 428 p = s = strsave(str); 429 } 430 431 macro_input::~macro_input() 432 { 433 a_delete s; 434 } 435 436 int macro_input::get() 437 { 438 if (p == 0 || *p == '\0') 439 return EOF; 440 else 441 return *p++ & 0377; 442 } 443 444 int macro_input::peek() 445 { 446 if (p == 0 || *p == '\0') 447 return EOF; 448 else 449 return *p & 0377; 450 } 451 452 top_input::top_input(const char *str, const char *fn, int ln, input *x) 453 : macro_input(str, x), lineno(ln) 454 { 455 filename = strsave(fn); 456 } 457 458 top_input::~top_input() 459 { 460 a_delete filename; 461 } 462 463 int top_input::get() 464 { 465 int c = macro_input::get(); 466 if (c == '\n') 467 lineno++; 468 return c; 469 } 470 471 int top_input::get_location(char **fnp, int *lnp) 472 { 473 *fnp = filename; 474 *lnp = lineno; 475 return 1; 476 } 477 478 // Character representing $1. Must be invalid input character. 479 #define ARG1 14 480 481 argument_macro_input::argument_macro_input(const char *body, int ac, 482 char **av, input *x) 483 : input(x), ap(0), argc(ac) 484 { 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'; 494 } 495 else 496 s[j++] = s[i]; 497 s[j] = '\0'; 498 } 499 500 501 argument_macro_input::~argument_macro_input() 502 { 503 for (int i = 0; i < argc; i++) 504 a_delete argv[i]; 505 a_delete s; 506 } 507 508 int argument_macro_input::get() 509 { 510 if (ap) { 511 if (*ap != '\0') 512 return *ap++ & 0377; 513 ap = 0; 514 } 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; 522 } 523 } 524 if (*p == '\0') 525 return EOF; 526 return *p++ & 0377; 527 } 528 529 int argument_macro_input::peek() 530 { 531 if (ap) { 532 if (*ap != '\0') 533 return *ap & 0377; 534 ap = 0; 535 } 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; 543 } 544 } 545 if (*p == '\0') 546 return EOF; 547 return *p & 0377; 548 } 549 550 static input *current_input = 0; 551 552 /* we insert a newline between input from different levels */ 553 554 int get_char() 555 { 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'; 567 } 568 } 569 } 570 571 int peek_char() 572 { 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'; 581 } 582 } 583 584 int get_location(char **fnp, int *lnp) 585 { 586 for (input *p = current_input; p; p = p->next) 587 if (p->get_location(fnp, lnp)) 588 return 1; 589 return 0; 590 } 591 592 string token_buffer; 593 const int NCONTEXT = 4; 594 string context_ring[NCONTEXT]; 595 int context_index = 0; 596 597 void flush_context() 598 { 599 for (int i = 0; i < NCONTEXT; i++) 600 context_ring[i] = ""; 601 context_index = 0; 602 } 603 604 void show_context() 605 { 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; 615 } 616 else if (context_ring[i].length() > 0) { 617 put_string(context_ring[i], stderr); 618 putc(' ', stderr); 619 } 620 i = j; 621 } 622 putc('\n', stderr); 623 } 624 625 void add_context(const string &s) 626 { 627 context_ring[context_index] = s; 628 context_index = (context_index + 1) % NCONTEXT; 629 } 630 631 void add_context(char c) 632 { 633 context_ring[context_index] = c; 634 context_index = (context_index + 1) % NCONTEXT; 635 } 636 637 void add_quoted_context(const string &s) 638 { 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; 648 } 649 650 void init_lex(const char *str, const char *filename, int lineno) 651 { 652 while (current_input != 0) { 653 input *tem = current_input; 654 current_input = current_input->next; 655 delete tem; 656 } 657 current_input = new top_input(str, filename, lineno, 0); 658 flush_context(); 659 } 660 661 662 void get_delimited_text() 663 { 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; 678 } 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; 689 } 690 if (c == start) 691 break; 692 token_buffer += char(c); 693 } 694 add_context(start + token_buffer + start); 695 } 696 697 void interpolate_macro_with_args(const char *body) 698 { 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; 713 } 714 if (level == 0 && (c == ',' || c == ')')) { 715 if (token_buffer.length() > 0) { 716 token_buffer += '\0'; 717 argv[argc] = strsave(token_buffer.contents()); 718 } 719 // for `foo()', argc = 0 720 if (argc > 0 || c != ')' || i > 0) 721 argc++; 722 break; 723 } 724 token_buffer += char(c); 725 if (c == '(') 726 level++; 727 else if (c == ')') 728 level--; 729 } 730 } while (c != ')' && c != EOF); 731 current_input = new argument_macro_input(body, argc, argv, current_input); 732 } 733 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. 736 */ 737 738 int get_token(int lookup_flag = 0) 739 { 740 for (;;) { 741 int c = get_char(); 742 while (c == ' ' || c == '\n') 743 c = get_char(); 744 switch (c) { 745 case EOF: 746 { 747 add_context("end of input"); 748 } 749 return 0; 750 case '"': 751 { 752 int quoted = 0; 753 token_buffer.clear(); 754 for (;;) { 755 c = get_char(); 756 if (c == EOF) { 757 lex_error("missing \""); 758 break; 759 } 760 else if (c == '\n') { 761 lex_error("newline before end of quoted text"); 762 break; 763 } 764 else if (c == '"') { 765 if (!quoted) 766 break; 767 token_buffer[token_buffer.length() - 1] = '"'; 768 quoted = 0; 769 } 770 else { 771 token_buffer += c; 772 quoted = quoted ? 0 : c == '\\'; 773 } 774 } 775 } 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: 786 { 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; 805 } 806 token_buffer.set_length(token_buffer.length() - 1); 807 } 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; 832 } 833 } 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; 855 } 856 } 857 } 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; 868 } 869 else if (lookup_flag == 1) { 870 add_context(token_buffer); 871 return def->tok; 872 } 873 } 874 } 875 add_context(token_buffer); 876 return TEXT; 877 } 878 } 879 } 880 } 881 882 void do_include() 883 { 884 int t = get_token(2); 885 if (t != TEXT && t != QUOTED_TEXT) { 886 lex_error("bad filename for include"); 887 return; 888 } 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; 896 } 897 current_input = new file_input(fp, filename, current_input); 898 } 899 900 void ignore_definition() 901 { 902 int t = get_token(); 903 if (t != TEXT) { 904 lex_error("bad definition"); 905 return; 906 } 907 get_delimited_text(); 908 } 909 910 void do_definition(int is_simple) 911 { 912 int t = get_token(); 913 if (t != TEXT) { 914 lex_error("bad definition"); 915 return; 916 } 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); 923 } 924 else if (def->is_macro) { 925 a_delete def->contents; 926 } 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; 932 } 933 934 void do_undef() 935 { 936 int t = get_token(); 937 if (t != TEXT) { 938 lex_error("bad undef command"); 939 return; 940 } 941 token_buffer += '\0'; 942 macro_table.define(token_buffer.contents(), 0); 943 } 944 945 void do_gsize() 946 { 947 int t = get_token(2); 948 if (t != TEXT && t != QUOTED_TEXT) { 949 lex_error("bad argument to gsize command"); 950 return; 951 } 952 token_buffer += '\0'; 953 if (!set_gsize(token_buffer.contents())) 954 lex_error("invalid size `%1'", token_buffer.contents()); 955 } 956 957 void do_gfont() 958 { 959 int t = get_token(2); 960 if (t != TEXT && t != QUOTED_TEXT) { 961 lex_error("bad argument to gfont command"); 962 return; 963 } 964 token_buffer += '\0'; 965 set_gfont(token_buffer.contents()); 966 } 967 968 void do_grfont() 969 { 970 int t = get_token(2); 971 if (t != TEXT && t != QUOTED_TEXT) { 972 lex_error("bad argument to grfont command"); 973 return; 974 } 975 token_buffer += '\0'; 976 set_grfont(token_buffer.contents()); 977 } 978 979 void do_gbfont() 980 { 981 int t = get_token(2); 982 if (t != TEXT && t != QUOTED_TEXT) { 983 lex_error("bad argument to gbfont command"); 984 return; 985 } 986 token_buffer += '\0'; 987 set_gbfont(token_buffer.contents()); 988 } 989 990 void do_space() 991 { 992 int t = get_token(2); 993 if (t != TEXT && t != QUOTED_TEXT) { 994 lex_error("bad argument to space command"); 995 return; 996 } 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)); 1004 } 1005 1006 void do_ifdef() 1007 { 1008 int t = get_token(); 1009 if (t != TEXT) { 1010 lex_error("bad ifdef"); 1011 return; 1012 } 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); 1020 } 1021 } 1022 1023 void do_delim() 1024 { 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'; 1035 } 1036 else { 1037 start_delim = c; 1038 end_delim = d; 1039 } 1040 } 1041 } 1042 1043 void do_chartype() 1044 { 1045 int t = get_token(2); 1046 if (t != TEXT && t != QUOTED_TEXT) { 1047 lex_error("bad chartype"); 1048 return; 1049 } 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; 1056 } 1057 token_buffer += '\0'; 1058 set_char_type(type.contents(), strsave(token_buffer.contents())); 1059 } 1060 1061 void do_set() 1062 { 1063 int t = get_token(2); 1064 if (t != TEXT && t != QUOTED_TEXT) { 1065 lex_error("bad set"); 1066 return; 1067 } 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; 1074 } 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; 1080 } 1081 set_param(param.contents(), n); 1082 } 1083 1084 int yylex() 1085 { 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; 1147 } 1148 } 1149 } 1150 1151 void lex_error(const char *message, 1152 const errarg &arg1, 1153 const errarg &arg2, 1154 const errarg &arg3) 1155 { 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); 1162 } 1163 1164 void yyerror(const char *s) 1165 { 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(); 1173 } 1174 1175