X-Git-Url: https://git.saurik.com/bison.git/blobdiff_plain/a0f6b076110ea79f25e13701d7f0ee4b38630d4d..8c7d6a3de82ca7fcbdfa6ad31c3bf70f63c6a069:/src/lex.c?ds=sidebyside diff --git a/src/lex.c b/src/lex.c index cf4f7e57..4bd0a6f2 100644 --- a/src/lex.c +++ b/src/lex.c @@ -1,5 +1,5 @@ /* Token-reader for Bison's input parser, - Copyright (C) 1984, 1986, 1989, 1992, 2000 Free Software Foundation, Inc. + Copyright 1984, 1986, 1989, 1992, 2000, 2001 Free Software Foundation, Inc. This file is part of Bison, the GNU Compiler Compiler. @@ -18,55 +18,20 @@ the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -/* - lex is the entry point. It is called from reader.c. - It returns one of the token-type codes defined in lex.h. - When an identifier is seen, the code IDENTIFIER is returned - and the name is looked up in the symbol table using symtab.c; - symval is set to a pointer to the entry found. */ - -#include #include "system.h" +#include "getargs.h" #include "files.h" #include "getopt.h" /* for optarg */ #include "symtab.h" #include "lex.h" -#include "alloc.h" +#include "xalloc.h" #include "complain.h" - -/* flags set by % directives */ -extern int definesflag; /* for -d */ -extern int toknumflag; /* for -k */ -extern int noparserflag; /* for -n */ -extern int fixed_outfiles; /* for -y */ -extern int nolinesflag; /* for -l */ -extern int rawtoknumflag; /* for -r */ -extern int verboseflag; /* for -v */ -extern int debugflag; /* for -t */ -extern char *spec_name_prefix; /* for -p */ -extern char *spec_file_prefix; /* for -b */ -/*spec_outfile is declared in files.h, for -o */ - -extern int translations; - -void init_lex PARAMS((void)); -char *grow_token_buffer PARAMS((char *)); -int skip_white_space PARAMS((void)); -int safegetc PARAMS((FILE *)); -int literalchar PARAMS((char **, int *, char)); -void unlex PARAMS((int)); -int lex PARAMS((void)); -int parse_percent_token PARAMS((void)); - -/* functions from main.c */ -extern char *printable_version PARAMS((int)); +#include "gram.h" +#include "quote.h" /* Buffer for storing the current token. */ -char *token_buffer; - -/* Allocated size of token_buffer, not including space for terminator. */ -int maxtoken; +struct obstack token_obstack; +const char *token_buffer = NULL; bucket *symval; int numval; @@ -78,29 +43,18 @@ static bucket *unlexed_symval; /* by the next call to lex */ void init_lex (void) { - maxtoken = 100; - token_buffer = NEW2 (maxtoken + 1, char); + obstack_init (&token_obstack); unlexed = -1; } -char * -grow_token_buffer (char *p) -{ - int offset = p - token_buffer; - maxtoken *= 2; - token_buffer = (char *) xrealloc(token_buffer, maxtoken + 1); - return token_buffer + offset; -} - - int skip_white_space (void) { - register int c; - register int inside; + int c; + int inside; - c = getc(finput); + c = getc (finput); for (;;) { @@ -109,7 +63,8 @@ skip_white_space (void) switch (c) { case '/': - c = getc(finput); + /* FIXME: Should probably be merged with copy_comment. */ + c = getc (finput); if (c != '*' && c != '/') { complain (_("unexpected `/' found and ignored")); @@ -117,7 +72,7 @@ skip_white_space (void) } cplus_comment = (c == '/'); - c = getc(finput); + c = getc (finput); inside = 1; while (inside) @@ -125,12 +80,12 @@ skip_white_space (void) if (!cplus_comment && c == '*') { while (c == '*') - c = getc(finput); + c = getc (finput); if (c == '/') { inside = 0; - c = getc(finput); + c = getc (finput); } } else if (c == '\n') @@ -138,12 +93,12 @@ skip_white_space (void) lineno++; if (cplus_comment) inside = 0; - c = getc(finput); + c = getc (finput); } else if (c == EOF) fatal (_("unterminated comment")); else - c = getc(finput); + c = getc (finput); } break; @@ -154,44 +109,56 @@ skip_white_space (void) case ' ': case '\t': case '\f': - c = getc(finput); + c = getc (finput); break; default: - return (c); + return c; } } } -/* do a getc, but give error message if EOF encountered */ -int -safegetc (FILE *f) + +/*-----------------------------------------------------. +| Do a getc, but give error message if EOF encountered | +`-----------------------------------------------------*/ + +static int +xgetc (FILE *f) { - register int c = getc(f); + int c = getc (f); if (c == EOF) fatal (_("unexpected end of file")); return c; } -/* read one literal character from finput. process \ escapes. - append the normalized string version of the char to *pp. - assign the character code to *pcode - return 1 unless the character is an unescaped `term' or \n - report error for \n -*/ -int -literalchar (char **pp, int *pcode, char term) + +/*------------------------------------------------------------------. +| Read one literal character from finput. Process \ escapes. | +| Append the normalized string version of the char to OUT. Assign | +| the character code to *PCODE. Return 1 unless the character is an | +| unescaped `term' or \n report error for \n. | +`------------------------------------------------------------------*/ + +/* FIXME: We could directly work in the obstack, but that would make + it more difficult to move to quotearg some day. So for the time + being, I prefer have literalchar behave like quotearg, and change + my mind later if I was wrong. */ + +static int +literalchar (struct obstack *out, int *pcode, char term) { - register int c; - register char *p; - register int code; + int c; + char buf[4096]; + char *cp; + int code; int wasquote = 0; - c = safegetc(finput); + c = xgetc (finput); if (c == '\n') { complain (_("unescaped newline in constant")); - ungetc(c, finput); + ungetc (c, finput); code = '?'; wasquote = 1; } @@ -203,17 +170,27 @@ literalchar (char **pp, int *pcode, char term) } else { - c = safegetc(finput); - if (c == 't') code = '\t'; - else if (c == 'n') code = '\n'; - else if (c == 'a') code = '\007'; - else if (c == 'r') code = '\r'; - else if (c == 'f') code = '\f'; - else if (c == 'b') code = '\b'; - else if (c == 'v') code = '\013'; - else if (c == '\\') code = '\\'; - else if (c == '\'') code = '\''; - else if (c == '\"') code = '\"'; + c = xgetc (finput); + if (c == 't') + code = '\t'; + else if (c == 'n') + code = '\n'; + else if (c == 'a') + code = '\007'; + else if (c == 'r') + code = '\r'; + else if (c == 'f') + code = '\f'; + else if (c == 'b') + code = '\b'; + else if (c == 'v') + code = '\013'; + else if (c == '\\') + code = '\\'; + else if (c == '\'') + code = '\''; + else if (c == '\"') + code = '\"'; else if (c <= '7' && c >= '0') { code = 0; @@ -227,71 +204,111 @@ literalchar (char **pp, int *pcode, char term) code &= 0xFF; break; } - c = safegetc(finput); + c = xgetc (finput); } - ungetc(c, finput); + ungetc (c, finput); } else if (c == 'x') { - c = safegetc(finput); + c = xgetc (finput); code = 0; while (1) { if (c >= '0' && c <= '9') - code *= 16, code += c - '0'; + code *= 16, code += c - '0'; else if (c >= 'a' && c <= 'f') - code *= 16, code += c - 'a' + 10; + code *= 16, code += c - 'a' + 10; else if (c >= 'A' && c <= 'F') - code *= 16, code += c - 'A' + 10; + code *= 16, code += c - 'A' + 10; else break; - if (code >= 256 || code<0) + if (code >= 256 || code < 0) { - complain (_("hexadecimal value above 255: `\\x%x'"), - code); + complain (_("hexadecimal value above 255: `\\x%x'"), code); code &= 0xFF; break; } - c = safegetc(finput); + c = xgetc (finput); } - ungetc(c, finput); + ungetc (c, finput); } else { + char badchar [] = "c"; + badchar[0] = c; complain (_("unknown escape sequence: `\\' followed by `%s'"), - printable_version(c)); + quote (badchar)); code = '?'; } - } /* has \ */ + } /* has \ */ - /* now fill token_buffer with the canonical name for this character - as a literal token. Do not use what the user typed, - so that `\012' and `\n' can be interchangeable. */ + /* now fill BUF with the canonical name for this character as a + literal token. Do not use what the user typed, so that `\012' + and `\n' can be interchangeable. */ - p = *pp; + cp = buf; if (code == term && wasquote) - *p++ = code; - else if (code == '\\') {*p++ = '\\'; *p++ = '\\';} - else if (code == '\'') {*p++ = '\\'; *p++ = '\'';} - else if (code == '\"') {*p++ = '\\'; *p++ = '\"';} + *cp++ = code; + else if (code == '\\') + { + *cp++ = '\\'; + *cp++ = '\\'; + } + else if (code == '\'') + { + *cp++ = '\\'; + *cp++ = '\''; + } + else if (code == '\"') + { + *cp++ = '\\'; + *cp++ = '\"'; + } else if (code >= 040 && code < 0177) - *p++ = code; - else if (code == '\t') {*p++ = '\\'; *p++ = 't';} - else if (code == '\n') {*p++ = '\\'; *p++ = 'n';} - else if (code == '\r') {*p++ = '\\'; *p++ = 'r';} - else if (code == '\v') {*p++ = '\\'; *p++ = 'v';} - else if (code == '\b') {*p++ = '\\'; *p++ = 'b';} - else if (code == '\f') {*p++ = '\\'; *p++ = 'f';} + *cp++ = code; + else if (code == '\t') + { + *cp++ = '\\'; + *cp++ = 't'; + } + else if (code == '\n') + { + *cp++ = '\\'; + *cp++ = 'n'; + } + else if (code == '\r') + { + *cp++ = '\\'; + *cp++ = 'r'; + } + else if (code == '\v') + { + *cp++ = '\\'; + *cp++ = 'v'; + } + else if (code == '\b') + { + *cp++ = '\\'; + *cp++ = 'b'; + } + else if (code == '\f') + { + *cp++ = '\\'; + *cp++ = 'f'; + } else { - *p++ = '\\'; - *p++ = code / 0100 + '0'; - *p++ = ((code / 010) & 07) + '0'; - *p++ = (code & 07) + '0'; + *cp++ = '\\'; + *cp++ = code / 0100 + '0'; + *cp++ = ((code / 010) & 07) + '0'; + *cp++ = (code & 07) + '0'; } - *pp = p; + *cp = '\0'; + + if (out) + obstack_sgrow (out, buf); *pcode = code; - return ! wasquote; + return !wasquote; } @@ -302,253 +319,247 @@ unlex (int token) unlexed_symval = symval; } +/*-----------------------------------------------------------------. +| We just read `<' from FIN. Store in TOKEN_BUFFER, the type name | +| specified between the `<...>'. | +`-----------------------------------------------------------------*/ -int +void +read_type_name (FILE *fin) +{ + int c = getc (fin); + + while (c != '>') + { + if (c == EOF) + fatal (_("unterminated type name at end of file")); + if (c == '\n') + { + complain (_("unterminated type name")); + ungetc (c, fin); + break; + } + + obstack_1grow (&token_obstack, c); + c = getc (fin); + } + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); +} + + +token_t lex (void) { - register int c; - char *p; + int c; + + /* Just to make sure. */ + token_buffer = NULL; if (unlexed >= 0) { symval = unlexed_symval; c = unlexed; unlexed = -1; - return (c); + return c; } - c = skip_white_space(); - *token_buffer = c; /* for error messages (token buffer always valid) */ - token_buffer[1] = 0; + c = skip_white_space (); switch (c) { case EOF: - strcpy(token_buffer, "EOF"); - return (ENDFILE); - - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': + token_buffer = "EOF"; + return tok_eof; + + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': - case '.': case '_': - p = token_buffer; - while (isalnum(c) || c == '_' || c == '.') - { - if (p == token_buffer + maxtoken) - p = grow_token_buffer(p); + case '.': case '_': - *p++ = c; - c = getc(finput); + while (isalnum (c) || c == '_' || c == '.') + { + obstack_1grow (&token_obstack, c); + c = getc (finput); } - - *p = 0; - ungetc(c, finput); - symval = getsym(token_buffer); - return (IDENTIFIER); - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); + ungetc (c, finput); + symval = getsym (token_buffer); + return tok_identifier; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': { numval = 0; - p = token_buffer; - while (isdigit(c)) + while (isdigit (c)) { - if (p == token_buffer + maxtoken) - p = grow_token_buffer(p); - - *p++ = c; - numval = numval*10 + c - '0'; - c = getc(finput); + obstack_1grow (&token_obstack, c); + numval = numval * 10 + c - '0'; + c = getc (finput); } - *p = 0; - ungetc(c, finput); - return (NUMBER); + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); + ungetc (c, finput); + return tok_number; } case '\'': - /* parse the literal token and compute character code in code */ translations = -1; { int code, discode; - char discard[10], *dp; - p = token_buffer; - *p++ = '\''; - literalchar(&p, &code, '\''); + obstack_1grow (&token_obstack, '\''); + literalchar (&token_obstack, &code, '\''); - c = getc(finput); + c = getc (finput); if (c != '\'') { complain (_("use \"...\" for multi-character literal tokens")); while (1) - { - dp = discard; - if (! literalchar(&dp, &discode, '\'')) - break; - } + if (!literalchar (0, &discode, '\'')) + break; } - *p++ = '\''; - *p = 0; - symval = getsym(token_buffer); - symval->class = STOKEN; - if (! symval->user_token_number) + obstack_1grow (&token_obstack, '\''); + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); + symval = getsym (token_buffer); + symval->class = token_sym; + if (!symval->user_token_number) symval->user_token_number = code; - return (IDENTIFIER); + return tok_identifier; } case '\"': - /* parse the literal string token and treat as an identifier */ translations = -1; { - int code; /* ignored here */ - p = token_buffer; - *p++ = '\"'; - while (literalchar(&p, &code, '\"')) /* read up to and including " */ - { - if (p >= token_buffer + maxtoken - 4) - p = grow_token_buffer(p); - } - *p = 0; + int code; /* ignored here */ - symval = getsym(token_buffer); - symval->class = STOKEN; + obstack_1grow (&token_obstack, '\"'); + /* Read up to and including ". */ + while (literalchar (&token_obstack, &code, '\"')) + /* nothing */; + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); - return (IDENTIFIER); + symval = getsym (token_buffer); + symval->class = token_sym; + + return tok_identifier; } case ',': - return (COMMA); + return tok_comma; case ':': - return (COLON); + return tok_colon; case ';': - return (SEMICOLON); + return tok_semicolon; case '|': - return (BAR); + return tok_bar; case '{': - return (LEFT_CURLY); + return tok_left_curly; case '=': do { - c = getc(finput); - if (c == '\n') lineno++; + c = getc (finput); + if (c == '\n') + lineno++; } - while(c==' ' || c=='\n' || c=='\t'); + while (c == ' ' || c == '\n' || c == '\t'); if (c == '{') { - strcpy(token_buffer, "={"); - return(LEFT_CURLY); + token_buffer = "={"; + return tok_left_curly; } else { - ungetc(c, finput); - return(ILLEGAL); + ungetc (c, finput); + return tok_illegal; } case '<': - p = token_buffer; - c = getc(finput); - while (c != '>') - { - if (c == EOF) - fatal (_("unterminated type name at end of file")); - if (c == '\n') - { - complain (_("unterminated type name")); - ungetc(c, finput); - break; - } - - if (p == token_buffer + maxtoken) - p = grow_token_buffer(p); - - *p++ = c; - c = getc(finput); - } - *p = 0; - return (TYPENAME); - + read_type_name (finput); + return tok_typename; case '%': - return (parse_percent_token()); + return parse_percent_token (); default: - return (ILLEGAL); + return tok_illegal; } } -/* the following table dictates the action taken for the various - % directives. A setflag value causes the named flag to be - set. A retval action returns the code. -*/ -struct percent_table_struct { - char *name; - void *setflag; - int retval; -} percent_table[] = +/* the following table dictates the action taken for the various % + directives. A set_flag value causes the named flag to be set. A + retval action returns the code. */ +struct percent_table_struct { - {"token", NULL, TOKEN}, - {"term", NULL, TOKEN}, - {"nterm", NULL, NTERM}, - {"type", NULL, TYPE}, - {"guard", NULL, GUARD}, - {"union", NULL, UNION}, - {"expect", NULL, EXPECT}, - {"thong", NULL, THONG}, - {"start", NULL, START}, - {"left", NULL, LEFT}, - {"right", NULL, RIGHT}, - {"nonassoc", NULL, NONASSOC}, - {"binary", NULL, NONASSOC}, - {"semantic_parser", NULL, SEMANTIC_PARSER}, - {"pure_parser", NULL, PURE_PARSER}, - {"prec", NULL, PREC}, - - {"no_lines", &nolinesflag, NOOP}, /* -l */ - {"raw", &rawtoknumflag, NOOP}, /* -r */ - {"token_table", &toknumflag, NOOP}, /* -k */ + const char *name; + void *set_flag; + int retval; +}; +struct percent_table_struct percent_table[] = +{ + { "token", NULL, tok_token }, + { "term", NULL, tok_token }, + { "nterm", NULL, tok_nterm }, + { "type", NULL, tok_type }, + { "guard", NULL, tok_guard }, + { "union", NULL, tok_union }, + { "expect", NULL, tok_expect }, + { "thong", NULL, tok_thong }, + { "start", NULL, tok_start }, + { "left", NULL, tok_left }, + { "right", NULL, tok_right }, + { "nonassoc", NULL, tok_nonassoc }, + { "binary", NULL, tok_nonassoc }, + { "prec", NULL, tok_prec }, + { "locations", &locations_flag, tok_noop }, /* -l */ + { "no_lines", &no_lines_flag, tok_noop }, /* -l */ + { "raw", NULL, tok_obsolete }, /* -r */ + { "token_table", &token_table_flag, tok_noop }, /* -k */ + { "yacc", &yacc_flag, tok_noop }, /* -y */ + { "fixed_output_files",&yacc_flag, tok_noop }, /* -y */ + { "defines", &defines_flag, tok_noop }, /* -d */ + { "no_parser", &no_parser_flag, tok_noop }, /* -n */ #if 0 - /* These can be utilized after main is reoganized so - open_files() is deferred 'til after read_declarations(). - But %{ and %union both put information into files - that have to be opened before read_declarations(). - */ - {"yacc", &fixed_outfiles, NOOP}, /* -y */ - {"fixed_output_files", &fixed_outfiles, NOOP}, /* -y */ - {"defines", &definesflag, NOOP}, /* -d */ - {"no_parser", &noparserflag, NOOP}, /* -n */ - {"output_file", &spec_outfile, SETOPT}, /* -o */ - {"file_prefix", &spec_file_prefix, SETOPT}, /* -b */ - {"name_prefix", &spec_name_prefix, SETOPT}, /* -p */ - - /* These would be acceptable, but they do not affect processing */ - {"verbose", &verboseflag, NOOP}, /* -v */ - {"debug", &debugflag, NOOP}, /* -t */ - /* {"help", , NOOP},*/ /* -h */ - /* {"version", , NOOP},*/ /* -V */ + /* For the time being, this is not enabled yet, while it's possible + though, since we use obstacks. The only risk is with semantic + parsers which will output an `include' of an output file: be sure + that the naem included is indeed the name of the output file. */ + { "output_file", &spec_outfile, tok_setopt }, /* -o */ + { "file_prefix", &spec_file_prefix, tok_setopt }, /* -b */ + { "name_prefix", &spec_name_prefix, tok_setopt }, /* -p */ #endif - - {NULL, NULL, ILLEGAL} + { "header_extension", NULL, tok_hdrext}, + { "source_extension", NULL, tok_srcext}, + { "verbose", &verbose_flag, tok_noop }, /* -v */ + { "debug", &debug_flag, tok_noop }, /* -t */ + { "semantic_parser", &semantic_parser, tok_noop }, + { "pure_parser", &pure_parser, tok_noop }, + + { NULL, NULL, tok_illegal} }; /* Parse a token which starts with %. @@ -557,71 +568,73 @@ struct percent_table_struct { int parse_percent_token (void) { - register int c; - register char *p; - register struct percent_table_struct *tx; + int c; + struct percent_table_struct *tx; - p = token_buffer; - c = getc(finput); - *p++ = '%'; - *p++ = c; /* for error msg */ - *p = 0; + c = getc (finput); switch (c) { case '%': - return (TWO_PERCENTS); + return tok_two_percents; case '{': - return (PERCENT_LEFT_CURLY); + return tok_percent_left_curly; case '<': - return (LEFT); + return tok_left; case '>': - return (RIGHT); + return tok_right; case '2': - return (NONASSOC); + return tok_nonassoc; case '0': - return (TOKEN); + return tok_token; case '=': - return (PREC); + return tok_prec; } - if (!isalpha(c)) - return (ILLEGAL); - p = token_buffer; - *p++ = '%'; - while (isalpha(c) || c == '_' || c == '-') - { - if (p == token_buffer + maxtoken) - p = grow_token_buffer(p); + if (!isalpha (c)) + return tok_illegal; - if (c == '-') c = '_'; - *p++ = c; - c = getc(finput); + obstack_1grow (&token_obstack, '%'); + while (isalpha (c) || c == '_' || c == '-') + { + if (c == '-') + c = '_'; + obstack_1grow (&token_obstack, c); + c = getc (finput); } - ungetc(c, finput); - - *p = 0; + ungetc (c, finput); + obstack_1grow (&token_obstack, '\0'); + token_buffer = obstack_finish (&token_obstack); /* table lookup % directive */ for (tx = percent_table; tx->name; tx++) - if (strcmp(token_buffer+1, tx->name) == 0) + if (strcmp (token_buffer + 1, tx->name) == 0) break; - if (tx->retval == SETOPT) + + if (tx->set_flag) { - *((char **)(tx->setflag)) = optarg; - return NOOP; + *((int *) (tx->set_flag)) = 1; + return tok_noop; } - if (tx->setflag) + + switch (tx->retval) { - *((int *)(tx->setflag)) = 1; - return NOOP; + case tok_setopt: + *((char **) (tx->set_flag)) = optarg; + return tok_noop; + break; + + case tok_obsolete: + fatal (_("`%s' is no longer supported"), token_buffer); + break; } + return tx->retval; }