BSD 4_3_Net_2 development
[unix-history] / usr / src / usr.bin / groff / eqn / lex.cc
// -*- C++ -*-
/* Copyright (C) 1989, 1990, 1991 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 "eqn.h"
#include "eqn.tab.h"
#include "stringclass.h"
#include "ptable.h"
struct definition {
char is_macro;
char is_simple;
union {
int tok;
char *contents;
};
definition();
~definition();
};
definition::definition() : is_macro(1), contents(0), is_simple(0)
{
}
definition::~definition()
{
if (is_macro)
delete contents;
}
declare_ptable(definition)
implement_ptable(definition)
PTABLE(definition) macro_table;
static struct {
const char *name;
int token;
} token_table[] = {
"over", OVER,
"smallover", SMALLOVER,
"sqrt", SQRT,
"sub", SUB,
"sup", SUP,
"lpile", LPILE,
"rpile", RPILE,
"cpile", CPILE,
"pile", PILE,
"left", LEFT,
"right", RIGHT,
"to", TO,
"from", FROM,
"size", SIZE,
"font", FONT,
"roman", ROMAN,
"bold", BOLD,
"italic", ITALIC,
"fat", FAT,
"bar", BAR,
"under", UNDER,
"accent", ACCENT,
"uaccent", UACCENT,
"above", ABOVE,
"fwd", FWD,
"back", BACK,
"down", DOWN,
"up", UP,
"matrix", MATRIX,
"col", COL,
"lcol", LCOL,
"rcol", RCOL,
"ccol", CCOL,
"mark", MARK,
"lineup", LINEUP,
"space", SPACE,
"gfont", GFONT,
"gsize", GSIZE,
"define", DEFINE,
"sdefine", SDEFINE,
"ndefine", NDEFINE,
"tdefine", TDEFINE,
"undef", UNDEF,
"ifdef", IFDEF,
"include", INCLUDE,
"copy", INCLUDE,
"delim", DELIM,
"chartype", CHARTYPE,
"type", TYPE,
"vcenter", VCENTER,
"set", SET,
"opprime", PRIME,
"grfont", GRFONT,
"gbfont", GBFONT,
"split", SPLIT,
"nosplit", NOSPLIT,
};
static struct {
const char *name;
const char *def;
} def_table[] = {
"ALPHA", "\\(*A",
"BETA", "\\(*B",
"CHI", "\\(*X",
"DELTA", "\\(*D",
"EPSILON", "\\(*E",
"ETA", "\\(*Y",
"GAMMA", "\\(*G",
"IOTA", "\\(*I",
"KAPPA", "\\(*K",
"LAMBDA", "\\(*L",
"MU", "\\(*M",
"NU", "\\(*N",
"OMEGA", "\\(*W",
"OMICRON", "\\(*O",
"PHI", "\\(*F",
"PI", "\\(*P",
"PSI", "\\(*Q",
"RHO", "\\(*R",
"SIGMA", "\\(*S",
"TAU", "\\(*T",
"THETA", "\\(*H",
"UPSILON", "\\(*U",
"XI", "\\(*C",
"ZETA", "\\(*Z",
"Alpha", "\\(*A",
"Beta", "\\(*B",
"Chi", "\\(*X",
"Delta", "\\(*D",
"Epsilon", "\\(*E",
"Eta", "\\(*Y",
"Gamma", "\\(*G",
"Iota", "\\(*I",
"Kappa", "\\(*K",
"Lambda", "\\(*L",
"Mu", "\\(*M",
"Nu", "\\(*N",
"Omega", "\\(*W",
"Omicron", "\\(*O",
"Phi", "\\(*F",
"Pi", "\\(*P",
"Psi", "\\(*Q",
"Rho", "\\(*R",
"Sigma", "\\(*S",
"Tau", "\\(*T",
"Theta", "\\(*H",
"Upsilon", "\\(*U",
"Xi", "\\(*C",
"Zeta", "\\(*Z",
"alpha", "\\(*a",
"beta", "\\(*b",
"chi", "\\(*x",
"delta", "\\(*d",
"epsilon", "\\(*e",
"eta", "\\(*y",
"gamma", "\\(*g",
"iota", "\\(*i",
"kappa", "\\(*k",
"lambda", "\\(*l",
"mu", "\\(*m",
"nu", "\\(*n",
"omega", "\\(*w",
"omicron", "\\(*o",
"phi", "\\(*f",
"pi", "\\(*p",
"psi", "\\(*q",
"rho", "\\(*r",
"sigma", "\\(*s",
"tau", "\\(*t",
"theta", "\\(*h",
"upsilon", "\\(*u",
"xi", "\\(*c",
"zeta", "\\(*z",
"max", "{type \"operator\" roman \"max\"}",
"min", "{type \"operator\" roman \"min\"}",
"lim", "{type \"operator\" roman \"lim\"}",
"sin", "{type \"operator\" roman \"sin\"}",
"cos", "{type \"operator\" roman \"cos\"}",
"tan", "{type \"operator\" roman \"tan\"}",
"sinh", "{type \"operator\" roman \"sinh\"}",
"cosh", "{type \"operator\" roman \"cosh\"}",
"tanh", "{type \"operator\" roman \"tanh\"}",
"arc", "{type \"operator\" roman \"arc\"}",
"log", "{type \"operator\" roman \"log\"}",
"ln", "{type \"operator\" roman \"ln\"}",
"exp", "{type \"operator\" roman \"exp\"}",
"Re", "{type \"operator\" roman \"Re\"}",
"Im", "{type \"operator\" roman \"Im\"}",
"det", "{type \"operator\" roman \"det\"}",
"and", "{roman \"and\"}",
"if", "{roman \"if\"}",
"for", "{roman \"for\"}",
"sum", "{type \"operator\" vcenter size +5 \\(*S}",
"prod", "{type \"operator\" vcenter size +5 \\(*P}",
"int", "{type \"operator\" vcenter size +8 \\(is}",
"union", "{type \"operator\" vcenter size +5 \\(cu}",
"inter", "{type \"operator\" vcenter size +5 \\(ca}",
"times", "type \"binary\" \\(mu",
"ldots", "type \"inner\" { . . . }",
"inf", "\\(if",
"partial", "\\(pd",
"nothing", "\"\"",
"half", "{1 smallover 2}",
"hat_def", "\"^\"",
"hat", "accent { hat_def }",
"dot_def", "back 15 \"\\v'-52M'.\\v'52M'\"",
"dot", "accent { dot_def }",
"dotdot_def", "back 25 \"\\v'-52M'..\\v'52M'\"",
"dotdot", "accent { dotdot_def }",
"tilde_def", "\"~\"",
"tilde", "accent { tilde_def }",
"utilde_def", "\"\\v'75M'~\\v'-75M'\"",
"utilde", "uaccent { utilde_def }",
"vec_def", "up 52 size -5 \\(->",
"vec", "accent { vec_def }",
"dyad_def", "up 52 size -5 {\\(<- back 60 \\(->}",
"dyad", "accent { dyad_def }",
"==", "type \"relation\" \\(==",
"!=", "type \"relation\" \\(!=",
"+-", "type \"binary\" \\(+-",
"->", "type \"relation\" \\(->",
"<-", "type \"relation\" \\(<-",
"<<", "{ < back 20 < }",
">>", "{ > back 20 > }",
"...", "type \"inner\" vcenter { . . . }",
"prime", "'",
"approx", "type \"relation\" \"\\(~=\"",
"grad", "\\(gr",
"del", "\\(gr",
"cdot", "type \"binary\" vcenter ."
};
void init_table(const char *device)
{
for (int i = 0; i < sizeof(token_table)/sizeof(token_table[0]); i++) {
definition *def = new definition;
def->is_macro = 0;
def->tok = token_table[i].token;
macro_table.define(token_table[i].name, def);
}
for (i = 0; i < sizeof(def_table)/sizeof(def_table[0]); i++) {
definition *def = new definition;
def->is_macro = 1;
def->contents = strsave(def_table[i].def);
def->is_simple = 1;
macro_table.define(def_table[i].name, def);
}
definition *def = new definition;
def->is_macro = 1;
def->contents = strsave("1");
macro_table.define(device, def);
}
class input {
input *next;
public:
input(input *p);
virtual ~input();
virtual int get() = 0;
virtual int peek() = 0;
virtual int get_location(char **, int *);
friend int get_char();
friend int peek_char();
friend int get_location(char **, int *);
friend void init_lex(const char *str, const char *filename, int lineno);
};
class file_input : public input {
FILE *fp;
char *filename;
int lineno;
string line;
const char *ptr;
int read_line();
public:
file_input(FILE *, const char *, input *);
~file_input();
int get();
int peek();
int get_location(char **, int *);
};
class macro_input : public input {
char *s;
char *p;
public:
macro_input(const char *, input *);
~macro_input();
int get();
int peek();
};
class top_input : public macro_input {
char *filename;
int lineno;
public:
top_input(const char *, const char *, int, input *);
~top_input();
int get();
int get_location(char **, int *);
};
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 **, input *);
~argument_macro_input();
int get();
int peek();
};
input::input(input *x) : next(x)
{
}
input::~input()
{
}
int input::get_location(char **, int *)
{
return 0;
}
file_input::file_input(FILE *f, const char *fn, input *p)
: input(p), lineno(0), ptr("")
{
fp = f;
filename = strsave(fn);
}
file_input::~file_input()
{
delete filename;
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] == 'E'
&& (line[2] == 'Q' || line[2] == 'N')
&& (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 *ptr++ & 0377;
else
return EOF;
}
int file_input::peek()
{
if (*ptr != '\0' || read_line())
return *ptr;
else
return EOF;
}
int file_input::get_location(char **fnp, int *lnp)
{
*fnp = filename;
*lnp = lineno;
return 1;
}
macro_input::macro_input(const char *str, input *x) : input(x)
{
p = s = strsave(str);
}
macro_input::~macro_input()
{
delete s;
}
int macro_input::get()
{
if (p == 0 || *p == '\0')
return EOF;
else
return *p++ & 0377;
}
int macro_input::peek()
{
if (p == 0 || *p == '\0')
return EOF;
else
return *p & 0377;
}
top_input::top_input(const char *str, const char *fn, int ln, input *x)
: macro_input(str, x), lineno(ln)
{
filename = strsave(fn);
}
top_input::~top_input()
{
delete filename;
}
int top_input::get()
{
int c = macro_input::get();
if (c == '\n')
lineno++;
return c;
}
int top_input::get_location(char **fnp, int *lnp)
{
*fnp = filename;
*lnp = lineno;
return 1;
}
#define ARG1 11
argument_macro_input::argument_macro_input(const char *body, int ac,
char **av, input *x)
: input(x), argc(ac), ap(0)
{
for (int i = 0; i < argc; i++)
argv[i] = av[i];
p = s = strsave(body);
int j = 0;
for (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';
}
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 *ap++ & 0377;
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 *ap++ & 0377;
}
}
if (*p == '\0')
return EOF;
return *p++ & 0377;
}
int argument_macro_input::peek()
{
if (ap) {
if (*ap != '\0')
return *ap & 0377;
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 *ap & 0377;
}
}
if (*p == '\0')
return EOF;
return *p & 0377;
}
static input *current_input = 0;
/* we insert a newline between input from different levels */
int get_char()
{
if (current_input == 0)
return EOF;
else {
int c = current_input->get();
if (c != EOF)
return c;
else {
input *tem = current_input;
current_input = current_input->next;
delete tem;
return '\n';
}
}
}
int peek_char()
{
if (current_input == 0)
return EOF;
else {
int c = current_input->peek();
if (c != EOF)
return c;
else
return '\n';
}
}
int get_location(char **fnp, int *lnp)
{
for (input *p = current_input; p; p = p->next)
if (p->get_location(fnp, lnp))
return 1;
return 0;
}
string token_buffer;
const int NCONTEXT = 4;
string context_ring[NCONTEXT];
int context_index = 0;
void flush_context()
{
for (int i = 0; i < NCONTEXT; i++)
context_ring[i] = "";
context_index = 0;
}
void show_context()
{
int i = context_index;
fputs(" context is\n\t", stderr);
for (;;) {
int j = (i + 1) % NCONTEXT;
if (j == context_index) {
fputs(">>> ", stderr);
put_string(context_ring[i], stderr);
fputs(" <<<", stderr);
break;
}
else if (context_ring[i].length() > 0) {
put_string(context_ring[i], stderr);
putc(' ', stderr);
}
i = j;
}
putc('\n', stderr);
}
void add_context(const string &s)
{
context_ring[context_index] = s;
context_index = (context_index + 1) % NCONTEXT;
}
void add_context(char c)
{
context_ring[context_index] = c;
context_index = (context_index + 1) % NCONTEXT;
}
void add_quoted_context(const string &s)
{
string &r = context_ring[context_index];
r = '"';
for (int i = 0; i < s.length(); i++)
if (s[i] == '"')
r += "\\\"";
else
r += s[i];
r += '"';
context_index = (context_index + 1) % NCONTEXT;
}
void init_lex(const char *str, const char *filename, int lineno)
{
while (current_input != 0) {
input *tem = current_input;
current_input = current_input->next;
delete tem;
}
current_input = new top_input(str, filename, lineno, 0);
flush_context();
}
void get_delimited_text()
{
char *filename;
int lineno;
int got_location = get_location(&filename, &lineno);
int start = get_char();
while (start == ' ' || start == '\n')
start = get_char();
token_buffer.clear();
if (start == EOF) {
if (got_location)
error_with_file_and_line(filename, lineno,
"end of input while defining macro");
else
error("end of input while defining macro");
return;
}
for (;;) {
int c = get_char();
if (c == EOF) {
if (got_location)
error_with_file_and_line(filename, lineno,
"end of input while defining macro");
else
error("end of input while defining macro");
add_context(start + token_buffer);
return;
}
if (c == start)
break;
token_buffer += char(c);
}
add_context(start + token_buffer + start);
}
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 = 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);
current_input = new argument_macro_input(body, argc, argv, current_input);
}
/* If lookup flag is non-zero the token will be looked up to see
if it is macro. If it's 1, it will looked up to see if it's a token.
*/
int get_token(int lookup_flag = 0)
{
for (;;) {
int c = get_char();
while (c == ' ' || c == '\n')
c = get_char();
switch (c) {
case EOF:
add_context("end of input");
return 0;
case '"':
{
int quoted = 0;
token_buffer.clear();
for (;;) {
c = get_char();
if (c == EOF) {
lex_error("missing \"");
break;
}
else if (c == '\n') {
lex_error("newline before end of quoted text");
break;
}
else if (c == '"') {
if (!quoted)
break;
token_buffer[token_buffer.length() - 1] = '"';
quoted = 0;
}
else {
token_buffer += c;
quoted = quoted ? 0 : c == '\\';
}
}
}
add_quoted_context(token_buffer);
return QUOTED_TEXT;
case '{':
case '}':
case '^':
case '~':
case '\t':
add_context(c);
return c;
default:
{
int break_flag = 0;
int quoted = 0;
token_buffer.clear();
if (c == '\\')
quoted = 1;
else
token_buffer += c;
int done = 0;
while (!done) {
c = peek_char();
if (!quoted && lookup_flag != 0 && c == '(') {
token_buffer += '\0';
definition *def = macro_table.lookup(token_buffer.contents());
if (def && def->is_macro && !def->is_simple) {
(void)get_char(); // skip initial '('
interpolate_macro_with_args(def->contents);
break_flag = 1;
break;
}
token_buffer.set_length(token_buffer.length() - 1);
}
if (quoted) {
quoted = 0;
switch (c) {
case EOF:
lex_error("`\\' ignored at end of equation");
done = 1;
break;
case '\n':
lex_error("`\\' ignored because followed by newline");
done = 1;
break;
case '\t':
lex_error("`\\' ignored because followed by tab");
done = 1;
break;
case '"':
(void)get_char();
token_buffer += '"';
break;
default:
(void)get_char();
token_buffer += '\\';
token_buffer += c;
break;
}
}
else {
switch (c) {
case EOF:
case '{':
case '}':
case '^':
case '~':
case '"':
case ' ':
case '\t':
case '\n':
done = 1;
break;
case '\\':
(void)get_char();
quoted = 1;
break;
default:
(void)get_char();
token_buffer += char(c);
break;
}
}
}
if (break_flag || token_buffer.length() == 0)
break;
if (lookup_flag != 0) {
token_buffer += '\0';
definition *def = macro_table.lookup(token_buffer.contents());
token_buffer.set_length(token_buffer.length() - 1);
if (def) {
if (def->is_macro) {
current_input = new macro_input(def->contents, current_input);
break;
}
else if (lookup_flag == 1) {
add_context(token_buffer);
return def->tok;
}
}
}
add_context(token_buffer);
return TEXT;
}
}
}
}
void do_include()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad filename for include");
return;
}
token_buffer += '\0';
const char *filename = token_buffer.contents();
FILE *fp = fopen(filename, "r");
if (fp == 0) {
lex_error("can't open included file `%1'", filename);
return;
}
current_input = new file_input(fp, filename, current_input);
}
void ignore_definition()
{
int t = get_token();
if (t != TEXT) {
lex_error("bad definition");
return;
}
get_delimited_text();
}
void do_definition(int is_simple)
{
int t = get_token();
if (t != TEXT) {
lex_error("bad definition");
return;
}
token_buffer += '\0';
const char *name = token_buffer.contents();
definition *def = macro_table.lookup(name);
if (def == 0) {
def = new definition;
macro_table.define(name, def);
}
else if (def->is_macro) {
delete def->contents;
}
get_delimited_text();
token_buffer += '\0';
def->is_macro = 1;
def->contents = strsave(token_buffer.contents());
def->is_simple = is_simple;
}
void do_undef()
{
int t = get_token();
if (t != TEXT) {
lex_error("bad undef command");
return;
}
token_buffer += '\0';
macro_table.define(token_buffer.contents(), 0);
}
void do_gsize()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad argument to gsize command");
return;
}
token_buffer += '\0';
char *ptr;
long n = strtol(token_buffer.contents(), &ptr, 10);
if (n == 0 && ptr == token_buffer.contents())
lex_error("bad argument `%1' to gsize command");
else
set_gsize(int(n));
}
void do_gfont()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad argument to gfont command");
return;
}
token_buffer += '\0';
set_gfont(token_buffer.contents());
}
void do_grfont()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad argument to grfont command");
return;
}
token_buffer += '\0';
set_grfont(token_buffer.contents());
}
void do_gbfont()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad argument to gbfont command");
return;
}
token_buffer += '\0';
set_gbfont(token_buffer.contents());
}
void do_space()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad argument to space command");
return;
}
token_buffer += '\0';
char *ptr;
long n = strtol(token_buffer.contents(), &ptr, 10);
if (n == 0 && ptr == token_buffer.contents())
lex_error("bad argument `%1' to space command");
else
set_space(int(n));
}
void do_ifdef()
{
int t = get_token();
if (t != TEXT) {
lex_error("bad ifdef");
return;
}
token_buffer += '\0';
definition *def = macro_table.lookup(token_buffer.contents());
int result = def && def->is_macro && !def->is_simple;
get_delimited_text();
if (result) {
token_buffer += '\0';
current_input = new macro_input(token_buffer.contents(), current_input);
}
}
void do_delim()
{
int c = get_char();
while (c == ' ' || c == '\n')
c = get_char();
int d;
if (c == EOF || (d = get_char()) == EOF)
lex_error("end of file while reading argument to `delim'");
else {
if (c == 'o' && d == 'f' && peek_char() == 'f') {
(void)get_char();
start_delim = end_delim = '\0';
}
else {
start_delim = c;
end_delim = d;
}
}
}
void do_chartype()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad chartype");
return;
}
token_buffer += '\0';
string type = token_buffer;
t = get_token();
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad chartype");
return;
}
token_buffer += '\0';
set_char_type(type.contents(), strsave(token_buffer.contents()));
}
void do_set()
{
int t = get_token(2);
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad chartype");
return;
}
token_buffer += '\0';
string param = token_buffer;
t = get_token();
if (t != TEXT && t != QUOTED_TEXT) {
lex_error("bad chartype");
return;
}
token_buffer += '\0';
int n;
if (sscanf(&token_buffer[0], "%d", &n) != 1) {
lex_error("bad number `%1'", token_buffer.contents());
return;
}
set_param(param.contents(), n);
}
int yylex()
{
for (;;) {
int tk = get_token(1);
switch(tk) {
case UNDEF:
do_undef();
break;
case SDEFINE:
do_definition(1);
break;
case TDEFINE:
case DEFINE:
do_definition(0);
break;
case NDEFINE:
ignore_definition();
break;
case GSIZE:
do_gsize();
break;
case GFONT:
do_gfont();
break;
case GRFONT:
do_grfont();
break;
case GBFONT:
do_gbfont();
break;
case SPACE:
do_space();
break;
case INCLUDE:
do_include();
break;
case IFDEF:
do_ifdef();
break;
case DELIM:
do_delim();
break;
case CHARTYPE:
do_chartype();
break;
case SET:
do_set();
break;
case QUOTED_TEXT:
case TEXT:
token_buffer += '\0';
yylval.str = strsave(token_buffer.contents());
// fall through
default:
return tk;
}
}
}
void lex_error(const char *message,
const errarg &arg1,
const errarg &arg2,
const errarg &arg3)
{
char *filename;
int lineno;
if (!get_location(&filename, &lineno))
error(message, arg1, arg2, arg3);
else
error_with_file_and_line(filename, lineno, message, arg1, arg2, arg3);
}
void yyerror(const char *s)
{
char *filename;
int lineno;
if (!get_location(&filename, &lineno))
error(s);
else
error_with_file_and_line(filename, lineno, s);
show_context();
}