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