1// -*- C++ -*- 2/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002, 2003, 2004 3 Free Software Foundation, Inc. 4 Written by James Clark (jjc@jclark.com) 5 6This file is part of groff. 7 8groff is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13groff is distributed in the hope that it will be useful, but WITHOUT ANY 14WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License along 19with groff; see the file COPYING. If not, write to the Free Software 20Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21 22#include "pic.h" 23#include "ptable.h" 24#include "object.h" 25#include "pic_tab.h" 26 27declare_ptable(char) 28implement_ptable(char) 29 30PTABLE(char) macro_table; 31 32class macro_input : public input { 33 char *s; 34 char *p; 35public: 36 macro_input(const char *); 37 ~macro_input(); 38 int get(); 39 int peek(); 40}; 41 42class argument_macro_input : public input { 43 char *s; 44 char *p; 45 char *ap; 46 int argc; 47 char *argv[9]; 48public: 49 argument_macro_input(const char *, int, char **); 50 ~argument_macro_input(); 51 int get(); 52 int peek(); 53}; 54 55input::input() : next(0) 56{ 57} 58 59input::~input() 60{ 61} 62 63int input::get_location(const char **, int *) 64{ 65 return 0; 66} 67 68file_input::file_input(FILE *f, const char *fn) 69: fp(f), filename(fn), lineno(0), ptr("") 70{ 71} 72 73file_input::~file_input() 74{ 75 fclose(fp); 76} 77 78int file_input::read_line() 79{ 80 for (;;) { 81 line.clear(); 82 lineno++; 83 for (;;) { 84 int c = getc(fp); 85 if (c == EOF) 86 break; 87 else if (invalid_input_char(c)) 88 lex_error("invalid input character code %1", c); 89 else { 90 line += char(c); 91 if (c == '\n') 92 break; 93 } 94 } 95 if (line.length() == 0) 96 return 0; 97 if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P' 98 && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F') 99 && (line.length() == 3 || line[3] == ' ' || line[3] == '\n' 100 || compatible_flag))) { 101 line += '\0'; 102 ptr = line.contents(); 103 return 1; 104 } 105 } 106} 107 108int file_input::get() 109{ 110 if (*ptr != '\0' || read_line()) 111 return (unsigned char)*ptr++; 112 else 113 return EOF; 114} 115 116int file_input::peek() 117{ 118 if (*ptr != '\0' || read_line()) 119 return (unsigned char)*ptr; 120 else 121 return EOF; 122} 123 124int file_input::get_location(const char **fnp, int *lnp) 125{ 126 *fnp = filename; 127 *lnp = lineno; 128 return 1; 129} 130 131macro_input::macro_input(const char *str) 132{ 133 p = s = strsave(str); 134} 135 136macro_input::~macro_input() 137{ 138 a_delete s; 139} 140 141int macro_input::get() 142{ 143 if (p == 0 || *p == '\0') 144 return EOF; 145 else 146 return (unsigned char)*p++; 147} 148 149int macro_input::peek() 150{ 151 if (p == 0 || *p == '\0') 152 return EOF; 153 else 154 return (unsigned char)*p; 155} 156 157// Character representing $1. Must be invalid input character. 158#define ARG1 14 159 160char *process_body(const char *body) 161{ 162 char *s = strsave(body); 163 int j = 0; 164 for (int i = 0; s[i] != '\0'; i++) 165 if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') { 166 if (s[i+1] != '0') 167 s[j++] = ARG1 + s[++i] - '1'; 168 } 169 else 170 s[j++] = s[i]; 171 s[j] = '\0'; 172 return s; 173} 174 175 176argument_macro_input::argument_macro_input(const char *body, int ac, char **av) 177: ap(0), argc(ac) 178{ 179 for (int i = 0; i < argc; i++) 180 argv[i] = av[i]; 181 p = s = process_body(body); 182} 183 184 185argument_macro_input::~argument_macro_input() 186{ 187 for (int i = 0; i < argc; i++) 188 a_delete argv[i]; 189 a_delete s; 190} 191 192int argument_macro_input::get() 193{ 194 if (ap) { 195 if (*ap != '\0') 196 return (unsigned char)*ap++; 197 ap = 0; 198 } 199 if (p == 0) 200 return EOF; 201 while (*p >= ARG1 && *p <= ARG1 + 8) { 202 int i = *p++ - ARG1; 203 if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { 204 ap = argv[i]; 205 return (unsigned char)*ap++; 206 } 207 } 208 if (*p == '\0') 209 return EOF; 210 return (unsigned char)*p++; 211} 212 213int argument_macro_input::peek() 214{ 215 if (ap) { 216 if (*ap != '\0') 217 return (unsigned char)*ap; 218 ap = 0; 219 } 220 if (p == 0) 221 return EOF; 222 while (*p >= ARG1 && *p <= ARG1 + 8) { 223 int i = *p++ - ARG1; 224 if (i < argc && argv[i] != 0 && argv[i][0] != '\0') { 225 ap = argv[i]; 226 return (unsigned char)*ap; 227 } 228 } 229 if (*p == '\0') 230 return EOF; 231 return (unsigned char)*p; 232} 233 234class input_stack { 235 static input *current_input; 236 static int bol_flag; 237public: 238 static void push(input *); 239 static void clear(); 240 static int get_char(); 241 static int peek_char(); 242 static int get_location(const char **fnp, int *lnp); 243 static void push_back(unsigned char c, int was_bol = 0); 244 static int bol(); 245}; 246 247input *input_stack::current_input = 0; 248int input_stack::bol_flag = 0; 249 250inline int input_stack::bol() 251{ 252 return bol_flag; 253} 254 255void input_stack::clear() 256{ 257 while (current_input != 0) { 258 input *tem = current_input; 259 current_input = current_input->next; 260 delete tem; 261 } 262 bol_flag = 1; 263} 264 265void input_stack::push(input *in) 266{ 267 in->next = current_input; 268 current_input = in; 269} 270 271void lex_init(input *top) 272{ 273 input_stack::clear(); 274 input_stack::push(top); 275} 276 277void lex_cleanup() 278{ 279 while (input_stack::get_char() != EOF) 280 ; 281} 282 283int input_stack::get_char() 284{ 285 while (current_input != 0) { 286 int c = current_input->get(); 287 if (c != EOF) { 288 bol_flag = c == '\n'; 289 return c; 290 } 291 // don't pop the top-level input off the stack 292 if (current_input->next == 0) 293 return EOF; 294 input *tem = current_input; 295 current_input = current_input->next; 296 delete tem; 297 } 298 return EOF; 299} 300 301int input_stack::peek_char() 302{ 303 while (current_input != 0) { 304 int c = current_input->peek(); 305 if (c != EOF) 306 return c; 307 if (current_input->next == 0) 308 return EOF; 309 input *tem = current_input; 310 current_input = current_input->next; 311 delete tem; 312 } 313 return EOF; 314} 315 316class char_input : public input { 317 int c; 318public: 319 char_input(int); 320 int get(); 321 int peek(); 322}; 323 324char_input::char_input(int n) : c((unsigned char)n) 325{ 326} 327 328int char_input::get() 329{ 330 int n = c; 331 c = EOF; 332 return n; 333} 334 335int char_input::peek() 336{ 337 return c; 338} 339 340void input_stack::push_back(unsigned char c, int was_bol) 341{ 342 push(new char_input(c)); 343 bol_flag = was_bol; 344} 345 346int input_stack::get_location(const char **fnp, int *lnp) 347{ 348 for (input *p = current_input; p; p = p->next) 349 if (p->get_location(fnp, lnp)) 350 return 1; 351 return 0; 352} 353 354string context_buffer; 355 356string token_buffer; 357double token_double; 358int token_int; 359 360void interpolate_macro_with_args(const char *body) 361{ 362 char *argv[9]; 363 int argc = 0; 364 int i; 365 for (i = 0; i < 9; i++) 366 argv[i] = 0; 367 int level = 0; 368 int c; 369 enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL; 370 do { 371 token_buffer.clear(); 372 for (;;) { 373 c = input_stack::get_char(); 374 if (c == EOF) { 375 lex_error("end of input while scanning macro arguments"); 376 break; 377 } 378 if (state == NORMAL && level == 0 && (c == ',' || c == ')')) { 379 if (token_buffer.length() > 0) { 380 token_buffer += '\0'; 381 argv[argc] = strsave(token_buffer.contents()); 382 } 383 // for `foo()', argc = 0 384 if (argc > 0 || c != ')' || i > 0) 385 argc++; 386 break; 387 } 388 token_buffer += char(c); 389 switch (state) { 390 case NORMAL: 391 if (c == '"') 392 state = IN_STRING; 393 else if (c == '(') 394 level++; 395 else if (c == ')') 396 level--; 397 break; 398 case IN_STRING: 399 if (c == '"') 400 state = NORMAL; 401 else if (c == '\\') 402 state = IN_STRING_QUOTED; 403 break; 404 case IN_STRING_QUOTED: 405 state = IN_STRING; 406 break; 407 } 408 } 409 } while (c != ')' && c != EOF); 410 input_stack::push(new argument_macro_input(body, argc, argv)); 411} 412 413static int docmp(const char *s1, int n1, const char *s2, int n2) 414{ 415 if (n1 < n2) { 416 int r = memcmp(s1, s2, n1); 417 return r ? r : -1; 418 } 419 else if (n1 > n2) { 420 int r = memcmp(s1, s2, n2); 421 return r ? r : 1; 422 } 423 else 424 return memcmp(s1, s2, n1); 425} 426 427int lookup_keyword(const char *str, int len) 428{ 429 static struct keyword { 430 const char *name; 431 int token; 432 } table[] = { 433 { "Here", HERE }, 434 { "above", ABOVE }, 435 { "aligned", ALIGNED }, 436 { "and", AND }, 437 { "arc", ARC }, 438 { "arrow", ARROW }, 439 { "at", AT }, 440 { "atan2", ATAN2 }, 441 { "below", BELOW }, 442 { "between", BETWEEN }, 443 { "bottom", BOTTOM }, 444 { "box", BOX }, 445 { "by", BY }, 446 { "ccw", CCW }, 447 { "center", CENTER }, 448 { "chop", CHOP }, 449 { "circle", CIRCLE }, 450 { "color", COLORED }, 451 { "colored", COLORED }, 452 { "colour", COLORED }, 453 { "coloured", COLORED }, 454 { "command", COMMAND }, 455 { "copy", COPY }, 456 { "cos", COS }, 457 { "cw", CW }, 458 { "dashed", DASHED }, 459 { "define", DEFINE }, 460 { "diam", DIAMETER }, 461 { "diameter", DIAMETER }, 462 { "do", DO }, 463 { "dotted", DOTTED }, 464 { "down", DOWN }, 465 { "east", EAST }, 466 { "ellipse", ELLIPSE }, 467 { "else", ELSE }, 468 { "end", END }, 469 { "exp", EXP }, 470 { "figname", FIGNAME }, 471 { "fill", FILL }, 472 { "filled", FILL }, 473 { "for", FOR }, 474 { "from", FROM }, 475 { "height", HEIGHT }, 476 { "ht", HEIGHT }, 477 { "if", IF }, 478 { "int", INT }, 479 { "invis", INVISIBLE }, 480 { "invisible", INVISIBLE }, 481 { "last", LAST }, 482 { "left", LEFT }, 483 { "line", LINE }, 484 { "ljust", LJUST }, 485 { "log", LOG }, 486 { "lower", LOWER }, 487 { "max", K_MAX }, 488 { "min", K_MIN }, 489 { "move", MOVE }, 490 { "north", NORTH }, 491 { "of", OF }, 492 { "outline", OUTLINED }, 493 { "outlined", OUTLINED }, 494 { "plot", PLOT }, 495 { "print", PRINT }, 496 { "rad", RADIUS }, 497 { "radius", RADIUS }, 498 { "rand", RAND }, 499 { "reset", RESET }, 500 { "right", RIGHT }, 501 { "rjust", RJUST }, 502 { "same", SAME }, 503 { "sh", SH }, 504 { "shaded", SHADED }, 505 { "sin", SIN }, 506 { "solid", SOLID }, 507 { "south", SOUTH }, 508 { "spline", SPLINE }, 509 { "sprintf", SPRINTF }, 510 { "sqrt", SQRT }, 511 { "srand", SRAND }, 512 { "start", START }, 513 { "the", THE }, 514 { "then", THEN }, 515 { "thick", THICKNESS }, 516 { "thickness", THICKNESS }, 517 { "thru", THRU }, 518 { "to", TO }, 519 { "top", TOP }, 520 { "undef", UNDEF }, 521 { "until", UNTIL }, 522 { "up", UP }, 523 { "upper", UPPER }, 524 { "way", WAY }, 525 { "west", WEST }, 526 { "wid", WIDTH }, 527 { "width", WIDTH }, 528 { "with", WITH }, 529 }; 530 531 const keyword *start = table; 532 const keyword *end = table + sizeof(table)/sizeof(table[0]); 533 while (start < end) { 534 // start <= target < end 535 const keyword *mid = start + (end - start)/2; 536 537 int cmp = docmp(str, len, mid->name, strlen(mid->name)); 538 if (cmp == 0) 539 return mid->token; 540 if (cmp < 0) 541 end = mid; 542 else 543 start = mid + 1; 544 } 545 return 0; 546} 547 548int get_token_after_dot(int c) 549{ 550 // get_token deals with the case where c is a digit 551 switch (c) { 552 case 'h': 553 input_stack::get_char(); 554 c = input_stack::peek_char(); 555 if (c == 't') { 556 input_stack::get_char(); 557 context_buffer = ".ht"; 558 return DOT_HT; 559 } 560 else if (c == 'e') { 561 input_stack::get_char(); 562 c = input_stack::peek_char(); 563 if (c == 'i') { 564 input_stack::get_char(); 565 c = input_stack::peek_char(); 566 if (c == 'g') { 567 input_stack::get_char(); 568 c = input_stack::peek_char(); 569 if (c == 'h') { 570 input_stack::get_char(); 571 c = input_stack::peek_char(); 572 if (c == 't') { 573 input_stack::get_char(); 574 context_buffer = ".height"; 575 return DOT_HT; 576 } 577 input_stack::push_back('h'); 578 } 579 input_stack::push_back('g'); 580 } 581 input_stack::push_back('i'); 582 } 583 input_stack::push_back('e'); 584 } 585 input_stack::push_back('h'); 586 return '.'; 587 case 'x': 588 input_stack::get_char(); 589 context_buffer = ".x"; 590 return DOT_X; 591 case 'y': 592 input_stack::get_char(); 593 context_buffer = ".y"; 594 return DOT_Y; 595 case 'c': 596 input_stack::get_char(); 597 c = input_stack::peek_char(); 598 if (c == 'e') { 599 input_stack::get_char(); 600 c = input_stack::peek_char(); 601 if (c == 'n') { 602 input_stack::get_char(); 603 c = input_stack::peek_char(); 604 if (c == 't') { 605 input_stack::get_char(); 606 c = input_stack::peek_char(); 607 if (c == 'e') { 608 input_stack::get_char(); 609 c = input_stack::peek_char(); 610 if (c == 'r') { 611 input_stack::get_char(); 612 context_buffer = ".center"; 613 return DOT_C; 614 } 615 input_stack::push_back('e'); 616 } 617 input_stack::push_back('t'); 618 } 619 input_stack::push_back('n'); 620 } 621 input_stack::push_back('e'); 622 } 623 context_buffer = ".c"; 624 return DOT_C; 625 case 'n': 626 input_stack::get_char(); 627 c = input_stack::peek_char(); 628 if (c == 'e') { 629 input_stack::get_char(); 630 context_buffer = ".ne"; 631 return DOT_NE; 632 } 633 else if (c == 'w') { 634 input_stack::get_char(); 635 context_buffer = ".nw"; 636 return DOT_NW; 637 } 638 else { 639 context_buffer = ".n"; 640 return DOT_N; 641 } 642 break; 643 case 'e': 644 input_stack::get_char(); 645 c = input_stack::peek_char(); 646 if (c == 'n') { 647 input_stack::get_char(); 648 c = input_stack::peek_char(); 649 if (c == 'd') { 650 input_stack::get_char(); 651 context_buffer = ".end"; 652 return DOT_END; 653 } 654 input_stack::push_back('n'); 655 context_buffer = ".e"; 656 return DOT_E; 657 } 658 context_buffer = ".e"; 659 return DOT_E; 660 case 'w': 661 input_stack::get_char(); 662 c = input_stack::peek_char(); 663 if (c == 'i') { 664 input_stack::get_char(); 665 c = input_stack::peek_char(); 666 if (c == 'd') { 667 input_stack::get_char(); 668 c = input_stack::peek_char(); 669 if (c == 't') { 670 input_stack::get_char(); 671 c = input_stack::peek_char(); 672 if (c == 'h') { 673 input_stack::get_char(); 674 context_buffer = ".width"; 675 return DOT_WID; 676 } 677 input_stack::push_back('t'); 678 } 679 context_buffer = ".wid"; 680 return DOT_WID; 681 } 682 input_stack::push_back('i'); 683 } 684 context_buffer = ".w"; 685 return DOT_W; 686 case 's': 687 input_stack::get_char(); 688 c = input_stack::peek_char(); 689 if (c == 'e') { 690 input_stack::get_char(); 691 context_buffer = ".se"; 692 return DOT_SE; 693 } 694 else if (c == 'w') { 695 input_stack::get_char(); 696 context_buffer = ".sw"; 697 return DOT_SW; 698 } 699 else { 700 if (c == 't') { 701 input_stack::get_char(); 702 c = input_stack::peek_char(); 703 if (c == 'a') { 704 input_stack::get_char(); 705 c = input_stack::peek_char(); 706 if (c == 'r') { 707 input_stack::get_char(); 708 c = input_stack::peek_char(); 709 if (c == 't') { 710 input_stack::get_char(); 711 context_buffer = ".start"; 712 return DOT_START; 713 } 714 input_stack::push_back('r'); 715 } 716 input_stack::push_back('a'); 717 } 718 input_stack::push_back('t'); 719 } 720 context_buffer = ".s"; 721 return DOT_S; 722 } 723 break; 724 case 't': 725 input_stack::get_char(); 726 c = input_stack::peek_char(); 727 if (c == 'o') { 728 input_stack::get_char(); 729 c = input_stack::peek_char(); 730 if (c == 'p') { 731 input_stack::get_char(); 732 context_buffer = ".top"; 733 return DOT_N; 734 } 735 input_stack::push_back('o'); 736 } 737 context_buffer = ".t"; 738 return DOT_N; 739 case 'l': 740 input_stack::get_char(); 741 c = input_stack::peek_char(); 742 if (c == 'e') { 743 input_stack::get_char(); 744 c = input_stack::peek_char(); 745 if (c == 'f') { 746 input_stack::get_char(); 747 c = input_stack::peek_char(); 748 if (c == 't') { 749 input_stack::get_char(); 750 context_buffer = ".left"; 751 return DOT_W; 752 } 753 input_stack::push_back('f'); 754 } 755 input_stack::push_back('e'); 756 } 757 context_buffer = ".l"; 758 return DOT_W; 759 case 'r': 760 input_stack::get_char(); 761 c = input_stack::peek_char(); 762 if (c == 'a') { 763 input_stack::get_char(); 764 c = input_stack::peek_char(); 765 if (c == 'd') { 766 input_stack::get_char(); 767 context_buffer = ".rad"; 768 return DOT_RAD; 769 } 770 input_stack::push_back('a'); 771 } 772 else if (c == 'i') { 773 input_stack::get_char(); 774 c = input_stack::peek_char(); 775 if (c == 'g') { 776 input_stack::get_char(); 777 c = input_stack::peek_char(); 778 if (c == 'h') { 779 input_stack::get_char(); 780 c = input_stack::peek_char(); 781 if (c == 't') { 782 input_stack::get_char(); 783 context_buffer = ".right"; 784 return DOT_E; 785 } 786 input_stack::push_back('h'); 787 } 788 input_stack::push_back('g'); 789 } 790 input_stack::push_back('i'); 791 } 792 context_buffer = ".r"; 793 return DOT_E; 794 case 'b': 795 input_stack::get_char(); 796 c = input_stack::peek_char(); 797 if (c == 'o') { 798 input_stack::get_char(); 799 c = input_stack::peek_char(); 800 if (c == 't') { 801 input_stack::get_char(); 802 c = input_stack::peek_char(); 803 if (c == 't') { 804 input_stack::get_char(); 805 c = input_stack::peek_char(); 806 if (c == 'o') { 807 input_stack::get_char(); 808 c = input_stack::peek_char(); 809 if (c == 'm') { 810 input_stack::get_char(); 811 context_buffer = ".bottom"; 812 return DOT_S; 813 } 814 input_stack::push_back('o'); 815 } 816 input_stack::push_back('t'); 817 } 818 context_buffer = ".bot"; 819 return DOT_S; 820 } 821 input_stack::push_back('o'); 822 } 823 context_buffer = ".b"; 824 return DOT_S; 825 default: 826 context_buffer = '.'; 827 return '.'; 828 } 829} 830 831int get_token(int lookup_flag) 832{ 833 context_buffer.clear(); 834 for (;;) { 835 int n = 0; 836 int bol = input_stack::bol(); 837 int c = input_stack::get_char(); 838 if (bol && c == command_char) { 839 token_buffer.clear(); 840 token_buffer += c; 841 // the newline is not part of the token 842 for (;;) { 843 c = input_stack::peek_char(); 844 if (c == EOF || c == '\n') 845 break; 846 input_stack::get_char(); 847 token_buffer += char(c); 848 } 849 context_buffer = token_buffer; 850 return COMMAND_LINE; 851 } 852 switch (c) { 853 case EOF: 854 return EOF; 855 case ' ': 856 case '\t': 857 break; 858 case '\\': 859 { 860 int d = input_stack::peek_char(); 861 if (d != '\n') { 862 context_buffer = '\\'; 863 return '\\'; 864 } 865 input_stack::get_char(); 866 break; 867 } 868 case '#': 869 do { 870 c = input_stack::get_char(); 871 } while (c != '\n' && c != EOF); 872 if (c == '\n') 873 context_buffer = '\n'; 874 return c; 875 case '"': 876 context_buffer = '"'; 877 token_buffer.clear(); 878 for (;;) { 879 c = input_stack::get_char(); 880 if (c == '\\') { 881 context_buffer += '\\'; 882 c = input_stack::peek_char(); 883 if (c == '"') { 884 input_stack::get_char(); 885 token_buffer += '"'; 886 context_buffer += '"'; 887 } 888 else 889 token_buffer += '\\'; 890 } 891 else if (c == '\n') { 892 error("newline in string"); 893 break; 894 } 895 else if (c == EOF) { 896 error("missing `\"'"); 897 break; 898 } 899 else if (c == '"') { 900 context_buffer += '"'; 901 break; 902 } 903 else { 904 context_buffer += char(c); 905 token_buffer += char(c); 906 } 907 } 908 return TEXT; 909 case '0': 910 case '1': 911 case '2': 912 case '3': 913 case '4': 914 case '5': 915 case '6': 916 case '7': 917 case '8': 918 case '9': 919 { 920 int overflow = 0; 921 n = 0; 922 for (;;) { 923 if (n > (INT_MAX - 9)/10) { 924 overflow = 1; 925 break; 926 } 927 n *= 10; 928 n += c - '0'; 929 context_buffer += char(c); 930 c = input_stack::peek_char(); 931 if (c == EOF || !csdigit(c)) 932 break; 933 c = input_stack::get_char(); 934 } 935 token_double = n; 936 if (overflow) { 937 for (;;) { 938 token_double *= 10.0; 939 token_double += c - '0'; 940 context_buffer += char(c); 941 c = input_stack::peek_char(); 942 if (c == EOF || !csdigit(c)) 943 break; 944 c = input_stack::get_char(); 945 } 946 // if somebody asks for 1000000000000th, we will silently 947 // give them INT_MAXth 948 double temp = token_double; // work around gas 1.34/sparc bug 949 if (token_double > INT_MAX) 950 n = INT_MAX; 951 else 952 n = int(temp); 953 } 954 } 955 switch (c) { 956 case 'i': 957 case 'I': 958 context_buffer += char(c); 959 input_stack::get_char(); 960 return NUMBER; 961 case '.': 962 { 963 context_buffer += '.'; 964 input_stack::get_char(); 965 got_dot: 966 double factor = 1.0; 967 for (;;) { 968 c = input_stack::peek_char(); 969 if (c == EOF || !csdigit(c)) 970 break; 971 input_stack::get_char(); 972 context_buffer += char(c); 973 factor /= 10.0; 974 if (c != '0') 975 token_double += factor*(c - '0'); 976 } 977 if (c != 'e' && c != 'E') { 978 if (c == 'i' || c == 'I') { 979 context_buffer += char(c); 980 input_stack::get_char(); 981 } 982 return NUMBER; 983 } 984 } 985 // fall through 986 case 'e': 987 case 'E': 988 { 989 int echar = c; 990 input_stack::get_char(); 991 c = input_stack::peek_char(); 992 int sign = '+'; 993 if (c == '+' || c == '-') { 994 sign = c; 995 input_stack::get_char(); 996 c = input_stack::peek_char(); 997 if (c == EOF || !csdigit(c)) { 998 input_stack::push_back(sign); 999 input_stack::push_back(echar); 1000 return NUMBER; 1001 } 1002 context_buffer += char(echar); 1003 context_buffer += char(sign); 1004 } 1005 else { 1006 if (c == EOF || !csdigit(c)) { 1007 input_stack::push_back(echar); 1008 return NUMBER; 1009 } 1010 context_buffer += char(echar); 1011 } 1012 input_stack::get_char(); 1013 context_buffer += char(c); 1014 n = c - '0'; 1015 for (;;) { 1016 c = input_stack::peek_char(); 1017 if (c == EOF || !csdigit(c)) 1018 break; 1019 input_stack::get_char(); 1020 context_buffer += char(c); 1021 n = n*10 + (c - '0'); 1022 } 1023 if (sign == '-') 1024 n = -n; 1025 if (c == 'i' || c == 'I') { 1026 context_buffer += char(c); 1027 input_stack::get_char(); 1028 } 1029 token_double *= pow(10.0, n); 1030 return NUMBER; 1031 } 1032 case 'n': 1033 input_stack::get_char(); 1034 c = input_stack::peek_char(); 1035 if (c == 'd') { 1036 input_stack::get_char(); 1037 token_int = n; 1038 context_buffer += "nd"; 1039 return ORDINAL; 1040 } 1041 input_stack::push_back('n'); 1042 return NUMBER; 1043 case 'r': 1044 input_stack::get_char(); 1045 c = input_stack::peek_char(); 1046 if (c == 'd') { 1047 input_stack::get_char(); 1048 token_int = n; 1049 context_buffer += "rd"; 1050 return ORDINAL; 1051 } 1052 input_stack::push_back('r'); 1053 return NUMBER; 1054 case 't': 1055 input_stack::get_char(); 1056 c = input_stack::peek_char(); 1057 if (c == 'h') { 1058 input_stack::get_char(); 1059 token_int = n; 1060 context_buffer += "th"; 1061 return ORDINAL; 1062 } 1063 input_stack::push_back('t'); 1064 return NUMBER; 1065 case 's': 1066 input_stack::get_char(); 1067 c = input_stack::peek_char(); 1068 if (c == 't') { 1069 input_stack::get_char(); 1070 token_int = n; 1071 context_buffer += "st"; 1072 return ORDINAL; 1073 } 1074 input_stack::push_back('s'); 1075 return NUMBER; 1076 default: 1077 return NUMBER; 1078 } 1079 break; 1080 case '\'': 1081 { 1082 c = input_stack::peek_char(); 1083 if (c == 't') { 1084 input_stack::get_char(); 1085 c = input_stack::peek_char(); 1086 if (c == 'h') { 1087 input_stack::get_char(); 1088 context_buffer = "'th"; 1089 return TH; 1090 } 1091 else 1092 input_stack::push_back('t'); 1093 } 1094 context_buffer = "'"; 1095 return '\''; 1096 } 1097 case '.': 1098 { 1099 c = input_stack::peek_char(); 1100 if (c != EOF && csdigit(c)) { 1101 n = 0; 1102 token_double = 0.0; 1103 context_buffer = '.'; 1104 goto got_dot; 1105 } 1106 return get_token_after_dot(c); 1107 } 1108 case '<': 1109 c = input_stack::peek_char(); 1110 if (c == '-') { 1111 input_stack::get_char(); 1112 c = input_stack::peek_char(); 1113 if (c == '>') { 1114 input_stack::get_char(); 1115 context_buffer = "<->"; 1116 return DOUBLE_ARROW_HEAD; 1117 } 1118 context_buffer = "<-"; 1119 return LEFT_ARROW_HEAD; 1120 } 1121 else if (c == '=') { 1122 input_stack::get_char(); 1123 context_buffer = "<="; 1124 return LESSEQUAL; 1125 } 1126 context_buffer = "<"; 1127 return '<'; 1128 case '-': 1129 c = input_stack::peek_char(); 1130 if (c == '>') { 1131 input_stack::get_char(); 1132 context_buffer = "->"; 1133 return RIGHT_ARROW_HEAD; 1134 } 1135 context_buffer = "-"; 1136 return '-'; 1137 case '!': 1138 c = input_stack::peek_char(); 1139 if (c == '=') { 1140 input_stack::get_char(); 1141 context_buffer = "!="; 1142 return NOTEQUAL; 1143 } 1144 context_buffer = "!"; 1145 return '!'; 1146 case '>': 1147 c = input_stack::peek_char(); 1148 if (c == '=') { 1149 input_stack::get_char(); 1150 context_buffer = ">="; 1151 return GREATEREQUAL; 1152 } 1153 context_buffer = ">"; 1154 return '>'; 1155 case '=': 1156 c = input_stack::peek_char(); 1157 if (c == '=') { 1158 input_stack::get_char(); 1159 context_buffer = "=="; 1160 return EQUALEQUAL; 1161 } 1162 context_buffer = "="; 1163 return '='; 1164 case '&': 1165 c = input_stack::peek_char(); 1166 if (c == '&') { 1167 input_stack::get_char(); 1168 context_buffer = "&&"; 1169 return ANDAND; 1170 } 1171 context_buffer = "&"; 1172 return '&'; 1173 case '|': 1174 c = input_stack::peek_char(); 1175 if (c == '|') { 1176 input_stack::get_char(); 1177 context_buffer = "||"; 1178 return OROR; 1179 } 1180 context_buffer = "|"; 1181 return '|'; 1182 default: 1183 if (c != EOF && csalpha(c)) { 1184 token_buffer.clear(); 1185 token_buffer = c; 1186 for (;;) { 1187 c = input_stack::peek_char(); 1188 if (c == EOF || (!csalnum(c) && c != '_')) 1189 break; 1190 input_stack::get_char(); 1191 token_buffer += char(c); 1192 } 1193 int tok = lookup_keyword(token_buffer.contents(), 1194 token_buffer.length()); 1195 if (tok != 0) { 1196 context_buffer = token_buffer; 1197 return tok; 1198 } 1199 char *def = 0; 1200 if (lookup_flag) { 1201 token_buffer += '\0'; 1202 def = macro_table.lookup(token_buffer.contents()); 1203 token_buffer.set_length(token_buffer.length() - 1); 1204 if (def) { 1205 if (c == '(') { 1206 input_stack::get_char(); 1207 interpolate_macro_with_args(def); 1208 } 1209 else 1210 input_stack::push(new macro_input(def)); 1211 } 1212 } 1213 if (!def) { 1214 context_buffer = token_buffer; 1215 if (csupper(token_buffer[0])) 1216 return LABEL; 1217 else 1218 return VARIABLE; 1219 } 1220 } 1221 else { 1222 context_buffer = char(c); 1223 return (unsigned char)c; 1224 } 1225 break; 1226 } 1227 } 1228} 1229 1230int get_delimited() 1231{ 1232 token_buffer.clear(); 1233 int c = input_stack::get_char(); 1234 while (c == ' ' || c == '\t' || c == '\n') 1235 c = input_stack::get_char(); 1236 if (c == EOF) { 1237 lex_error("missing delimiter"); 1238 return 0; 1239 } 1240 context_buffer = char(c); 1241 int had_newline = 0; 1242 int start = c; 1243 int level = 0; 1244 enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL; 1245 for (;;) { 1246 c = input_stack::get_char(); 1247 if (c == EOF) { 1248 lex_error("missing closing delimiter"); 1249 return 0; 1250 } 1251 if (c == '\n') 1252 had_newline = 1; 1253 else if (!had_newline) 1254 context_buffer += char(c); 1255 switch (state) { 1256 case NORMAL: 1257 if (start == '{') { 1258 if (c == '{') { 1259 level++; 1260 break; 1261 } 1262 if (c == '}') { 1263 if (--level < 0) 1264 state = DELIM_END; 1265 break; 1266 } 1267 } 1268 else { 1269 if (c == start) { 1270 state = DELIM_END; 1271 break; 1272 } 1273 } 1274 if (c == '"') 1275 state = IN_STRING; 1276 break; 1277 case IN_STRING_QUOTED: 1278 if (c == '\n') 1279 state = NORMAL; 1280 else 1281 state = IN_STRING; 1282 break; 1283 case IN_STRING: 1284 if (c == '"' || c == '\n') 1285 state = NORMAL; 1286 else if (c == '\\') 1287 state = IN_STRING_QUOTED; 1288 break; 1289 case DELIM_END: 1290 // This case it just to shut cfront 2.0 up. 1291 default: 1292 assert(0); 1293 } 1294 if (state == DELIM_END) 1295 break; 1296 token_buffer += c; 1297 } 1298 return 1; 1299} 1300 1301void do_define() 1302{ 1303 int t = get_token(0); // do not expand what we are defining 1304 if (t != VARIABLE && t != LABEL) { 1305 lex_error("can only define variable or placename"); 1306 return; 1307 } 1308 token_buffer += '\0'; 1309 string nm = token_buffer; 1310 const char *name = nm.contents(); 1311 if (!get_delimited()) 1312 return; 1313 token_buffer += '\0'; 1314 macro_table.define(name, strsave(token_buffer.contents())); 1315} 1316 1317void do_undef() 1318{ 1319 int t = get_token(0); // do not expand what we are undefining 1320 if (t != VARIABLE && t != LABEL) { 1321 lex_error("can only define variable or placename"); 1322 return; 1323 } 1324 token_buffer += '\0'; 1325 macro_table.define(token_buffer.contents(), 0); 1326} 1327 1328 1329class for_input : public input { 1330 char *var; 1331 char *body; 1332 double from; 1333 double to; 1334 int by_is_multiplicative; 1335 double by; 1336 const char *p; 1337 int done_newline; 1338public: 1339 for_input(char *, double, double, int, double, char *); 1340 ~for_input(); 1341 int get(); 1342 int peek(); 1343}; 1344 1345for_input::for_input(char *vr, double f, double t, 1346 int bim, double b, char *bd) 1347: var(vr), body(bd), from(f), to(t), by_is_multiplicative(bim), by(b), 1348 p(body), done_newline(0) 1349{ 1350} 1351 1352for_input::~for_input() 1353{ 1354 a_delete var; 1355 a_delete body; 1356} 1357 1358int for_input::get() 1359{ 1360 if (p == 0) 1361 return EOF; 1362 for (;;) { 1363 if (*p != '\0') 1364 return (unsigned char)*p++; 1365 if (!done_newline) { 1366 done_newline = 1; 1367 return '\n'; 1368 } 1369 double val; 1370 if (!lookup_variable(var, &val)) { 1371 lex_error("body of `for' terminated enclosing block"); 1372 return EOF; 1373 } 1374 if (by_is_multiplicative) 1375 val *= by; 1376 else 1377 val += by; 1378 define_variable(var, val); 1379 if ((from <= to && val > to) 1380 || (from >= to && val < to)) { 1381 p = 0; 1382 return EOF; 1383 } 1384 p = body; 1385 done_newline = 0; 1386 } 1387} 1388 1389int for_input::peek() 1390{ 1391 if (p == 0) 1392 return EOF; 1393 if (*p != '\0') 1394 return (unsigned char)*p; 1395 if (!done_newline) 1396 return '\n'; 1397 double val; 1398 if (!lookup_variable(var, &val)) 1399 return EOF; 1400 if (by_is_multiplicative) { 1401 if (val * by > to) 1402 return EOF; 1403 } 1404 else { 1405 if ((from <= to && val + by > to) 1406 || (from >= to && val + by < to)) 1407 return EOF; 1408 } 1409 if (*body == '\0') 1410 return EOF; 1411 return (unsigned char)*body; 1412} 1413 1414void do_for(char *var, double from, double to, int by_is_multiplicative, 1415 double by, char *body) 1416{ 1417 define_variable(var, from); 1418 if ((by_is_multiplicative && by <= 0) 1419 || (by > 0 && from > to) 1420 || (by < 0 && from < to)) 1421 return; 1422 input_stack::push(new for_input(var, from, to, 1423 by_is_multiplicative, by, body)); 1424} 1425 1426 1427void do_copy(const char *filename) 1428{ 1429 errno = 0; 1430 FILE *fp = fopen(filename, "r"); 1431 if (fp == 0) { 1432 lex_error("can't open `%1': %2", filename, strerror(errno)); 1433 return; 1434 } 1435 input_stack::push(new file_input(fp, filename)); 1436} 1437 1438class copy_thru_input : public input { 1439 int done; 1440 char *body; 1441 char *until; 1442 const char *p; 1443 const char *ap; 1444 int argv[9]; 1445 int argc; 1446 string line; 1447 int get_line(); 1448 virtual int inget() = 0; 1449public: 1450 copy_thru_input(const char *b, const char *u); 1451 ~copy_thru_input(); 1452 int get(); 1453 int peek(); 1454}; 1455 1456class copy_file_thru_input : public copy_thru_input { 1457 input *in; 1458public: 1459 copy_file_thru_input(input *, const char *b, const char *u); 1460 ~copy_file_thru_input(); 1461 int inget(); 1462}; 1463 1464copy_file_thru_input::copy_file_thru_input(input *i, const char *b, 1465 const char *u) 1466: copy_thru_input(b, u), in(i) 1467{ 1468} 1469 1470copy_file_thru_input::~copy_file_thru_input() 1471{ 1472 delete in; 1473} 1474 1475int copy_file_thru_input::inget() 1476{ 1477 if (!in) 1478 return EOF; 1479 else 1480 return in->get(); 1481} 1482 1483class copy_rest_thru_input : public copy_thru_input { 1484public: 1485 copy_rest_thru_input(const char *, const char *u); 1486 int inget(); 1487}; 1488 1489copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u) 1490: copy_thru_input(b, u) 1491{ 1492} 1493 1494int copy_rest_thru_input::inget() 1495{ 1496 while (next != 0) { 1497 int c = next->get(); 1498 if (c != EOF) 1499 return c; 1500 if (next->next == 0) 1501 return EOF; 1502 input *tem = next; 1503 next = next->next; 1504 delete tem; 1505 } 1506 return EOF; 1507 1508} 1509 1510copy_thru_input::copy_thru_input(const char *b, const char *u) 1511: done(0) 1512{ 1513 ap = 0; 1514 body = process_body(b); 1515 p = 0; 1516 until = strsave(u); 1517} 1518 1519 1520copy_thru_input::~copy_thru_input() 1521{ 1522 a_delete body; 1523 a_delete until; 1524} 1525 1526int copy_thru_input::get() 1527{ 1528 if (ap) { 1529 if (*ap != '\0') 1530 return (unsigned char)*ap++; 1531 ap = 0; 1532 } 1533 for (;;) { 1534 if (p == 0) { 1535 if (!get_line()) 1536 break; 1537 p = body; 1538 } 1539 if (*p == '\0') { 1540 p = 0; 1541 return '\n'; 1542 } 1543 while (*p >= ARG1 && *p <= ARG1 + 8) { 1544 int i = *p++ - ARG1; 1545 if (i < argc && line[argv[i]] != '\0') { 1546 ap = line.contents() + argv[i]; 1547 return (unsigned char)*ap++; 1548 } 1549 } 1550 if (*p != '\0') 1551 return (unsigned char)*p++; 1552 } 1553 return EOF; 1554} 1555 1556int copy_thru_input::peek() 1557{ 1558 if (ap) { 1559 if (*ap != '\0') 1560 return (unsigned char)*ap; 1561 ap = 0; 1562 } 1563 for (;;) { 1564 if (p == 0) { 1565 if (!get_line()) 1566 break; 1567 p = body; 1568 } 1569 if (*p == '\0') 1570 return '\n'; 1571 while (*p >= ARG1 && *p <= ARG1 + 8) { 1572 int i = *p++ - ARG1; 1573 if (i < argc && line[argv[i]] != '\0') { 1574 ap = line.contents() + argv[i]; 1575 return (unsigned char)*ap; 1576 } 1577 } 1578 if (*p != '\0') 1579 return (unsigned char)*p; 1580 } 1581 return EOF; 1582} 1583 1584int copy_thru_input::get_line() 1585{ 1586 if (done) 1587 return 0; 1588 line.clear(); 1589 argc = 0; 1590 int c = inget(); 1591 for (;;) { 1592 while (c == ' ') 1593 c = inget(); 1594 if (c == EOF || c == '\n') 1595 break; 1596 if (argc == 9) { 1597 do { 1598 c = inget(); 1599 } while (c != '\n' && c != EOF); 1600 break; 1601 } 1602 argv[argc++] = line.length(); 1603 do { 1604 line += char(c); 1605 c = inget(); 1606 } while (c != ' ' && c != '\n'); 1607 line += '\0'; 1608 } 1609 if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) { 1610 done = 1; 1611 return 0; 1612 } 1613 return argc > 0 || c == '\n'; 1614} 1615 1616class simple_file_input : public input { 1617 const char *filename; 1618 int lineno; 1619 FILE *fp; 1620public: 1621 simple_file_input(FILE *, const char *); 1622 ~simple_file_input(); 1623 int get(); 1624 int peek(); 1625 int get_location(const char **, int *); 1626}; 1627 1628simple_file_input::simple_file_input(FILE *p, const char *s) 1629: filename(s), lineno(1), fp(p) 1630{ 1631} 1632 1633simple_file_input::~simple_file_input() 1634{ 1635 // don't delete the filename 1636 fclose(fp); 1637} 1638 1639int simple_file_input::get() 1640{ 1641 int c = getc(fp); 1642 while (invalid_input_char(c)) { 1643 error("invalid input character code %1", c); 1644 c = getc(fp); 1645 } 1646 if (c == '\n') 1647 lineno++; 1648 return c; 1649} 1650 1651int simple_file_input::peek() 1652{ 1653 int c = getc(fp); 1654 while (invalid_input_char(c)) { 1655 error("invalid input character code %1", c); 1656 c = getc(fp); 1657 } 1658 if (c != EOF) 1659 ungetc(c, fp); 1660 return c; 1661} 1662 1663int simple_file_input::get_location(const char **fnp, int *lnp) 1664{ 1665 *fnp = filename; 1666 *lnp = lineno; 1667 return 1; 1668} 1669 1670 1671void copy_file_thru(const char *filename, const char *body, const char *until) 1672{ 1673 errno = 0; 1674 FILE *fp = fopen(filename, "r"); 1675 if (fp == 0) { 1676 lex_error("can't open `%1': %2", filename, strerror(errno)); 1677 return; 1678 } 1679 input *in = new copy_file_thru_input(new simple_file_input(fp, filename), 1680 body, until); 1681 input_stack::push(in); 1682} 1683 1684void copy_rest_thru(const char *body, const char *until) 1685{ 1686 input_stack::push(new copy_rest_thru_input(body, until)); 1687} 1688 1689void push_body(const char *s) 1690{ 1691 input_stack::push(new char_input('\n')); 1692 input_stack::push(new macro_input(s)); 1693} 1694 1695int delim_flag = 0; 1696 1697char *get_thru_arg() 1698{ 1699 int c = input_stack::peek_char(); 1700 while (c == ' ') { 1701 input_stack::get_char(); 1702 c = input_stack::peek_char(); 1703 } 1704 if (c != EOF && csalpha(c)) { 1705 // looks like a macro 1706 input_stack::get_char(); 1707 token_buffer = c; 1708 for (;;) { 1709 c = input_stack::peek_char(); 1710 if (c == EOF || (!csalnum(c) && c != '_')) 1711 break; 1712 input_stack::get_char(); 1713 token_buffer += char(c); 1714 } 1715 context_buffer = token_buffer; 1716 token_buffer += '\0'; 1717 char *def = macro_table.lookup(token_buffer.contents()); 1718 if (def) 1719 return strsave(def); 1720 // I guess it wasn't a macro after all; so push the macro name back. 1721 // -2 because we added a '\0' 1722 for (int i = token_buffer.length() - 2; i >= 0; i--) 1723 input_stack::push_back(token_buffer[i]); 1724 } 1725 if (get_delimited()) { 1726 token_buffer += '\0'; 1727 return strsave(token_buffer.contents()); 1728 } 1729 else 1730 return 0; 1731} 1732 1733int lookahead_token = -1; 1734string old_context_buffer; 1735 1736void do_lookahead() 1737{ 1738 if (lookahead_token == -1) { 1739 old_context_buffer = context_buffer; 1740 lookahead_token = get_token(1); 1741 } 1742} 1743 1744int yylex() 1745{ 1746 if (delim_flag) { 1747 assert(lookahead_token == -1); 1748 if (delim_flag == 2) { 1749 if ((yylval.str = get_thru_arg()) != 0) 1750 return DELIMITED; 1751 else 1752 return 0; 1753 } 1754 else { 1755 if (get_delimited()) { 1756 token_buffer += '\0'; 1757 yylval.str = strsave(token_buffer.contents()); 1758 return DELIMITED; 1759 } 1760 else 1761 return 0; 1762 } 1763 } 1764 for (;;) { 1765 int t; 1766 if (lookahead_token >= 0) { 1767 t = lookahead_token; 1768 lookahead_token = -1; 1769 } 1770 else 1771 t = get_token(1); 1772 switch (t) { 1773 case '\n': 1774 return ';'; 1775 case EOF: 1776 return 0; 1777 case DEFINE: 1778 do_define(); 1779 break; 1780 case UNDEF: 1781 do_undef(); 1782 break; 1783 case ORDINAL: 1784 yylval.n = token_int; 1785 return t; 1786 case NUMBER: 1787 yylval.x = token_double; 1788 return t; 1789 case COMMAND_LINE: 1790 case TEXT: 1791 token_buffer += '\0'; 1792 if (!input_stack::get_location(&yylval.lstr.filename, 1793 &yylval.lstr.lineno)) { 1794 yylval.lstr.filename = 0; 1795 yylval.lstr.lineno = -1; 1796 } 1797 yylval.lstr.str = strsave(token_buffer.contents()); 1798 return t; 1799 case LABEL: 1800 case VARIABLE: 1801 token_buffer += '\0'; 1802 yylval.str = strsave(token_buffer.contents()); 1803 return t; 1804 case LEFT: 1805 // change LEFT to LEFT_CORNER when followed by OF 1806 old_context_buffer = context_buffer; 1807 lookahead_token = get_token(1); 1808 if (lookahead_token == OF) 1809 return LEFT_CORNER; 1810 else 1811 return t; 1812 case RIGHT: 1813 // change RIGHT to RIGHT_CORNER when followed by OF 1814 old_context_buffer = context_buffer; 1815 lookahead_token = get_token(1); 1816 if (lookahead_token == OF) 1817 return RIGHT_CORNER; 1818 else 1819 return t; 1820 case UPPER: 1821 // recognise UPPER only before LEFT or RIGHT 1822 old_context_buffer = context_buffer; 1823 lookahead_token = get_token(1); 1824 if (lookahead_token != LEFT && lookahead_token != RIGHT) { 1825 yylval.str = strsave("upper"); 1826 return VARIABLE; 1827 } 1828 else 1829 return t; 1830 case LOWER: 1831 // recognise LOWER only before LEFT or RIGHT 1832 old_context_buffer = context_buffer; 1833 lookahead_token = get_token(1); 1834 if (lookahead_token != LEFT && lookahead_token != RIGHT) { 1835 yylval.str = strsave("lower"); 1836 return VARIABLE; 1837 } 1838 else 1839 return t; 1840 case NORTH: 1841 // recognise NORTH only before OF 1842 old_context_buffer = context_buffer; 1843 lookahead_token = get_token(1); 1844 if (lookahead_token != OF) { 1845 yylval.str = strsave("north"); 1846 return VARIABLE; 1847 } 1848 else 1849 return t; 1850 case SOUTH: 1851 // recognise SOUTH only before OF 1852 old_context_buffer = context_buffer; 1853 lookahead_token = get_token(1); 1854 if (lookahead_token != OF) { 1855 yylval.str = strsave("south"); 1856 return VARIABLE; 1857 } 1858 else 1859 return t; 1860 case EAST: 1861 // recognise EAST only before OF 1862 old_context_buffer = context_buffer; 1863 lookahead_token = get_token(1); 1864 if (lookahead_token != OF) { 1865 yylval.str = strsave("east"); 1866 return VARIABLE; 1867 } 1868 else 1869 return t; 1870 case WEST: 1871 // recognise WEST only before OF 1872 old_context_buffer = context_buffer; 1873 lookahead_token = get_token(1); 1874 if (lookahead_token != OF) { 1875 yylval.str = strsave("west"); 1876 return VARIABLE; 1877 } 1878 else 1879 return t; 1880 case TOP: 1881 // recognise TOP only before OF 1882 old_context_buffer = context_buffer; 1883 lookahead_token = get_token(1); 1884 if (lookahead_token != OF) { 1885 yylval.str = strsave("top"); 1886 return VARIABLE; 1887 } 1888 else 1889 return t; 1890 case BOTTOM: 1891 // recognise BOTTOM only before OF 1892 old_context_buffer = context_buffer; 1893 lookahead_token = get_token(1); 1894 if (lookahead_token != OF) { 1895 yylval.str = strsave("bottom"); 1896 return VARIABLE; 1897 } 1898 else 1899 return t; 1900 case CENTER: 1901 // recognise CENTER only before OF 1902 old_context_buffer = context_buffer; 1903 lookahead_token = get_token(1); 1904 if (lookahead_token != OF) { 1905 yylval.str = strsave("center"); 1906 return VARIABLE; 1907 } 1908 else 1909 return t; 1910 case START: 1911 // recognise START only before OF 1912 old_context_buffer = context_buffer; 1913 lookahead_token = get_token(1); 1914 if (lookahead_token != OF) { 1915 yylval.str = strsave("start"); 1916 return VARIABLE; 1917 } 1918 else 1919 return t; 1920 case END: 1921 // recognise END only before OF 1922 old_context_buffer = context_buffer; 1923 lookahead_token = get_token(1); 1924 if (lookahead_token != OF) { 1925 yylval.str = strsave("end"); 1926 return VARIABLE; 1927 } 1928 else 1929 return t; 1930 default: 1931 return t; 1932 } 1933 } 1934} 1935 1936void lex_error(const char *message, 1937 const errarg &arg1, 1938 const errarg &arg2, 1939 const errarg &arg3) 1940{ 1941 const char *filename; 1942 int lineno; 1943 if (!input_stack::get_location(&filename, &lineno)) 1944 error(message, arg1, arg2, arg3); 1945 else 1946 error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); 1947} 1948 1949void lex_warning(const char *message, 1950 const errarg &arg1, 1951 const errarg &arg2, 1952 const errarg &arg3) 1953{ 1954 const char *filename; 1955 int lineno; 1956 if (!input_stack::get_location(&filename, &lineno)) 1957 warning(message, arg1, arg2, arg3); 1958 else 1959 warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3); 1960} 1961 1962void yyerror(const char *s) 1963{ 1964 const char *filename; 1965 int lineno; 1966 const char *context = 0; 1967 if (lookahead_token == -1) { 1968 if (context_buffer.length() > 0) { 1969 context_buffer += '\0'; 1970 context = context_buffer.contents(); 1971 } 1972 } 1973 else { 1974 if (old_context_buffer.length() > 0) { 1975 old_context_buffer += '\0'; 1976 context = old_context_buffer.contents(); 1977 } 1978 } 1979 if (!input_stack::get_location(&filename, &lineno)) { 1980 if (context) { 1981 if (context[0] == '\n' && context[1] == '\0') 1982 error("%1 before newline", s); 1983 else 1984 error("%1 before `%2'", s, context); 1985 } 1986 else 1987 error("%1 at end of picture", s); 1988 } 1989 else { 1990 if (context) { 1991 if (context[0] == '\n' && context[1] == '\0') 1992 error_with_file_and_line(filename, lineno, "%1 before newline", s); 1993 else 1994 error_with_file_and_line(filename, lineno, "%1 before `%2'", 1995 s, context); 1996 } 1997 else 1998 error_with_file_and_line(filename, lineno, "%1 at end of picture", s); 1999 } 2000} 2001 2002