📄 lex.cc
字号:
// -*- C++ -*-/* Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. Written by James Clark (jjc@jclark.com)This file is part of groff.groff is free software; you can redistribute it and/or modify it underthe terms of the GNU General Public License as published by the FreeSoftware Foundation; either version 2, or (at your option) any laterversion.groff is distributed in the hope that it will be useful, but WITHOUT ANYWARRANTY; without even the implied warranty of MERCHANTABILITY orFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licensefor more details.You should have received a copy of the GNU General Public License alongwith groff; see the file COPYING. If not, write to the Free SoftwareFoundation, 675 Mass Ave, Cambridge, MA 02139, USA. */#include "pic.h"#include "ptable.h"#include "object.h"#include "pic.tab.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(){ a_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;}// Character respresenting $1. Must be illegal input character.#define ARG1 14char *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++) a_delete argv[i]; a_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 int bol();};input *input_stack::current_input = 0;int input_stack::bol_flag = 0;inline int input_stack::bol(){ return bol_flag;}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; enum { NORMAL, IN_STRING, IN_STRING_QUOTED } state = NORMAL; do { token_buffer.clear(); for (;;) { c = input_stack::get_char(); if (c == EOF) { lex_error("end of input while scanning macro arguments"); break; } if (state == NORMAL && 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); switch (state) { case NORMAL: if (c == '"') state = IN_STRING; else if (c == '(') level++; else if (c == ')') level--; break; case IN_STRING: if (c == '"') state = NORMAL; else if (c == '\\') state = IN_STRING_QUOTED; break; case IN_STRING_QUOTED: state = IN_STRING; break; } } } while (c != ')' && c != EOF); input_stack::push(new argument_macro_input(body, argc, argv));}static int docmp(const char *s1, int n1, const char *s2, int n2){ if (n1 < n2) { int r = memcmp(s1, s2, n1); return r ? r : -1; } else if (n1 > n2) { int r = memcmp(s1, s2, n2); return r ? r : 1; } else return memcmp(s1, s2, n1);}int lookup_keyword(const char *str, int len){ static struct keyword { const char *name; int token; } table[] = { "Here", HERE, "above", ABOVE, "aligned", ALIGNED, "and", AND, "arc", ARC, "arrow", ARROW, "at", AT, "atan2", ATAN2, "below", BELOW, "between", BETWEEN, "bottom", BOTTOM, "box", BOX, "by", BY, "ccw", CCW, "center", CENTER, "chop", CHOP, "circle", CIRCLE, "command", COMMAND, "copy", COPY, "cos", COS, "cw", CW, "dashed", DASHED, "define", DEFINE, "diam", DIAMETER, "diameter", DIAMETER, "do", DO, "dotted", DOTTED, "down", DOWN, "ellipse", ELLIPSE, "else", ELSE, "end", END, "exp", EXP, "fill", FILL, "filled", FILL, "for", FOR, "from", FROM, "height", HEIGHT, "ht", HEIGHT, "if", IF, "int", INT, "invis", INVISIBLE, "invisible", INVISIBLE, "last", LAST, "left", LEFT, "line", LINE, "ljust", LJUST, "log", LOG, "lower", LOWER, "max", K_MAX, "min", K_MIN, "move", MOVE, "of", OF, "plot", PLOT, "print", PRINT, "rad", RADIUS, "radius", RADIUS, "rand", RAND, "reset", RESET, "right", RIGHT, "rjust", RJUST, "same", SAME, "sh", SH, "sin", SIN, "spline", SPLINE, "sprintf", SPRINTF, "sqrt", SQRT, "start", START, "the", THE, "then", THEN, "thick", THICKNESS, "thickness", THICKNESS, "thru", THRU, "to", TO, "top", TOP, "undef", UNDEF, "until", UNTIL, "up", UP, "upper", UPPER, "way", WAY, "wid", WIDTH, "width", WIDTH, "with", WITH, }; const keyword *start = table; const keyword *end = table + sizeof(table)/sizeof(table[0]); while (start < end) { // start <= target < end const keyword *mid = start + (end - start)/2; int cmp = docmp(str, len, mid->name, strlen(mid->name)); if (cmp == 0) return mid->token; if (cmp < 0) end = mid; else start = mid + 1; } return 0;}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();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -