home *** CD-ROM | disk | FTP | other *** search
- // -*- C++ -*-
- /* Copyright (C) 1989, 1990 Free Software Foundation, Inc.
- Written by James Clark (jjc@jclark.uucp)
-
- This file is part of groff.
-
- groff is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 1, or (at your option) any later
- version.
-
- groff is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
-
- You should have received a copy of the GNU General Public License along
- with groff; see the file LICENSE. If not, write to the Free Software
- Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "pic.h"
- #include "ptable.h"
- #include "object.h"
- #include "pic.tab.h"
- #include "key.h"
-
- declare_ptable(char)
- implement_ptable(char)
-
- PTABLE(char) macro_table;
-
- class macro_input : public input {
- char *s;
- char *p;
- public:
- macro_input(const char *);
- ~macro_input();
- int get();
- int peek();
- };
-
- class argument_macro_input : public input {
- char *s;
- char *p;
- char *ap;
- int argc;
- char *argv[9];
- public:
- argument_macro_input(const char *, int, char **);
- ~argument_macro_input();
- int get();
- int peek();
- };
-
- input::input() : next(0)
- {
- }
-
- input::~input()
- {
- }
-
- int input::get_location(const char **, int *)
- {
- return 0;
- }
-
- file_input::file_input(FILE *f, const char *fn)
- : lineno(0), ptr(""), filename(fn)
- {
- fp = f;
- }
-
- file_input::~file_input()
- {
- fclose(fp);
- }
-
- int file_input::read_line()
- {
- for (;;) {
- line.clear();
- lineno++;
- for (;;) {
- int c = getc(fp);
- if (c == EOF)
- break;
- else if (illegal_input_char(c))
- lex_error("illegal input character code %1", c);
- else {
- line += char(c);
- if (c == '\n')
- break;
- }
- }
- if (line.length() == 0)
- return 0;
- if (!(line.length() >= 3 && line[0] == '.' && line[1] == 'P'
- && (line[2] == 'S' || line[2] == 'E' || line[2] == 'F')
- && (line.length() == 3 || line[3] == ' ' || line[3] == '\n'
- || compatible_flag))) {
- line += '\0';
- ptr = line.contents();
- return 1;
- }
- }
- }
-
- int file_input::get()
- {
- if (*ptr != '\0' || read_line())
- return (unsigned char)*ptr++;
- else
- return EOF;
- }
-
- int file_input::peek()
- {
- if (*ptr != '\0' || read_line())
- return (unsigned char)*ptr;
- else
- return EOF;
- }
-
- int file_input::get_location(const char **fnp, int *lnp)
- {
- *fnp = filename;
- *lnp = lineno;
- return 1;
- }
-
- macro_input::macro_input(const char *str)
- {
- p = s = strsave(str);
- }
-
- macro_input::~macro_input()
- {
- delete s;
- }
-
- int macro_input::get()
- {
- if (p == 0 || *p == '\0')
- return EOF;
- else
- return (unsigned char)*p++;
- }
-
- int macro_input::peek()
- {
- if (p == 0 || *p == '\0')
- return EOF;
- else
- return (unsigned char)*p;
- }
-
- #define ARG1 11
-
- char *process_body(const char *body)
- {
- char *s = strsave(body);
- int j = 0;
- for (int i = 0; s[i] != '\0'; i++)
- if (s[i] == '$' && s[i+1] >= '0' && s[i+1] <= '9') {
- if (s[i+1] != '0')
- s[j++] = ARG1 + s[++i] - '1';
- }
- else
- s[j++] = s[i];
- s[j] = '\0';
- return s;
- }
-
-
- argument_macro_input::argument_macro_input(const char *body, int ac, char **av)
- : argc(ac), ap(0)
- {
- for (int i = 0; i < argc; i++)
- argv[i] = av[i];
- p = s = process_body(body);
- }
-
-
- argument_macro_input::~argument_macro_input()
- {
- for (int i = 0; i < argc; i++)
- delete argv[i];
- delete s;
- }
-
- int argument_macro_input::get()
- {
- if (ap) {
- if (*ap != '\0')
- return (unsigned char)*ap++;
- ap = 0;
- }
- if (p == 0)
- return EOF;
- while (*p >= ARG1 && *p <= ARG1 + 8) {
- int i = *p++ - ARG1;
- if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
- ap = argv[i];
- return (unsigned char)*ap++;
- }
- }
- if (*p == '\0')
- return EOF;
- return (unsigned char)*p++;
- }
-
- int argument_macro_input::peek()
- {
- if (ap) {
- if (*ap != '\0')
- return (unsigned char)*ap;
- ap = 0;
- }
- if (p == 0)
- return EOF;
- while (*p >= ARG1 && *p <= ARG1 + 8) {
- int i = *p++ - ARG1;
- if (i < argc && argv[i] != 0 && argv[i][0] != '\0') {
- ap = argv[i];
- return (unsigned char)*ap;
- }
- }
- if (*p == '\0')
- return EOF;
- return (unsigned char)*p;
- }
-
- class input_stack {
- static input *current_input;
- static int bol_flag;
- public:
- static void push(input *);
- static void clear();
- static int get_char();
- static int peek_char();
- static int get_location(const char **fnp, int *lnp);
- static void push_back(unsigned char c, int was_bol = 0);
- static inline int bol() { return bol_flag; }
- };
-
- input *input_stack::current_input = 0;
- int input_stack::bol_flag = 0;
-
- void input_stack::clear()
- {
- while (current_input != 0) {
- input *tem = current_input;
- current_input = current_input->next;
- delete tem;
- }
- bol_flag = 1;
- }
-
- void input_stack::push(input *in)
- {
- in->next = current_input;
- current_input = in;
- }
-
- void lex_init(input *top)
- {
- input_stack::clear();
- input_stack::push(top);
- }
-
- void lex_cleanup()
- {
- while (input_stack::get_char() != EOF)
- ;
- }
-
- int input_stack::get_char()
- {
- while (current_input != 0) {
- int c = current_input->get();
- if (c != EOF) {
- bol_flag = c == '\n';
- return c;
- }
- // don't pop the top-level input off the stack
- if (current_input->next == 0)
- return EOF;
- input *tem = current_input;
- current_input = current_input->next;
- delete tem;
- }
- return EOF;
- }
-
- int input_stack::peek_char()
- {
- while (current_input != 0) {
- int c = current_input->peek();
- if (c != EOF)
- return c;
- if (current_input->next == 0)
- return EOF;
- input *tem = current_input;
- current_input = current_input->next;
- delete tem;
- }
- return EOF;
- }
-
- class char_input : public input {
- int c;
- public:
- char_input(int);
- int get();
- int peek();
- };
-
- char_input::char_input(int n) : c((unsigned char)n)
- {
- }
-
- int char_input::get()
- {
- int n = c;
- c = EOF;
- return n;
- }
-
- int char_input::peek()
- {
- return c;
- }
-
- void input_stack::push_back(unsigned char c, int was_bol)
- {
- push(new char_input(c));
- bol_flag = was_bol;
- }
-
- int input_stack::get_location(const char **fnp, int *lnp)
- {
- for (input *p = current_input; p; p = p->next)
- if (p->get_location(fnp, lnp))
- return 1;
- return 0;
- }
-
- string context_buffer;
-
- string token_buffer;
- double token_double;
- int token_int;
-
- void interpolate_macro_with_args(const char *body)
- {
- char *argv[9];
- int argc = 0;
- for (int i = 0; i < 9; i++)
- argv[i] = 0;
- int level = 0;
- int c;
- do {
- token_buffer.clear();
- for (;;) {
- c = input_stack::get_char();
- if (c == EOF) {
- lex_error("end of input while scanning macro arguments");
- break;
- }
- if (level == 0 && (c == ',' || c == ')')) {
- if (token_buffer.length() > 0) {
- token_buffer += '\0';
- argv[argc] = strsave(token_buffer.contents());
- }
- // for `foo()', argc = 0
- if (argc > 0 || c != ')' || i > 0)
- argc++;
- break;
- }
- token_buffer += char(c);
- if (c == '(')
- level++;
- else if (c == ')')
- level--;
- }
- } while (c != ')' && c != EOF);
- input_stack::push(new argument_macro_input(body, argc, argv));
- }
-
- int get_token_after_dot(int c)
- {
- // get_token deals with the case where c is a digit
- switch (c) {
- case 'h':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- context_buffer = ".ht";
- return DOT_HT;
- }
- else if (c == 'e') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'i') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'g') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'h') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- context_buffer = ".height";
- return DOT_HT;
- }
- input_stack::push_back('h');
- }
- input_stack::push_back('g');
- }
- input_stack::push_back('i');
- }
- input_stack::push_back('e');
- }
- input_stack::push_back('h');
- return '.';
- case 'x':
- input_stack::get_char();
- context_buffer = ".x";
- return DOT_X;
- case 'y':
- input_stack::get_char();
- context_buffer = ".y";
- return DOT_Y;
- case 'c':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'e') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'n') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'e') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'r') {
- input_stack::get_char();
- context_buffer = ".center";
- return DOT_C;
- }
- input_stack::push_back('e');
- }
- input_stack::push_back('t');
- }
- input_stack::push_back('n');
- }
- input_stack::push_back('e');
- }
- context_buffer = ".c";
- return DOT_C;
- case 'n':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'e') {
- input_stack::get_char();
- context_buffer = ".ne";
- return DOT_NE;
- }
- else if (c == 'w') {
- input_stack::get_char();
- context_buffer = ".nw";
- return DOT_NW;
- }
- else {
- context_buffer = ".n";
- return DOT_N;
- }
- break;
- case 'e':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'n') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'd') {
- input_stack::get_char();
- context_buffer = ".end";
- return DOT_END;
- }
- input_stack::push_back('n');
- context_buffer = ".e";
- return DOT_E;
- }
- context_buffer = ".e";
- return DOT_E;
- case 'w':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'i') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'd') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'h') {
- input_stack::get_char();
- context_buffer = ".width";
- return DOT_WID;
- }
- input_stack::push_back('t');
- }
- context_buffer = ".wid";
- return DOT_WID;
- }
- input_stack::push_back('i');
- }
- context_buffer = ".w";
- return DOT_W;
- case 's':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'e') {
- input_stack::get_char();
- context_buffer = ".se";
- return DOT_SE;
- }
- else if (c == 'w') {
- input_stack::get_char();
- context_buffer = ".sw";
- return DOT_SW;
- }
- else {
- if (c == 't') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'a') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'r') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- context_buffer = ".start";
- return DOT_START;
- }
- input_stack::push_back('r');
- }
- input_stack::push_back('a');
- }
- input_stack::push_back('t');
- }
- context_buffer = ".s";
- return DOT_S;
- }
- break;
- case 't':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'o') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'p') {
- input_stack::get_char();
- context_buffer = ".top";
- return DOT_N;
- }
- input_stack::push_back('o');
- }
- context_buffer = ".t";
- return DOT_N;
- case 'l':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'e') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'f') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- context_buffer = ".left";
- }
- input_stack::push_back('f');
- }
- input_stack::push_back('e');
- }
- context_buffer = ".l";
- return DOT_W;
- case 'r':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'a') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'd') {
- input_stack::get_char();
- context_buffer = ".rad";
- return DOT_RAD;
- }
- input_stack::push_back('a');
- }
- else if (c == 'i') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'g') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'h') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- context_buffer = ".right";
- }
- input_stack::push_back('h');
- }
- input_stack::push_back('g');
- }
- input_stack::push_back('i');
- }
- context_buffer = ".r";
- return DOT_E;
- case 'b':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'o') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'o') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'm') {
- input_stack::get_char();
- context_buffer = ".bottom";
- return DOT_S;
- }
- input_stack::push_back('o');
- }
- input_stack::push_back('t');
- }
- context_buffer = ".bot";
- return DOT_S;
- }
- input_stack::push_back('o');
- }
- context_buffer = ".b";
- return DOT_S;
- default:
- context_buffer = '.';
- return '.';
- }
- }
-
- int get_token(int lookup_flag)
- {
- context_buffer.clear();
- for (;;) {
- int n = 0;
- int bol = input_stack::bol();
- int c = input_stack::get_char();
- if (bol && c == command_char) {
- token_buffer.clear();
- token_buffer += c;
- // the newline is not part of the token
- for (;;) {
- c = input_stack::peek_char();
- if (c == EOF || c == '\n')
- break;
- input_stack::get_char();
- token_buffer += char(c);
- }
- context_buffer = token_buffer;
- return COMMAND;
- }
- switch (c) {
- case EOF:
- return EOF;
- case ' ':
- case '\t':
- break;
- case '\\':
- {
- int d = input_stack::peek_char();
- if (d != '\n') {
- context_buffer = '\\';
- return '\\';
- }
- input_stack::get_char();
- break;
- }
- case '#':
- do {
- c = input_stack::get_char();
- } while (c != '\n' && c != EOF);
- if (c == '\n')
- context_buffer = '\n';
- return c;
- case '"':
- context_buffer = '"';
- token_buffer.clear();
- for (;;) {
- c = input_stack::get_char();
- if (c == '\\') {
- context_buffer += '\\';
- c = input_stack::peek_char();
- if (c == '"') {
- input_stack::get_char();
- token_buffer += '"';
- context_buffer += '"';
- }
- else
- token_buffer += '\\';
- }
- else if (c == '\n') {
- error("newline in string");
- break;
- }
- else if (c == EOF) {
- error("missing `\"'");
- break;
- }
- else if (c == '"') {
- context_buffer += '"';
- break;
- }
- else {
- context_buffer += char(c);
- token_buffer += char(c);
- }
- }
- return TEXT;
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7':
- case '8':
- case '9':
- {
- int overflow = 0;
- n = 0;
- for (;;) {
- if (n > (INT_MAX - 9)/10) {
- overflow = 1;
- break;
- }
- n *= 10;
- n += c - '0';
- context_buffer += char(c);
- c = input_stack::peek_char();
- if (c == EOF || !csdigit(c))
- break;
- c = input_stack::get_char();
- }
- token_double = n;
- if (overflow) {
- for (;;) {
- token_double *= 10.0;
- token_double += c - '0';
- context_buffer += char(c);
- c = input_stack::peek_char();
- if (c == EOF || !csdigit(c))
- break;
- c = input_stack::get_char();
- }
- // if somebody asks for 1000000000000th, we will silently
- // give them INT_MAXth
- double temp = token_double; // work around gas 1.34/sparc bug
- if (token_double > INT_MAX)
- n = INT_MAX;
- else
- n = int(temp);
- }
- }
- switch (c) {
- case 'i':
- case 'I':
- context_buffer += char(c);
- input_stack::get_char();
- return NUMBER;
- case '.':
- {
- context_buffer += '.';
- input_stack::get_char();
- got_dot:
- double factor = 1.0;
- for (;;) {
- c = input_stack::peek_char();
- if (!c == EOF || !csdigit(c))
- break;
- input_stack::get_char();
- context_buffer += char(c);
- factor /= 10.0;
- if (c != '0')
- token_double += factor*(c - '0');
- }
- if (c != 'e' && c != 'E') {
- if (c == 'i' || c == 'I') {
- context_buffer += char(c);
- input_stack::get_char();
- }
- return NUMBER;
- }
- }
- // fall through
- case 'e':
- case 'E':
- {
- int echar = c;
- input_stack::get_char();
- c = input_stack::peek_char();
- int sign = '+';
- if (c == '+' || c == '-') {
- sign = c;
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == EOF || !csdigit(c)) {
- input_stack::push_back(sign);
- input_stack::push_back(echar);
- return NUMBER;
- }
- context_buffer += char(echar);
- context_buffer += char(sign);
- }
- else {
- if (c == EOF || !csdigit(c)) {
- input_stack::push_back(echar);
- return NUMBER;
- }
- context_buffer += char(echar);
- }
- input_stack::get_char();
- context_buffer += char(c);
- n = c - '0';
- for (;;) {
- c = input_stack::peek_char();
- if (c == EOF || !csdigit(c))
- break;
- input_stack::get_char();
- context_buffer += char(c);
- n = n*10 + (c - '0');
- }
- if (sign == '-')
- n = -n;
- if (c == 'i' || c == 'I') {
- context_buffer += char(c);
- input_stack::get_char();
- }
- token_double *= pow(10.0, n);
- return NUMBER;
- }
- case 'n':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'd') {
- input_stack::get_char();
- token_int = n;
- context_buffer += "nd";
- return ORDINAL;
- }
- input_stack::push_back('n');
- return NUMBER;
- case 'r':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'd') {
- input_stack::get_char();
- token_int = n;
- context_buffer += "rd";
- return ORDINAL;
- }
- input_stack::push_back('r');
- return NUMBER;
- case 't':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 'h') {
- input_stack::get_char();
- token_int = n;
- context_buffer += "th";
- return ORDINAL;
- }
- input_stack::push_back('t');
- return NUMBER;
- case 's':
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == 't') {
- input_stack::get_char();
- token_int = n;
- context_buffer += "st";
- return ORDINAL;
- }
- input_stack::push_back('s');
- return NUMBER;
- default:
- return NUMBER;
- }
- break;
- case '.':
- {
- c = input_stack::peek_char();
- if (c != EOF && csdigit(c)) {
- n = 0;
- token_double = 0.0;
- context_buffer = '.';
- goto got_dot;
- }
- return get_token_after_dot(c);
- }
- case '<':
- c = input_stack::peek_char();
- if (c == '-') {
- input_stack::get_char();
- c = input_stack::peek_char();
- if (c == '>') {
- input_stack::get_char();
- context_buffer = "<->";
- return DOUBLE_ARROW_HEAD;
- }
- context_buffer = "<-";
- return LEFT_ARROW_HEAD;
- }
- else if (c == '=') {
- input_stack::get_char();
- context_buffer = "<=";
- return LESSEQUAL;
- }
- context_buffer = "<";
- return '<';
- case '-':
- c = input_stack::peek_char();
- if (c == '>') {
- input_stack::get_char();
- context_buffer = "->";
- return RIGHT_ARROW_HEAD;
- }
- context_buffer = "-";
- return '-';
- case '!':
- c = input_stack::peek_char();
- if (c == '=') {
- input_stack::get_char();
- context_buffer = "!=";
- return NOTEQUAL;
- }
- context_buffer = "!";
- return '!';
- case '>':
- c = input_stack::peek_char();
- if (c == '=') {
- input_stack::get_char();
- context_buffer = ">=";
- return GREATEREQUAL;
- }
- context_buffer = ">";
- return '>';
- case '=':
- c = input_stack::peek_char();
- if (c == '=') {
- input_stack::get_char();
- context_buffer = "==";
- return EQUALEQUAL;
- }
- context_buffer = "=";
- return '=';
- case '&':
- c = input_stack::peek_char();
- if (c == '&') {
- input_stack::get_char();
- context_buffer = "&&";
- return ANDAND;
- }
- context_buffer = "&";
- return '&';
- case '|':
- c = input_stack::peek_char();
- if (c == '|') {
- input_stack::get_char();
- context_buffer = "||";
- return OROR;
- }
- context_buffer = "|";
- return '|';
- default:
- if (c != EOF && csalpha(c)) {
- token_buffer.clear();
- token_buffer = c;
- for (;;) {
- c = input_stack::peek_char();
- if (c == EOF || (!csalnum(c) && c != '_'))
- break;
- input_stack::get_char();
- token_buffer += char(c);
- }
- const keyword *ky = lookup_keyword(token_buffer.contents(),
- token_buffer.length());
- if (ky != 0) {
- context_buffer = token_buffer;
- return ky->token;
- }
- char *def = 0;
- if (lookup_flag) {
- token_buffer += '\0';
- def = macro_table.lookup(token_buffer.contents());
- token_buffer.set_length(token_buffer.length() - 1);
- if (def) {
- if (c == '(') {
- input_stack::get_char();
- interpolate_macro_with_args(def);
- }
- else
- input_stack::push(new macro_input(def));
- }
- }
- if (!def) {
- context_buffer = token_buffer;
- if (csupper(token_buffer[0]))
- return LABEL;
- else
- return VARIABLE;
- }
- }
- else {
- context_buffer = char(c);
- return (unsigned char)c;
- }
- break;
- }
- }
- }
-
- int get_delimited()
- {
- token_buffer.clear();
- int c = input_stack::get_char();
- while (c == ' ' || c == '\n')
- c = input_stack::get_char();
- if (c == EOF) {
- lex_error("missing delimiter");
- return 0;
- }
- context_buffer = char(c);
- int had_newline = 0;
- int start = c;
- int level = 0;
- enum { NORMAL, IN_STRING, IN_STRING_QUOTED, DELIM_END } state = NORMAL;
- for (;;) {
- c = input_stack::get_char();
- if (c == EOF) {
- lex_error("missing closing delimiter");
- return 0;
- }
- if (c == '\n')
- had_newline = 1;
- else if (!had_newline)
- context_buffer += char(c);
- switch (state) {
- case NORMAL:
- if (start == '{') {
- if (c == '{') {
- level++;
- break;
- }
- if (c == '}') {
- if (--level < 0)
- state = DELIM_END;
- break;
- }
- }
- else {
- if (c == start) {
- state = DELIM_END;
- break;
- }
- }
- if (c == '"')
- state = IN_STRING;
- break;
- case IN_STRING_QUOTED:
- if (c == '\n')
- state = NORMAL;
- else
- state = IN_STRING;
- break;
- case IN_STRING:
- if (c == '"' || c == '\n')
- state = NORMAL;
- else if (c == '\\')
- state = IN_STRING_QUOTED;
- break;
- case DELIM_END:
- // This case it just to shut cfront 2.0 up.
- default:
- assert(0);
- }
- if (state == DELIM_END)
- break;
- token_buffer += c;
- }
- return 1;
- }
-
- void do_define()
- {
- int t = get_token(0); // do not expand what we are defining
- if (t != VARIABLE && t != LABEL) {
- lex_error("can only define variable or placename");
- return;
- }
- token_buffer += '\0';
- string nm = token_buffer;
- if (!get_delimited())
- return;
- token_buffer += '\0';
- macro_table.define(nm.contents(), strsave(token_buffer.contents()));
- }
-
- void do_undef()
- {
- int t = get_token(0); // do not expand what we are undefining
- if (t != VARIABLE && t != LABEL) {
- lex_error("can only define variable or placename");
- return;
- }
- token_buffer += '\0';
- macro_table.define(token_buffer.contents(), 0);
- }
-
-
- class for_input : public input {
- char *var;
- char *body;
- double to;
- int by_is_multiplicative;
- double by;
- const char *p;
- int done_newline;
- public:
- for_input(char *, double, int, double, char *);
- ~for_input();
- int get();
- int peek();
- };
-
- for_input::for_input(char *vr, double t, int bim, double b, char *bd)
- : var(vr), to(t), by_is_multiplicative(bim), by(b), body(bd), p(body),
- done_newline(0)
- {
- }
-
- for_input::~for_input()
- {
- delete var;
- delete body;
- }
-
- int for_input::get()
- {
- if (p == 0)
- return EOF;
- for (;;) {
- if (*p != '\0')
- return (unsigned char)*p++;
- if (!done_newline) {
- done_newline = 1;
- return '\n';
- }
- double val;
- if (!lookup_variable(var, &val)) {
- lex_error("body of `for' terminated enclosing block");
- return EOF;
- }
- if (by_is_multiplicative)
- val *= by;
- else
- val += by;
- define_variable(var, val);
- if (val > to) {
- p = 0;
- return EOF;
- }
- p = body;
- done_newline = 0;
- }
- }
-
- int for_input::peek()
- {
- if (p == 0)
- return EOF;
- if (*p != '\0')
- return (unsigned char)*p;
- if (!done_newline)
- return '\n';
- double val;
- if (!lookup_variable(var, &val))
- return EOF;
- if (by_is_multiplicative) {
- if (val * by > to)
- return EOF;
- }
- else {
- if (val + by > to)
- return EOF;
- }
- if (*body == '\0')
- return EOF;
- return (unsigned char)*body;
- }
-
- void do_for(char *var, double from, double to, int by_is_multiplicative,
- double by, char *body)
- {
- define_variable(var, from);
- if (from <= to)
- input_stack::push(new for_input(var, to, by_is_multiplicative, by, body));
- }
-
-
- void do_copy(const char *filename)
- {
- FILE *fp = fopen(filename, "r");
- if (fp == 0) {
- lex_error("can't open `%1': %2", filename, strerror(errno));
- return;
- }
- input_stack::push(new file_input(fp, filename));
- }
-
- class copy_thru_input : public input {
- int done;
- char *body;
- char *until;
- const char *p;
- const char *ap;
- int argv[9];
- int argc;
- string line;
- int get_line();
- virtual int inget() = 0;
- public:
- copy_thru_input(const char *b, const char *u);
- ~copy_thru_input();
- int get();
- int peek();
- };
-
- class copy_file_thru_input : public copy_thru_input {
- input *in;
- public:
- copy_file_thru_input(input *, const char *b, const char *u);
- ~copy_file_thru_input();
- int inget();
- };
-
- copy_file_thru_input::copy_file_thru_input(input *i, const char *b,
- const char *u)
- : in(i), copy_thru_input(b, u)
- {
- }
-
- copy_file_thru_input::~copy_file_thru_input()
- {
- delete in;
- }
-
- int copy_file_thru_input::inget()
- {
- if (!in)
- return EOF;
- else
- return in->get();
- }
-
- class copy_rest_thru_input : public copy_thru_input {
- public:
- copy_rest_thru_input(const char *, const char *u);
- int inget();
- };
-
- copy_rest_thru_input::copy_rest_thru_input(const char *b, const char *u)
- : copy_thru_input(b, u)
- {
- }
-
- int copy_rest_thru_input::inget()
- {
- while (next != 0) {
- int c = next->get();
- if (c != EOF)
- return c;
- if (next->next == 0)
- return EOF;
- input *tem = next;
- next = next->next;
- delete tem;
- }
- return EOF;
-
- }
-
- copy_thru_input::copy_thru_input(const char *b, const char *u)
- : done(0)
- {
- ap = 0;
- body = process_body(b);
- p = 0;
- until = strsave(u);
- }
-
-
- copy_thru_input::~copy_thru_input()
- {
- delete body;
- delete until;
- }
-
- int copy_thru_input::get()
- {
- if (ap) {
- if (*ap != '\0')
- return (unsigned char)*ap++;
- ap = 0;
- }
- for (;;) {
- if (p == 0) {
- if (!get_line())
- break;
- p = body;
- }
- if (*p == '\0') {
- p = 0;
- return '\n';
- }
- while (*p >= ARG1 && *p <= ARG1 + 8) {
- int i = *p++ - ARG1;
- if (i < argc && line[argv[i]] != '\0') {
- ap = line.contents() + argv[i];
- return (unsigned char)*ap++;
- }
- }
- if (*p != '\0')
- return (unsigned char)*p++;
- }
- return EOF;
- }
-
- int copy_thru_input::peek()
- {
- if (ap) {
- if (*ap != '\0')
- return (unsigned char)*ap;
- ap = 0;
- }
- for (;;) {
- if (p == 0) {
- if (!get_line())
- break;
- p = body;
- }
- if (*p == '\0')
- return '\n';
- while (*p >= ARG1 && *p <= ARG1 + 8) {
- int i = *p++ - ARG1;
- if (i < argc && line[argv[i]] != '\0') {
- ap = line.contents() + argv[i];
- return (unsigned char)*ap;
- }
- }
- if (*p != '\0')
- return (unsigned char)*p;
- }
- return EOF;
- }
-
- int copy_thru_input::get_line()
- {
- if (done)
- return 0;
- line.clear();
- argc = 0;
- int c = inget();
- for (;;) {
- while (c == ' ')
- c = inget();
- if (c == EOF || c == '\n')
- break;
- if (argc == 9) {
- do {
- c = inget();
- } while (c != '\n' && c != EOF);
- break;
- }
- argv[argc++] = line.length();
- do {
- line += char(c);
- c = inget();
- } while (c != ' ' && c != '\n');
- line += '\0';
- }
- if (until != 0 && argc > 0 && strcmp(&line[argv[0]], until) == 0) {
- done = 1;
- return 0;
- }
- return argc > 0 || c == '\n';
- }
-
- class simple_file_input : public input {
- const char *filename;
- int lineno;
- FILE *fp;
- public:
- simple_file_input(FILE *, const char *);
- ~simple_file_input();
- int get();
- int peek();
- int get_location(const char **, int *);
- };
-
- simple_file_input::simple_file_input(FILE *p, const char *s)
- : filename(s), fp(p), lineno(1)
- {
- }
-
- simple_file_input::~simple_file_input()
- {
- // don't delete the filename
- fclose(fp);
- }
-
- int simple_file_input::get()
- {
- int c = getc(fp);
- while (illegal_input_char(c)) {
- error("illegal input character code %1", c);
- c = getc(fp);
- }
- if (c == '\n')
- lineno++;
- return c;
- }
-
- int simple_file_input::peek()
- {
- int c = getc(fp);
- while (illegal_input_char(c)) {
- error("illegal input character code %1", c);
- c = getc(fp);
- }
- if (c != EOF)
- ungetc(c, fp);
- return c;
- }
-
- int simple_file_input::get_location(const char **fnp, int *lnp)
- {
- *fnp = filename;
- *lnp = lineno;
- return 1;
- }
-
-
- void copy_file_thru(const char *filename, const char *body, const char *until)
- {
- FILE *fp = fopen(filename, "r");
- if (fp == 0) {
- lex_error("can't open `%1': %2", filename, strerror(errno));
- return;
- }
- input *in = new copy_file_thru_input(new simple_file_input(fp, filename),
- body, until);
- input_stack::push(in);
- }
-
- void copy_rest_thru(const char *body, const char *until)
- {
- input_stack::push(new copy_rest_thru_input(body, until));
- }
-
- void push_body(const char *s)
- {
- input_stack::push(new char_input('\n'));
- input_stack::push(new macro_input(s));
- }
-
- int delim_flag = 0;
-
- char *get_thru_arg()
- {
- int c = input_stack::peek_char();
- while (c == ' ') {
- input_stack::get_char();
- c = input_stack::peek_char();
- }
- if (c != EOF && csalpha(c)) {
- // looks like a macro
- input_stack::get_char();
- token_buffer = c;
- for (;;) {
- c = input_stack::peek_char();
- if (c == EOF || (!csalnum(c) && c != '_'))
- break;
- input_stack::get_char();
- token_buffer += char(c);
- }
- context_buffer = token_buffer;
- token_buffer += '\0';
- char *def = macro_table.lookup(token_buffer.contents());
- if (def)
- return strsave(def);
- // I guess it wasn't a macro after all; so push the macro name back.
- // -2 because we added a '\0'
- for (int i = token_buffer.length() - 2; i >= 0; i--)
- input_stack::push_back(token_buffer[i]);
- }
- if (get_delimited()) {
- token_buffer += '\0';
- return strsave(token_buffer.contents());
- }
- else
- return 0;
- }
-
- int lookahead_token = -1;
- string old_context_buffer;
-
- void do_lookahead()
- {
- if (lookahead_token == -1) {
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- }
- }
-
- int yylex()
- {
- if (delim_flag) {
- assert(lookahead_token == -1);
- if (delim_flag == 2) {
- if ((yylval.str = get_thru_arg()) != 0)
- return DELIMITED;
- else
- return 0;
- }
- else {
- if (get_delimited()) {
- token_buffer += '\0';
- yylval.str = strsave(token_buffer.contents());
- return DELIMITED;
- }
- else
- return 0;
- }
- }
- for (;;) {
- int t;
- if (lookahead_token >= 0) {
- t = lookahead_token;
- lookahead_token = -1;
- }
- else
- t = get_token(1);
- switch (t) {
- case '\n':
- return ';';
- case EOF:
- return 0;
- case DEFINE:
- do_define();
- break;
- case UNDEF:
- do_undef();
- break;
- case ORDINAL:
- yylval.n = token_int;
- return t;
- case NUMBER:
- yylval.x = token_double;
- return t;
- case COMMAND:
- case TEXT:
- token_buffer += '\0';
- if (!input_stack::get_location(&yylval.lstr.filename,
- &yylval.lstr.lineno)) {
- yylval.lstr.filename = 0;
- yylval.lstr.lineno = -1;
- }
- yylval.lstr.str = strsave(token_buffer.contents());
- return t;
- case LABEL:
- case VARIABLE:
- token_buffer += '\0';
- yylval.str = strsave(token_buffer.contents());
- return t;
- case LEFT:
- // change LEFT to LEFT_CORNER when followed by OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token == OF)
- return LEFT_CORNER;
- else
- return t;
- case RIGHT:
- // change RIGHT to RIGHT_CORNER when followed by OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token == OF)
- return RIGHT_CORNER;
- else
- return t;
- case UPPER:
- // recognise UPPER only before LEFT or RIGHT
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != LEFT && lookahead_token != RIGHT) {
- yylval.str = strsave("upper");
- return VARIABLE;
- }
- else
- return t;
- case LOWER:
- // recognise LOWER only before LEFT or RIGHT
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != LEFT && lookahead_token != RIGHT) {
- yylval.str = strsave("lower");
- return VARIABLE;
- }
- else
- return t;
- case TOP:
- // recognise TOP only before OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != OF) {
- yylval.str = strsave("top");
- return VARIABLE;
- }
- else
- return t;
- case BOTTOM:
- // recognise BOTTOM only before OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != OF) {
- yylval.str = strsave("bottom");
- return VARIABLE;
- }
- else
- return t;
- case CENTER:
- // recognise CENTER only before OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != OF) {
- yylval.str = strsave("center");
- return VARIABLE;
- }
- else
- return t;
- case START:
- // recognise START only before OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != OF) {
- yylval.str = strsave("start");
- return VARIABLE;
- }
- else
- return t;
- case END:
- // recognise END only before OF
- old_context_buffer = context_buffer;
- lookahead_token = get_token(1);
- if (lookahead_token != OF) {
- yylval.str = strsave("end");
- return VARIABLE;
- }
- else
- return t;
- default:
- return t;
- }
- }
- }
-
- void lex_error(const char *message,
- const errarg &arg1,
- const errarg &arg2,
- const errarg &arg3)
- {
- const char *filename;
- int lineno;
- if (!input_stack::get_location(&filename, &lineno))
- error(message, arg1, arg2, arg3);
- else
- error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
- }
-
- void lex_warning(const char *message,
- const errarg &arg1,
- const errarg &arg2,
- const errarg &arg3)
- {
- const char *filename;
- int lineno;
- if (!input_stack::get_location(&filename, &lineno))
- warning(message, arg1, arg2, arg3);
- else
- warning_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
- }
-
- void yyerror(const char *s)
- {
- const char *filename;
- int lineno;
- const char *context = 0;
- if (lookahead_token == -1) {
- if (context_buffer.length() > 0) {
- context_buffer += '\0';
- context = context_buffer.contents();
- }
- }
- else {
- if (old_context_buffer.length() > 0) {
- old_context_buffer += '\0';
- context = old_context_buffer.contents();
- }
- }
- if (!input_stack::get_location(&filename, &lineno)) {
- if (context) {
- if (context[0] == '\n' && context[1] == '\0')
- error("%1 before newline", s);
- else
- error("%1 before `%2'", s, context);
- }
- else
- error("%1 at end of picture", s);
- }
- else {
- if (context) {
- if (context[0] == '\n' && context[1] == '\0')
- error_with_file_and_line(filename, lineno, "%1 before newline", s);
- else
- error_with_file_and_line(filename, lineno, "%1 before `%2'",
- s, context);
- }
- else
- error_with_file_and_line(filename, lineno, "%1 at end of picture", s);
- }
- }
-
-