Have Bison grammars parsed by a Bison grammar.

* src/reader.c, src/reader.h (prologue_augment): New.
* src/reader.c (copy_definition): Remove.
* src/reader.h, src/reader.c (gram_start_symbol_set, prologue_augment)
(grammar_symbol_append, grammar_rule_begin, grammar_midrule_action)
(grammar_current_rule_prec_set, grammar_current_rule_check)
(grammar_current_rule_symbol_append)
(grammar_current_rule_action_append): Export.
* src/parse-gram.y (symbol_list_new, symbol_list_symbol_append_
(symbol_list_action_append): Remove.
Hook the routines from reader.
* src/scan-gram.l: In INITIAL, characters and strings are tokens.
* src/system.h (ATTRIBUTE_NORETURN, ATTRIBUTE_UNUSED): Now.
* src/reader.c (read_declarations): Remove, unused.
* src/parse-gram.y: Handle the epilogue.
* src/reader.h, src/reader.c (gram_start_symbol_set): Rename as...
(grammar_start_symbol_set): this.
* src/scan-gram.l: Be sure to ``use'' yycontrol to keep GCC quiet.
* src/reader.c (readgram): Remove, unused.
(reader): Adjust to insert eoftoken and axiom where appropriate.
* src/reader.c (copy_dollar): Replace with...
* src/scan-gram.h (handle_dollar): this.
* src/parse-gram.y: Remove `%thong'.
* src/reader.c (copy_at): Replace with...
* src/scan-gram.h (handle_at): this.
* src/complain.h, src/complain.c (warn_at, complain_at, fatal_at):
New.
* src/scan-gram.l (YY_LINES): Keep lineno synchronized for the
time being.
* src/reader.h, src/reader.c (grammar_rule_end): New.
* src/parse.y (current_type, current_class): New.
Implement `%nterm', `%token' support.
Merge `%term' into `%token'.
(string_as_id): New.
* src/symtab.h, src/symtab.c (symbol_make_alias): Don't pass the
type name.
* src/parse-gram.y: Be sure to handle properly the beginning of
rules.
* src/parse-gram.y: Handle %type.
* src/reader.c (grammar_rule_end): Call grammar_current_rule_check.
* src/parse-gram.y: More directives support.
* src/options.c: No longer handle source directives.
* src/parse-gram.y: Fix %output.
* src/parse-gram.y: Handle %union.
Use the prologue locations.
* src/reader.c (parse_union_decl): Remove.
* src/reader.h, src/reader.c (epilogue_set): New.
* src/parse-gram.y: Use it.
* data/bison.simple, data/bison.c++: b4_stype is now either not
defined, then default to int, or to the contents of %union,
without `union' itself.
Adjust.
* src/muscle_tab.c (muscle_init): Don't predefine `stype'.
* src/output.c (actions_output): Don't output braces, as they are
already handled by the scanner.
* src/scan-gram.l (SC_CHARACTER): Set the user_token_number of
characters to themselves.
* tests/reduce.at (Reduced Automaton): End the grammars with %% so
that the epilogue has a proper #line.
* src/parse-gram.y: Handle precedence/associativity.
* src/symtab.c (symbol_precedence_set): Requires the symbol to be
a terminal.
* src/scan-gram.l (SC_BRACED_CODE): Catch strings and characters.
* tests/calc.at: Do not use `%token "foo"' as it makes not sense
at all to define terminals that cannot be emitted.
* src/scan-gram.l: Escape M4 characters.
* src/scan-gram.l: Working properly with escapes in user
strings/characters.
* tests/torture.at (AT_DATA_TRIANGULAR_GRAMMAR)
(AT_DATA_HORIZONTAL_GRAMMAR): Respect the `%token ID NUM STRING'
grammar.
Use more modest sizes, as for the time being the parser does not
release memory, and therefore the process swallows a huge amount
of memory.
* tests/torture.at (AT_DATA_LOOKAHEADS_GRAMMAR): Adjust to the
stricter %token grammar.
* src/symtab.h (associativity): Add `undef_assoc'.
(symbol_precedence_set): Do nothing when passed an undef_assoc.
* src/symtab.c (symbol_check_alias_consistence): Adjust.
* tests/regression.at (Invalid %directive): Remove, as it is now
meaningless.
(Invalid inputs): Adjust to the new error messages.
(Token definitions): The new grammar doesn't allow too many
eccentricities.
* src/lex.h, src/lex.c: Remove.
* src/reader.c (lastprec, skip_to_char, read_signed_integer)
(copy_character, copy_string2, copy_string, copy_identifier)
(copy_comment, parse_token_decl, parse_type_decl, parse_assoc_decl)
(parse_muscle_decl, parse_dquoted_param, parse_skel_decl)
(parse_action): Remove.
* po/POTFILES.in: Adjust.
This commit is contained in:
Akim Demaille
2002-06-11 20:16:05 +00:00
parent 39fd0b540d
commit e9955c8373
30 changed files with 6278 additions and 1971 deletions

123
ChangeLog
View File

@@ -1,3 +1,126 @@
2002-06-11 Akim Demaille <akim@epita.fr>
Have Bison grammars parsed by a Bison grammar.
* src/reader.c, src/reader.h (prologue_augment): New.
* src/reader.c (copy_definition): Remove.
* src/reader.h, src/reader.c (gram_start_symbol_set, prologue_augment)
(grammar_symbol_append, grammar_rule_begin, grammar_midrule_action)
(grammar_current_rule_prec_set, grammar_current_rule_check)
(grammar_current_rule_symbol_append)
(grammar_current_rule_action_append): Export.
* src/parse-gram.y (symbol_list_new, symbol_list_symbol_append_
(symbol_list_action_append): Remove.
Hook the routines from reader.
* src/scan-gram.l: In INITIAL, characters and strings are tokens.
* src/system.h (ATTRIBUTE_NORETURN, ATTRIBUTE_UNUSED): Now.
* src/reader.c (read_declarations): Remove, unused.
* src/parse-gram.y: Handle the epilogue.
* src/reader.h, src/reader.c (gram_start_symbol_set): Rename as...
(grammar_start_symbol_set): this.
* src/scan-gram.l: Be sure to ``use'' yycontrol to keep GCC quiet.
* src/reader.c (readgram): Remove, unused.
(reader): Adjust to insert eoftoken and axiom where appropriate.
* src/reader.c (copy_dollar): Replace with...
* src/scan-gram.h (handle_dollar): this.
* src/parse-gram.y: Remove `%thong'.
* src/reader.c (copy_at): Replace with...
* src/scan-gram.h (handle_at): this.
* src/complain.h, src/complain.c (warn_at, complain_at, fatal_at):
New.
* src/scan-gram.l (YY_LINES): Keep lineno synchronized for the
time being.
* src/reader.h, src/reader.c (grammar_rule_end): New.
* src/parse.y (current_type, current_class): New.
Implement `%nterm', `%token' support.
Merge `%term' into `%token'.
(string_as_id): New.
* src/symtab.h, src/symtab.c (symbol_make_alias): Don't pass the
type name.
* src/parse-gram.y: Be sure to handle properly the beginning of
rules.
* src/parse-gram.y: Handle %type.
* src/reader.c (grammar_rule_end): Call grammar_current_rule_check.
* src/parse-gram.y: More directives support.
* src/options.c: No longer handle source directives.
* src/parse-gram.y: Fix %output.
* src/parse-gram.y: Handle %union.
Use the prologue locations.
* src/reader.c (parse_union_decl): Remove.
* src/reader.h, src/reader.c (epilogue_set): New.
* src/parse-gram.y: Use it.
* data/bison.simple, data/bison.c++: b4_stype is now either not
defined, then default to int, or to the contents of %union,
without `union' itself.
Adjust.
* src/muscle_tab.c (muscle_init): Don't predefine `stype'.
* src/output.c (actions_output): Don't output braces, as they are
already handled by the scanner.
* src/scan-gram.l (SC_CHARACTER): Set the user_token_number of
characters to themselves.
* tests/reduce.at (Reduced Automaton): End the grammars with %% so
that the epilogue has a proper #line.
* src/parse-gram.y: Handle precedence/associativity.
* src/symtab.c (symbol_precedence_set): Requires the symbol to be
a terminal.
* src/scan-gram.l (SC_BRACED_CODE): Catch strings and characters.
* tests/calc.at: Do not use `%token "foo"' as it makes not sense
at all to define terminals that cannot be emitted.
* src/scan-gram.l: Escape M4 characters.
* src/scan-gram.l: Working properly with escapes in user
strings/characters.
* tests/torture.at (AT_DATA_TRIANGULAR_GRAMMAR)
(AT_DATA_HORIZONTAL_GRAMMAR): Respect the `%token ID NUM STRING'
grammar.
Use more modest sizes, as for the time being the parser does not
release memory, and therefore the process swallows a huge amount
of memory.
* tests/torture.at (AT_DATA_LOOKAHEADS_GRAMMAR): Adjust to the
stricter %token grammar.
* src/symtab.h (associativity): Add `undef_assoc'.
(symbol_precedence_set): Do nothing when passed an undef_assoc.
* src/symtab.c (symbol_check_alias_consistence): Adjust.
* tests/regression.at (Invalid %directive): Remove, as it is now
meaningless.
(Invalid inputs): Adjust to the new error messages.
(Token definitions): The new grammar doesn't allow too many
eccentricities.
* src/lex.h, src/lex.c: Remove.
* src/reader.c (lastprec, skip_to_char, read_signed_integer)
(copy_character, copy_string2, copy_string, copy_identifier)
(copy_comment, parse_token_decl, parse_type_decl, parse_assoc_decl)
(parse_muscle_decl, parse_dquoted_param, parse_skel_decl)
(parse_action): Remove.
* po/POTFILES.in: Adjust.
2002-06-11 Akim Demaille <akim@epita.fr> 2002-06-11 Akim Demaille <akim@epita.fr>
* src/reader.c (parse_action): Don't store directly into the * src/reader.c (parse_action): Don't store directly into the

View File

@@ -159,11 +159,10 @@ b4_token_defines(b4_tokens)
#endif #endif
#ifndef YYSTYPE #ifndef YYSTYPE
m4_ifdef([b4_stype_line], m4_ifdef([b4_stype],
[#line b4_stype_line "b4_filename" [#line b4_stype_line "b4_filename"
])dnl typedef union b4_stype yystype;],
typedef b4_stype [typedef int yystype;])
yystype;
# define YYSTYPE yystype # define YYSTYPE yystype
#endif #endif

View File

@@ -191,10 +191,10 @@ b4_token_defines(b4_tokens)
#endif #endif
#ifndef YYSTYPE #ifndef YYSTYPE
m4_ifdef([b4_stype_line], m4_ifdef([b4_stype],
[#line b4_stype_line "b4_filename" [#line b4_stype_line "b4_filename"
])dnl typedef union b4_stype yystype;],
typedef b4_stype yystype; [typedef int yystype;])
# define YYSTYPE yystype # define YYSTYPE yystype
# define YYSTYPE_IS_TRIVIAL 1 # define YYSTYPE_IS_TRIVIAL 1
#endif #endif
@@ -1238,11 +1238,10 @@ m4_if(b4_defines_flag, 0, [],
b4_token_defines(b4_tokens) b4_token_defines(b4_tokens)
#ifndef YYSTYPE #ifndef YYSTYPE
m4_ifdef([b4_stype_line], m4_ifdef([b4_stype],
[#line b4_stype_line "b4_filename" [#line b4_stype_line "b4_filename"
])dnl typedef union b4_stype yystype;],
typedef b4_stype [typedef int yystype;])
yystype;
# define YYSTYPE yystype # define YYSTYPE yystype
#endif #endif

View File

@@ -4,10 +4,11 @@ src/conflicts.c
src/files.c src/files.c
src/getargs.c src/getargs.c
src/lalr.c src/lalr.c
src/lex.c src/parse-gram.c
src/print.c src/print.c
src/reader.c src/reader.c
src/reduce.c src/reduce.c
src/scan-gram.c
lib/error.c lib/error.c
lib/getopt.c lib/getopt.c

View File

@@ -36,8 +36,10 @@ LDADD = $(INTLLIBS) ../lib/libbison.a
bin_PROGRAMS = bison bin_PROGRAMS = bison
bison_SOURCES = LR0.c closure.c complain.c conflicts.c \ bison_SOURCES = LR0.c closure.c complain.c conflicts.c \
parse-gram.y parse-gram.h \
scan-gram.c \
derives.c \ derives.c \
files.c getargs.c gram.c lalr.c lex.c main.c nullable.c \ files.c getargs.c gram.c lalr.c main.c nullable.c \
output.h output.c \ output.h output.c \
state.h state.c \ state.h state.c \
print_graph.h print_graph.c \ print_graph.h print_graph.c \
@@ -46,13 +48,13 @@ bison_SOURCES = LR0.c closure.c complain.c conflicts.c \
print.c reader.c reduce.c symtab.c vcg.c \ print.c reader.c reduce.c symtab.c vcg.c \
scan-skel.l scan-skel.l
BUILT_SOURCES = scan-skel.c BUILT_SOURCES = scan-skel.c scan-gram.c parse-gram.c parse-gram.h
EXTRA_bison_SOURCES = vmsgetargs.c EXTRA_bison_SOURCES = vmsgetargs.c
noinst_HEADERS = LR0.h closure.h complain.h conflicts.h \ noinst_HEADERS = LR0.h closure.h complain.h conflicts.h \
derives.h \ derives.h \
files.h getargs.h gram.h lalr.h lex.h nullable.h \ files.h getargs.h gram.h lalr.h nullable.h \
print.h reader.h reduce.h symtab.h system.h \ print.h reader.h reduce.h symtab.h system.h \
types.h vcg.h vcg_defaults.h types.h vcg.h vcg_defaults.h

View File

@@ -114,6 +114,56 @@ unsigned int complain_message_count;
| Report a warning, and proceed. | | Report a warning, and proceed. |
`--------------------------------*/ `--------------------------------*/
void
#if defined VA_START && defined __STDC__
warn_at (int location, const char *message, ...)
#else
warn_at (location, message, va_alist)
int location
char *message;
va_dcl
#endif
{
#ifdef VA_START
va_list args;
#endif
if (error_one_per_line)
{
static const char *old_infile;
static int old_lineno;
if (old_lineno == location &&
(infile == old_infile || !strcmp (old_infile, infile)))
/* Simply return and print nothing. */
return;
old_infile = infile;
old_lineno = location;
}
fflush (stdout);
if (infile != NULL)
fprintf (stderr, "%s:%d: ", infile, location);
else
fprintf (stderr, "%s:", program_name);
fputs (_("warning: "), stderr);
#ifdef VA_START
VA_START (args, message);
vfprintf (stderr, message, args);
va_end (args);
#else
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
++warn_message_count;
putc ('\n', stderr);
fflush (stderr);
}
void void
#if defined VA_START && defined __STDC__ #if defined VA_START && defined __STDC__
warn (const char *message, ...) warn (const char *message, ...)
@@ -166,6 +216,54 @@ warn (message, va_alist)
| An error has occurred, but we can proceed, and die later. | | An error has occurred, but we can proceed, and die later. |
`-----------------------------------------------------------*/ `-----------------------------------------------------------*/
void
#if defined VA_START && defined __STDC__
complain_at (int location, const char *message, ...)
#else
complain_at (location, message, va_alist)
int location;
char *message;
va_dcl
#endif
{
#ifdef VA_START
va_list args;
#endif
if (error_one_per_line)
{
static const char *old_infile;
static int old_lineno;
if (old_lineno == location &&
(infile == old_infile || !strcmp (old_infile, infile)))
/* Simply return and print nothing. */
return;
old_infile = infile;
old_lineno = location;
}
fflush (stdout);
if (infile != NULL)
fprintf (stderr, "%s:%d: ", infile, location);
else
fprintf (stderr, "%s:", program_name);
#ifdef VA_START
VA_START (args, message);
vfprintf (stderr, message, args);
va_end (args);
#else
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
++complain_message_count;
putc ('\n', stderr);
fflush (stderr);
}
void void
#if defined VA_START && defined __STDC__ #if defined VA_START && defined __STDC__
complain (const char *message, ...) complain (const char *message, ...)
@@ -216,6 +314,40 @@ complain (message, va_alist)
| A severe error has occurred, we cannot proceed. | | A severe error has occurred, we cannot proceed. |
`-------------------------------------------------*/ `-------------------------------------------------*/
void
#if defined VA_START && defined __STDC__
fatal_at (int location, const char *message, ...)
#else
fatal (location, message, va_alist)
int location;
char *message;
va_dcl
#endif
{
#ifdef VA_START
va_list args;
#endif
fflush (stdout);
if (infile != NULL)
fprintf (stderr, "%s:%d: ", infile, location);
else
fprintf (stderr, "%s:", program_name);
fputs (_("fatal error: "), stderr);
#ifdef VA_START
VA_START (args, message);
vfprintf (stderr, message, args);
va_end (args);
#else
fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
putc ('\n', stderr);
fflush (stderr);
exit (1);
}
void void
#if defined VA_START && defined __STDC__ #if defined VA_START && defined __STDC__
fatal (const char *message, ...) fatal (const char *message, ...)

View File

@@ -27,23 +27,35 @@ extern "C" {
/* Informative messages, but we proceed. */ /* Informative messages, but we proceed. */
extern void warn (const char *format, ...) void warn (const char *format, ...)
__attribute__ ((__format__ (__printf__, 1, 2))); __attribute__ ((__format__ (__printf__, 1, 2)));
void warn_at (int location, const char *format, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
/* Something bad happen, but let's continue and die later. */ /* Something bad happen, but let's continue and die later. */
extern void complain (const char *format, ...) void complain (const char *format, ...)
__attribute__ ((__format__ (__printf__, 1, 2))); __attribute__ ((__format__ (__printf__, 1, 2)));
void complain_at (int location, const char *format, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
/* Something bad happen and we die now. */ /* Something bad happen and we die now. */
extern void fatal (const char *format, ...) void fatal (const char *format, ...)
__attribute__ ((__format__ (__printf__, 1, 2))); __attribute__ ((__format__ (__printf__, 1, 2)));
void fatal_at (int location, const char *format, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
#else #else
void warn (); void warn ();
void warn_at ();
void complain (); void complain ();
void complain_at ();
void fatal (); void fatal ();
void fatal_at ();
#endif #endif
/* Position in the current input file. */ /* Position in the current input file. */

View File

@@ -216,6 +216,10 @@ resolve_sr_conflict (state_t *state, int lookahead)
/* Record an explicit error for this token. */ /* Record an explicit error for this token. */
errp->errs[errp->nerrs++] = i; errp->errs[errp->nerrs++] = i;
break; break;
case undef_assoc:
assert (symbols[i]->assoc != undef_assoc);
break;
} }
} }

604
src/lex.c
View File

@@ -1,604 +0,0 @@
/* Token-reader for Bison's input parser,
Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002
Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison 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 2, or (at your option)
any later version.
Bison 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 Bison; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "system.h"
#include "getargs.h"
#include "files.h"
#include "symtab.h"
#include "options.h"
#include "lex.h"
#include "complain.h"
#include "gram.h"
#include "quote.h"
/* Buffer for storing the current token. */
static struct obstack token_obstack;
const char *token_buffer = NULL;
symbol_t *symval = NULL;
int numval;
/* A token to be reread, see unlex and lex. */
static token_t unlexed = tok_undef;
static symbol_t *unlexed_symval = NULL;
static const char *unlexed_token_buffer = NULL;
void
lex_init (void)
{
obstack_init (&token_obstack);
unlexed = tok_undef;
}
void
lex_free (void)
{
obstack_free (&token_obstack, NULL);
}
int
skip_white_space (void)
{
int c;
int inside;
c = getc (finput);
for (;;)
{
int cplus_comment;
switch (c)
{
case '/':
/* FIXME: Should probably be merged with copy_comment. */
c = getc (finput);
if (c != '*' && c != '/')
{
complain (_("unexpected `/' found and ignored"));
break;
}
cplus_comment = (c == '/');
c = getc (finput);
inside = 1;
while (inside)
{
if (!cplus_comment && c == '*')
{
while (c == '*')
c = getc (finput);
if (c == '/')
{
inside = 0;
c = getc (finput);
}
}
else if (c == '\n')
{
lineno++;
if (cplus_comment)
inside = 0;
c = getc (finput);
}
else if (c == EOF)
fatal (_("unterminated comment"));
else
c = getc (finput);
}
break;
case '\n':
lineno++;
case ' ':
case '\t':
case '\f':
c = getc (finput);
break;
default:
return c;
}
}
}
/*-----------------------------------------------------.
| Do a getc, but give error message if EOF encountered |
`-----------------------------------------------------*/
int
xgetc (FILE *f)
{
int c = getc (f);
if (c == EOF)
fatal (_("unexpected end of file"));
return c;
}
/*---------------------------------------------------------------.
| Read one literal character from FINPUT, process \-escapes, and |
| return the character. |
`---------------------------------------------------------------*/
char
literalchar (void)
{
int c;
int res;
c = xgetc (finput);
if (c == '\n')
{
complain (_("unescaped newline in constant"));
ungetc (c, finput);
res = '?';
}
else if (c != '\\')
{
res = c;
}
else
{
c = xgetc (finput);
if (c == 't')
res = '\t';
else if (c == 'n')
res = '\n';
else if (c == 'a')
res = '\007';
else if (c == 'r')
res = '\r';
else if (c == 'f')
res = '\f';
else if (c == 'b')
res = '\b';
else if (c == 'v')
res = '\013';
else if (c == '\\')
res = '\\';
else if (c == '\'')
res = '\'';
else if (c == '\"')
res = '\"';
else if (c <= '7' && c >= '0')
{
res = 0;
while (c <= '7' && c >= '0')
{
res = (res * 8) + (c - '0');
if (res >= 256 || res < 0)
{
complain (_("octal value outside range 0...255: `\\%o'"),
res);
res &= 0xFF;
break;
}
c = xgetc (finput);
}
ungetc (c, finput);
}
else if (c == 'x')
{
c = xgetc (finput);
res = 0;
while (1)
{
if (c >= '0' && c <= '9')
res *= 16, res += c - '0';
else if (c >= 'a' && c <= 'f')
res *= 16, res += c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
res *= 16, res += c - 'A' + 10;
else
break;
if (res >= 256 || res < 0)
{
complain (_("hexadecimal value above 255: `\\x%x'"), res);
res &= 0xFF;
break;
}
c = xgetc (finput);
}
ungetc (c, finput);
}
else
{
char badchar [] = "c";
badchar[0] = c;
complain (_("unknown escape sequence: `\\' followed by `%s'"),
quote (badchar));
res = '?';
}
} /* has \ */
return res;
}
void
unlex (token_t token)
{
unlexed = token;
unlexed_token_buffer = token_buffer;
unlexed_symval = symval;
}
/*-----------------------------------------------------------------.
| We just read `<' from FIN. Store in TOKEN_BUFFER, the type name |
| specified between the `<...>'. |
`-----------------------------------------------------------------*/
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)
{
int c;
/* Just to make sure. */
token_buffer = NULL;
if (unlexed != tok_undef)
{
token_t res = unlexed;
symval = unlexed_symval;
token_buffer = unlexed_token_buffer;
unlexed = tok_undef;
return res;
}
c = skip_white_space ();
switch (c)
{
case EOF:
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 'z':
case '.': case '_':
while (isalnum (c) || c == '_' || c == '.')
{
obstack_1grow (&token_obstack, c);
c = getc (finput);
}
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;
while (isdigit (c))
{
obstack_1grow (&token_obstack, c);
numval = numval * 10 + c - '0';
c = getc (finput);
}
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 */
{
int code = literalchar ();
obstack_1grow (&token_obstack, '\'');
obstack_1grow (&token_obstack, code);
c = getc (finput);
if (c != '\'')
{
complain (_("use \"...\" for multi-character literal tokens"));
while (literalchar () != '\'')
/* Skip. */;
}
obstack_1grow (&token_obstack, '\'');
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
symval = getsym (token_buffer);
symbol_class_set (symval, token_sym);
symbol_user_token_number_set (symval, code);
return tok_identifier;
}
case '\"':
/* parse the literal string token and treat as an identifier */
{
int code;
obstack_1grow (&token_obstack, '\"');
/* Read up to and including ". */
do
{
code = literalchar ();
obstack_1grow (&token_obstack, code);
}
while (code != '\"');
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
symval = getsym (token_buffer);
symbol_class_set (symval, token_sym);
return tok_identifier;
}
case ',':
token_buffer = ",";
return tok_comma;
case ':':
token_buffer = ":";
return tok_colon;
case ';':
token_buffer = ";";
return tok_semicolon;
case '|':
token_buffer = "|";
return tok_bar;
case '{':
token_buffer = "{";
return tok_left_curly;
case '=':
obstack_1grow (&token_obstack, c);
do
{
c = getc (finput);
obstack_1grow (&token_obstack, c);
if (c == '\n')
lineno++;
}
while (c == ' ' || c == '\n' || c == '\t');
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
if (c == '{')
{
return tok_left_curly;
}
else
{
ungetc (c, finput);
return tok_illegal;
}
case '<':
read_type_name (finput);
return tok_typename;
case '%':
return parse_percent_token ();
default:
obstack_1grow (&token_obstack, c);
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
return tok_illegal;
}
}
/* This function is a strcmp, which doesn't differentiate `-' and `_'
chars. */
static int
option_strcmp (const char *left, const char *right)
{
const unsigned char *l, *r;
int c;
assert (left);
assert (right);
l = (const unsigned char *)left;
r = (const unsigned char *)right;
while (((c = *l - *r++) == 0 && *l != '\0')
|| ((*l == '-' || *l == '_') && (*r == '_' || *r == '-')))
l++;
return c;
}
/* Parse a token which starts with %.
Assumes the % has already been read and discarded. */
token_t
parse_percent_token (void)
{
const struct option_table_s *tx = NULL;
const char *arg = NULL;
/* Where the ARG was found in token_buffer. */
size_t arg_offset = 0;
int c = getc (finput);
obstack_1grow (&token_obstack, '%');
obstack_1grow (&token_obstack, c);
if (!isalpha (c))
{
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
switch (c)
{
case '%':
return tok_two_percents;
case '{':
return tok_percent_left_curly;
/* The following guys are here for backward compatibility with
very ancient Yacc versions. The paper of Johnson mentions
them (as ancient :). */
case '<':
return tok_left;
case '>':
return tok_right;
case '2':
return tok_nonassoc;
case '0':
return tok_token;
case '=':
return tok_prec;
default:
return tok_illegal;
}
}
while (c = getc (finput), isalpha (c) || c == '_' || c == '-')
{
if (c == '_')
c = '-';
obstack_1grow (&token_obstack, c);
}
/* %DIRECTIVE="ARG". Separate into
TOKEN_BUFFER = `%DIRECTIVE\0ARG\0'.
This is a bit hackish, but once we move to a Bison parser,
things will be cleaned up. */
if (c == '=')
{
/* End of the directive. We skip the `='. */
obstack_1grow (&token_obstack, '\0');
/* Fetch the ARG if present. */
c = getc (finput);
if (c == '"')
{
int code;
arg_offset = obstack_object_size (&token_obstack);
/* Read up to and including `"'. Do not append the closing
`"' in the output: it's not part of the ARG. */
while ((code = literalchar ()) != '"')
obstack_1grow (&token_obstack, code);
}
/* else: should be an error. */
}
else
ungetc (c, finput);
obstack_1grow (&token_obstack, '\0');
token_buffer = obstack_finish (&token_obstack);
if (arg_offset)
arg = token_buffer + arg_offset;
/* table lookup % directive */
for (tx = option_table; tx->name; tx++)
if ((tx->access == opt_percent || tx->access == opt_both)
&& option_strcmp (token_buffer + 1, tx->name) == 0)
break;
if (arg && tx->ret_val != tok_stropt)
fatal (_("`%s' supports no argument: %s"), token_buffer, quote (arg));
switch (tx->ret_val)
{
case tok_stropt:
assert (tx->flag);
if (arg)
{
char **flag = (char **) tx->flag;
/* Keep only the first assignment: command line options have
already been processed, and we want them to have
precedence. Side effect: if this %-option is used
several times, only the first is honored. Bah. */
if (!*flag)
*flag = xstrdup (arg);
}
else
fatal (_("`%s' requires an argument"), token_buffer);
return tok_noop;
break;
case tok_intopt:
assert (tx->flag);
*((int *) (tx->flag)) = 1;
return tok_noop;
break;
case tok_obsolete:
fatal (_("`%s' is no longer supported"), token_buffer);
return tok_noop;
break;
default:
return tx->ret_val;
break;
}
abort ();
}

View File

@@ -1,82 +0,0 @@
/* Token type definitions for bison's input reader,
Copyright 1984, 1989, 1992, 2000, 2001 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison 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 2, or (at your option)
any later version.
Bison 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 Bison; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#ifndef LEX_H_
# define LEX_H_
/* Token-type codes. */
typedef enum token_e
{
tok_undef, /* Not defined. Used to initial token_t vars. */
tok_eof,
tok_identifier,
tok_comma,
tok_colon,
tok_semicolon,
tok_bar,
tok_left_curly,
tok_two_percents,
tok_percent_left_curly,
tok_token,
tok_nterm,
tok_type,
tok_union,
tok_start,
tok_left,
tok_right,
tok_nonassoc,
tok_prec,
tok_typename,
tok_number,
tok_expect,
tok_define,
tok_skel,
tok_noop,
/* A directive that sets to true its associated variable. */
tok_intopt,
/* A directive that sets its associated variable to the string
argument. */
tok_stropt,
tok_illegal,
tok_obsolete
} token_t;
extern const char *token_buffer;
extern symbol_t *symval;
extern int numval;
void lex_init PARAMS ((void));
void lex_free PARAMS ((void));
int skip_white_space PARAMS ((void));
void unlex PARAMS ((token_t));
void read_type_name PARAMS ((FILE *fin));
int xgetc PARAMS ((FILE *fin));
/* Return one of the token-type codes. 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. */
token_t lex PARAMS ((void));
char literalchar PARAMS ((void));
token_t parse_percent_token PARAMS ((void));
#endif /* !LEX_H_ */

View File

@@ -38,7 +38,6 @@
#include "conflicts.h" #include "conflicts.h"
#include "print_graph.h" #include "print_graph.h"
#include "muscle_tab.h" #include "muscle_tab.h"
#include "lex.h"
/* The name this program was run with, for messages. */ /* The name this program was run with, for messages. */
char *program_name; char *program_name;

View File

@@ -55,7 +55,6 @@ muscle_init (void)
muscle_insert ("filename", infile); muscle_insert ("filename", infile);
/* Types. */ /* Types. */
muscle_insert ("stype", "int");
muscle_insert ("ltype", "yyltype"); muscle_insert ("ltype", "yyltype");
/* Default #line formatting. */ /* Default #line formatting. */

View File

@@ -24,7 +24,6 @@
#include "getargs.h" #include "getargs.h"
#include "symtab.h" #include "symtab.h"
#include "gram.h" #include "gram.h"
#include "lex.h"
#include "output.h" #include "output.h"
#include "options.h" #include "options.h"
@@ -77,55 +76,33 @@ const struct option_table_s option_table[] =
/* Hidden. */ /* Hidden. */
OPTN ("trace", no, &trace_flag, 0, 1) OPTN ("trace", no, &trace_flag, 0, 1)
/*
* Percent declarations.
*/
DRTV ("token", no, NULL, tok_token)
DRTV ("term", no, NULL, tok_token)
DRTV ("nterm", no, NULL, tok_nterm)
DRTV ("type", no, NULL, tok_type)
DRTV ("union", no, NULL, tok_union)
DRTV ("expect", no, NULL, tok_expect)
DRTV ("start", no, NULL, tok_start)
DRTV ("left", no, NULL, tok_left)
DRTV ("right", no, NULL, tok_right)
DRTV ("nonassoc", no, NULL, tok_nonassoc)
DRTV ("binary", no, NULL, tok_nonassoc)
DRTV ("prec", no, NULL, tok_prec)
DRTV ("verbose", no, &report_flag, tok_intopt)
DRTV ("error-verbose",no, &error_verbose, tok_intopt)
/* FIXME: semantic parsers will output an `include' of an /* FIXME: semantic parsers will output an `include' of an
output file: be sure that the naem included is indeed the name of output file: be sure that the naem included is indeed the name of
the output file. */ /* FIXME Should we activate this options ? the output file. */ /* FIXME Should we activate this options ?
*/ */
BOTH ("output", required, &spec_outfile, tok_stropt, 'o') OPTN ("output", required, &spec_outfile, 0, 'o')
BOTH ("file-prefix", required, &spec_file_prefix, tok_stropt, 'b') OPTN ("file-prefix", required, &spec_file_prefix, 0, 'b')
BOTH ("name-prefix", required, &spec_name_prefix, tok_stropt, 'p') OPTN ("name-prefix", required, &spec_name_prefix, 0, 'p')
DRTV ("define", no, NULL, tok_define)
DRTV ("pure-parser", no, &pure_parser, tok_intopt)
/* /*
* Percent and command line declarations. * Percent and command line declarations.
*/ */
/* Output. */ /* Output. */
BOTH ("defines", optional, &defines_flag, tok_intopt, 'd') OPTN ("defines", optional, &defines_flag, 0, 'd')
/* Operation modes. */ /* Operation modes. */
BOTH ("fixed-output-files", no, &yacc_flag, tok_intopt, 'y') OPTN ("fixed-output-files", no, &yacc_flag, 0, 'y')
BOTH ("yacc", no, &yacc_flag, tok_intopt, 'y') OPTN ("yacc", no, &yacc_flag, 0, 'y')
/* Parser. */ /* Parser. */
BOTH ("debug", no, &debug_flag, tok_intopt, 't') OPTN ("debug", no, &debug_flag, 0, 't')
BOTH ("locations", no, &locations_flag, tok_intopt, 1) OPTN ("locations", no, &locations_flag, 0, 1)
BOTH ("no-lines", no, &no_lines_flag, tok_intopt, 'l') OPTN ("no-lines", no, &no_lines_flag, 0, 'l')
BOTH ("no-parser", no, &no_parser_flag, tok_intopt, 'n') OPTN ("no-parser", no, &no_parser_flag, 0, 'n')
BOTH ("raw", no, 0, tok_obsolete, 0) OPTN ("raw", no, 0, 0, 0)
BOTH ("skeleton", required, 0, tok_skel, 'S') OPTN ("skeleton", required, 0, 0, 'S')
BOTH ("token-table", no, &token_table_flag, tok_intopt, 'k') OPTN ("token-table", no, &token_table_flag, 0, 'k')
{0, 0, 0, 0, 0, 0} {0, 0, 0, 0, 0, 0}
}; };

View File

@@ -548,12 +548,8 @@ actions_output (FILE *out)
rules[rule].action_line, rules[rule].action_line,
quotearg_style (c_quoting_style, quotearg_style (c_quoting_style,
muscle_find ("filename"))); muscle_find ("filename")));
/* As a Bison extension, add the ending semicolon. Since some fprintf (out, " %s\n break;\n\n",
Yacc don't do that, help people using bison as a Yacc rules[rule].action);
finding their missing semicolons. */
fprintf (out, "{ %s%s }\n break;\n\n",
rules[rule].action,
yacc_flag ? ";" : "");
} }
} }

1790
src/parse-gram.c Normal file

File diff suppressed because it is too large Load Diff

124
src/parse-gram.h Normal file
View File

@@ -0,0 +1,124 @@
#ifndef BISON_PARSE_GRAM_H
# define BISON_PARSE_GRAM_H
/* Tokens. */
#ifndef YYTOKENTYPE
# if defined (__STDC__) || defined (__cplusplus)
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
GRAM_EOF = 0,
STRING = 258,
CHARACTER = 259,
INT = 260,
PERCENT_TOKEN = 261,
PERCENT_NTERM = 262,
PERCENT_TYPE = 263,
PERCENT_UNION = 264,
PERCENT_EXPECT = 265,
PERCENT_START = 266,
PERCENT_LEFT = 267,
PERCENT_RIGHT = 268,
PERCENT_NONASSOC = 269,
PERCENT_PREC = 270,
PERCENT_VERBOSE = 271,
PERCENT_ERROR_VERBOSE = 272,
PERCENT_OUTPUT = 273,
PERCENT_FILE_PREFIX = 274,
PERCENT_NAME_PREFIX = 275,
PERCENT_DEFINE = 276,
PERCENT_PURE_PARSER = 277,
PERCENT_DEFINES = 278,
PERCENT_YACC = 279,
PERCENT_DEBUG = 280,
PERCENT_LOCATIONS = 281,
PERCENT_NO_LINES = 282,
PERCENT_SKELETON = 283,
PERCENT_TOKEN_TABLE = 284,
TYPE = 285,
EQUAL = 286,
SEMICOLON = 287,
COLON = 288,
PIPE = 289,
ID = 290,
PERCENT_PERCENT = 291,
PROLOGUE = 292,
EPILOGUE = 293,
BRACED_CODE = 294
};
# endif
/* POSIX requires `int' for tokens in interfaces. */
# define YYTOKENTYPE int
#endif /* !YYTOKENTYPE */
#define GRAM_EOF 0
#define STRING 258
#define CHARACTER 259
#define INT 260
#define PERCENT_TOKEN 261
#define PERCENT_NTERM 262
#define PERCENT_TYPE 263
#define PERCENT_UNION 264
#define PERCENT_EXPECT 265
#define PERCENT_START 266
#define PERCENT_LEFT 267
#define PERCENT_RIGHT 268
#define PERCENT_NONASSOC 269
#define PERCENT_PREC 270
#define PERCENT_VERBOSE 271
#define PERCENT_ERROR_VERBOSE 272
#define PERCENT_OUTPUT 273
#define PERCENT_FILE_PREFIX 274
#define PERCENT_NAME_PREFIX 275
#define PERCENT_DEFINE 276
#define PERCENT_PURE_PARSER 277
#define PERCENT_DEFINES 278
#define PERCENT_YACC 279
#define PERCENT_DEBUG 280
#define PERCENT_LOCATIONS 281
#define PERCENT_NO_LINES 282
#define PERCENT_SKELETON 283
#define PERCENT_TOKEN_TABLE 284
#define TYPE 285
#define EQUAL 286
#define SEMICOLON 287
#define COLON 288
#define PIPE 289
#define ID 290
#define PERCENT_PERCENT 291
#define PROLOGUE 292
#define EPILOGUE 293
#define BRACED_CODE 294
#ifndef YYSTYPE
#line 70 "parse-gram.y"
typedef union
{
symbol_t *symbol;
int integer;
char *string;
associativity assoc;
}
yystype;
# define YYSTYPE yystype
#endif
#ifndef YYLTYPE
typedef struct yyltype
{
int first_line;
int first_column;
int last_line;
int last_column;
} yyltype;
# define YYLTYPE yyltype
#endif
#endif /* not BISON_PARSE_GRAM_H */

386
src/parse-gram.y Normal file
View File

@@ -0,0 +1,386 @@
/* Bison Grammar Parser -*- C -*-
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/
%debug
%defines
%locations
%pure-parser
%error-verbose
%defines
%name-prefix="gram_"
%{
#include "system.h"
#include "muscle_tab.h"
#include "files.h"
#include "getargs.h"
#include "output.h"
#include "gram.h"
#include "reader.h"
#include "conflicts.h"
/* Pass the control structure to YYPARSE and YYLEX. */
#define YYPARSE_PARAM gram_control
#define YYLEX_PARAM gram_control
/* YYPARSE receives GRAM_CONTROL as a void *. Provide a
correctly typed access to it. */
#define yycontrol ((gram_control_t *) gram_control)
/* Request detailed parse error messages, and pass them to
GRAM_ERROR. */
#undef yyerror
#define yyerror(Msg) \
gram_error (yycontrol, &yylloc, Msg)
/* When debugging our pure parser, we want to see values and locations
of the tokens. */
#define YYPRINT(File, Type, Value) \
yyprint (File, &yylloc, Type, &Value)
static void yyprint (FILE *file, const yyltype *loc,
int type, const yystype *value);
symbol_class current_class = unknown_sym;
char *current_type = 0;
symbol_t *current_lhs;
associativity current_assoc;
int current_prec = 0;
%}
/* Only NUMBERS have a value. */
%union
{
symbol_t *symbol;
int integer;
char *string;
associativity assoc;
};
/* Define the tokens together with there human representation. */
%token GRAM_EOF 0 "end of string"
%token STRING CHARACTER
%token INT
%token PERCENT_TOKEN "%token"
%token PERCENT_NTERM "%nterm"
%token PERCENT_TYPE "%type"
%token PERCENT_UNION "%union"
%token PERCENT_EXPECT "%expect"
%token PERCENT_START "%start"
%token PERCENT_LEFT "%left"
%token PERCENT_RIGHT "%right"
%token PERCENT_NONASSOC "%nonassoc"
%token PERCENT_PREC "%prec"
%token PERCENT_VERBOSE "%verbose"
%token PERCENT_ERROR_VERBOSE "%error-verbose"
%token PERCENT_OUTPUT "%output"
%token PERCENT_FILE_PREFIX "%file-prefix"
%token PERCENT_NAME_PREFIX "%name-prefix"
%token PERCENT_DEFINE "%define"
%token PERCENT_PURE_PARSER "%pure-parser"
%token PERCENT_DEFINES "%defines"
%token PERCENT_YACC "%yacc"
%token PERCENT_DEBUG "%debug"
%token PERCENT_LOCATIONS "%locations"
%token PERCENT_NO_LINES "%no-lines"
%token PERCENT_SKELETON "%skeleton"
%token PERCENT_TOKEN_TABLE "%token-table"
%token TYPE
%token EQUAL "="
%token SEMICOLON ";"
%token COLON ":"
%token PIPE "|"
%token ID "identifier"
%token PERCENT_PERCENT "%%"
%token PROLOGUE EPILOGUE
%token BRACED_CODE
%type <string> CHARACTER TYPE BRACED_CODE PROLOGUE EPILOGUE epilogue.opt action STRING string_content
%type <integer> INT
%type <symbol> ID symbol string_as_id
%type <assoc> precedence_directive
%%
input: { LOCATION_RESET (yylloc); }
directives "%%" gram epilogue.opt
{
yycontrol->errcode = 0;
epilogue_set ($5, @5.first_line);
}
;
directives:
/* Nothing */
| directives directive
;
directive:
grammar_directives
| PROLOGUE { prologue_augment ($1, @1.first_line); }
| "%debug" { debug_flag = 1; }
| "%define" string_content string_content { muscle_insert ($2, $3); }
| "%defines" { defines_flag = 1; }
| "%error-verbose" { error_verbose = 1; }
| "%expect" INT { expected_conflicts = $2; }
| "%file-prefix" "=" string_content { spec_file_prefix = $3; }
| "%locations" { locations_flag = 1; }
| "%name-prefix" "=" string_content { spec_name_prefix = $3; }
| "%no-lines" { no_lines_flag = 1; }
| "%output" "=" string_content { spec_outfile = $3; }
| "%pure-parser" { pure_parser = 1; }
| "%skeleton" string_content { skeleton = $2; }
| "%token-table" { token_table_flag = 1; }
| "%verbose" { report_flag = 1; }
| "%yacc" { yacc_flag = 1; }
;
grammar_directives:
precedence_directives
| "%nterm" { current_class = nterm_sym; } symbol_defs.1
{
current_class = unknown_sym;
current_type = NULL;
}
| "%start" symbol
{
grammar_start_symbol_set ($2);
}
| "%token" { current_class = token_sym; } symbol_defs.1
{
current_class = unknown_sym;
current_type = NULL;
}
| "%type" TYPE {current_type = $2; } nterms_to_type.1
{
current_type = NULL;
}
| "%union" BRACED_CODE semi_colon_opt
{
typed = 1;
MUSCLE_INSERT_INT ("stype_line", @2.first_line);
muscle_insert ("stype", $2);
}
;
precedence_directives:
precedence_directive type.opt
{ current_assoc = $1; ++current_prec; }
terms_to_prec.1
{ current_assoc = non_assoc; current_type = NULL; }
;
precedence_directive:
"%left" { $$ = left_assoc; }
| "%right" { $$ = right_assoc; }
| "%nonassoc" { $$ = non_assoc; }
;
type.opt:
/* Nothing. */ { current_type = NULL;}
| TYPE { current_type = $1; }
;
/* One or more nonterminals to be %typed. */
nterms_to_type.1:
ID { symbol_type_set ($1, current_type); }
| nterms_to_type.1 ID { symbol_type_set ($2, current_type); }
;
/* One or more symbols to be given a precedence/associativity. */
terms_to_prec.1:
symbol
{
symbol_type_set ($1, current_type);
symbol_precedence_set ($1, current_prec, current_assoc);
}
| terms_to_prec.1 symbol
{
symbol_type_set ($2, current_type);
symbol_precedence_set ($2, current_prec, current_assoc);
}
;
/* One token definition. */
symbol_def:
TYPE
{
current_type = $1;
}
| ID
{
symbol_class_set ($1, current_class);
symbol_type_set ($1, current_type);
}
| ID INT
{
symbol_class_set ($1, current_class);
symbol_type_set ($1, current_type);
symbol_user_token_number_set ($1, $2);
}
| ID string_as_id
{
symbol_class_set ($1, current_class);
symbol_type_set ($1, current_type);
symbol_make_alias ($1, $2);
}
| ID INT string_as_id
{
symbol_class_set ($1, current_class);
symbol_type_set ($1, current_type);
symbol_user_token_number_set ($1, $2);
symbol_make_alias ($1, $3);
}
;
/* One or more symbol definitions. */
symbol_defs.1:
symbol_def
{;}
| symbol_defs.1 symbol_def
{;}
;
gram:
rules
| gram rules
;
rules:
ID ":" { current_lhs = $1; } rhses.1 ";"
{;}
;
rhses.1:
rhs { grammar_rule_end (); }
| rhses.1 "|" rhs { grammar_rule_end (); }
;
rhs:
/* Nothing. */
{ grammar_rule_begin (current_lhs); }
| rhs symbol
{ grammar_current_rule_symbol_append ($2); }
| rhs action
{ grammar_current_rule_action_append ($2, @2.first_line); }
| rhs "%prec" symbol
{ grammar_current_rule_prec_set ($3); }
;
symbol:
ID { $$ = $1; }
| string_as_id { $$ = $1; }
| CHARACTER { $$ = getsym ($1); }
;
action:
BRACED_CODE
{ $$ = $1; }
;
/* A string used as an ID: we have to keep the quotes. */
string_as_id:
STRING
{
$$ = getsym ($1);
symbol_class_set ($$, token_sym);
}
;
/* A string used for its contents. Strip the quotes. */
string_content:
STRING
{
$$ = $1 + 1;
$$[strlen ($$) - 1] = '\0';
};
epilogue.opt:
/* Nothing. */
{
$$ = xstrdup ("");
}
| "%%" EPILOGUE
{
$$ = $2;
}
;
semi_colon_opt:
/* Nothing. */
| ";"
;
%%
/*------------------------------------------------------------------.
| When debugging the parser, display tokens' locations and values. |
`------------------------------------------------------------------*/
static void
yyprint (FILE *file,
const yyltype *loc, int type, const yystype *value)
{
fputs (" (", file);
LOCATION_PRINT (file, *loc);
fputs (")", file);
switch (type)
{
case CHARACTER:
fprintf (file, " = '%s'", value->string);
break;
case ID:
fprintf (file, " = %s", value->symbol->tag);
break;
case INT:
fprintf (file, " = %d", value->integer);
break;
case STRING:
fprintf (file, " = \"%s\"", value->string);
break;
case TYPE:
fprintf (file, " = <%s>", value->string);
break;
case BRACED_CODE:
case PROLOGUE:
case EPILOGUE:
fprintf (file, " = {{ %s }}", value->string);
break;
}
}
void
gram_error (gram_control_t *control ATTRIBUTE_UNUSED,
yyltype *yylloc, const char *msg)
{
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": %s\n", msg);
}

File diff suppressed because it is too large Load Diff

View File

@@ -21,13 +21,92 @@
#ifndef READER_H_ #ifndef READER_H_
# define READER_H_ # define READER_H_
#include "symtab.h" typedef struct symbol_list
{
struct symbol_list *next;
symbol_t *sym;
int line;
/* Read in the grammar specification and record it in the format /* The action is attached to the LHS of a rule. */
described in gram.h. */ const char *action;
int action_line;
symbol_t *ruleprec;
} symbol_list;
# include "parse-gram.h"
typedef int location_t;
/* Initialize LOC. */
# define LOCATION_RESET(Loc) \
(Loc).first_column = (Loc).first_line = 1; \
(Loc).last_column = (Loc).last_line = 1;
/* Advance of NUM columns. */
# define LOCATION_COLUMNS(Loc, Num) \
(Loc).last_column += Num;
/* Advance of NUM lines. */
# define LOCATION_LINES(Loc, Num) \
(Loc).last_column = 1; \
(Loc).last_line += Num;
/* Restart: move the first cursor to the last position. */
# define LOCATION_STEP(Loc) \
(Loc).first_column = (Loc).last_column; \
(Loc).first_line = (Loc).last_line;
/* Output LOC on the stream OUT. */
# define LOCATION_PRINT(Out, Loc) \
fprintf (stderr, "%s:", infile); \
if ((Loc).first_line != (Loc).last_line) \
fprintf (Out, "%d.%d-%d.%d", \
(Loc).first_line, (Loc).first_column, \
(Loc).last_line, (Loc).last_column - 1); \
else if ((Loc).first_column < (Loc).last_column - 1) \
fprintf (Out, "%d.%d-%d", (Loc).first_line, \
(Loc).first_column, (Loc).last_column - 1); \
else \
fprintf (Out, "%d.%d", (Loc).first_line, (Loc).first_column)
typedef struct gram_control_s
{
int errcode;
} gram_control_t;
/* From the scanner. */
extern FILE *gram_in;
extern int gram__flex_debug;
# define YY_DECL \
int gram_lex (yystype *yylval, yyltype *yylloc, \
gram_control_t *yycontrol)
YY_DECL;
/* From the parser. */
extern int gram_debug;
void gram_error (gram_control_t *control,
yyltype *loc, const char *msg);
int gram_parse (void *control);
char *get_type_name PARAMS ((int n, symbol_list *rule));
extern int typed;
/* From reader.c. */
void grammar_start_symbol_set PARAMS ((symbol_t *s));
void prologue_augment PARAMS ((const char *prologue, location_t location));
void epilogue_set PARAMS ((const char *epilogue, location_t location));
void grammar_symbol_append PARAMS ((symbol_t *s));
void grammar_rule_begin PARAMS ((symbol_t *lhs));
void grammar_rule_end PARAMS ((void));
void grammar_midrule_action PARAMS ((void));
void grammar_current_rule_prec_set PARAMS ((symbol_t *precsym));
void grammar_current_rule_symbol_append PARAMS ((symbol_t *symbol));
void grammar_current_rule_action_append PARAMS ((const char *action,
int line));
extern symbol_list *current_rule;
void reader PARAMS ((void)); void reader PARAMS ((void));
extern int lineno;
#endif /* !READER_H_ */ #endif /* !READER_H_ */

46
src/scan-action.l Normal file
View File

@@ -0,0 +1,46 @@
/* Scan User Actions. -*- C -*-
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
Bison 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 2, or (at your option)
any later version.
Bison 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 Bison; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
%option nodefault noyywrap nounput
%option prefix="action_" outfile="lex.yy.c"
%{
#include "system.h"
#include "files.h"
int skel_lex PARAMS ((void));
static int yylineno = 1;
%}
%x DOLLAR
ID [a-zA-Z]+
NUM -?[0-9]+
%%
$(-?[0-9])+ { fprintf (action_out, "yylsp[%s]", yytext + 1) ;}
@(-?[0-9])+ { fprintf (action_out, "yylsp[%s]", yytext + 1) ;}
$<{ID} { action_type = xstrndup (yytext + 2, yyleng - 2); BEGIN DOLLAR;}
$ { BEGIN DOLLAR;}
<DOLLAR>
{
{NUM}> { fprintf (action_out, "yyvsp[%s]", NUM }
}
%%

2750
src/scan-gram.c Normal file

File diff suppressed because it is too large Load Diff

582
src/scan-gram.l Normal file
View File

@@ -0,0 +1,582 @@
/* Bison Grammar Scanner -*- C -*-
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
This program 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 2 of the License, or
(at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/
%option debug nodefault noyywrap nounput never-interactive stack
%option prefix="gram_" outfile="lex.yy.c"
%{
#include "system.h"
#include "complain.h"
#include "quote.h"
#include "getargs.h"
#include "gram.h"
#include "reader.h"
/* Each time we match a string, move the end cursor to its end. */
#define YY_USER_ACTION LOCATION_COLUMNS (*yylloc, yyleng)
#define YY_LINES LOCATION_LINES (*yylloc, yyleng); lineno += yyleng;
#define YY_STEP LOCATION_STEP (*yylloc)
/* Appending to the STRING_OBSTACK. */
#define YY_INIT obstack_init (&string_obstack)
#define YY_GROW obstack_grow (&string_obstack, yytext, yyleng)
#define YY_FINISH obstack_1grow (&string_obstack, '\0'); yylval->string = obstack_finish (&string_obstack);
/* This is only to avoid GCC warnings. */
#define YY_USER_INIT if (yycontrol) {;};
static struct obstack string_obstack;
static int braces_level = 0;
static int percent_percent_count = 0;
static void handle_dollar PARAMS ((char *cp));
static void handle_at PARAMS ((char *cp));
%}
%x SC_COMMENT
%x SC_STRING SC_CHARACTER
%x SC_ESCAPED_STRING SC_ESCAPED_CHARACTER
%x SC_BRACED_CODE SC_PROLOGUE SC_EPILOGUE
id [.a-zA-Z][.a-zA-Z_0-9]*
int [0-9]+
eols (\n|\r|\n\r|\r\n)+
blanks [ \t\f]+
%%
%{
/* At each yylex invocation, mark the current position as the
start of the next token. */
#define TR_POS 0
#if TR_POS
fprintf (stderr, "FOO1: ");
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, "\n");
#endif
YY_STEP;
#if TR_POS
fprintf (stderr, "BAR1: ");
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, "\n");
#endif
%}
/*----------------------------.
| Scanning Bison directives. |
`----------------------------*/
<INITIAL>
{
"%binary" return PERCENT_NONASSOC;
"%debug" return PERCENT_DEBUG;
"%define" return PERCENT_DEFINE;
"%defines" return PERCENT_DEFINES;
"%error"[-_]"verbose" return PERCENT_ERROR_VERBOSE;
"%expect" return PERCENT_EXPECT;
"%file-prefix" return PERCENT_FILE_PREFIX;
"%fixed"[-_]"output"[-_]"files" return PERCENT_YACC;
"%left" return PERCENT_LEFT;
"%locations" return PERCENT_LOCATIONS;
"%name"[-_]"prefix" return PERCENT_NAME_PREFIX;
"%no"[-_]"lines" return PERCENT_NO_LINES;
"%nonassoc" return PERCENT_NONASSOC;
"%nterm" return PERCENT_NTERM;
"%output" return PERCENT_OUTPUT;
"%prec" return PERCENT_PREC;
"%pure"[-_]"parser" return PERCENT_PURE_PARSER;
"%right" return PERCENT_RIGHT;
"%skeleton" return PERCENT_SKELETON;
"%start" return PERCENT_START;
"%term" return PERCENT_TOKEN;
"%token" return PERCENT_TOKEN;
"%token"[-_]"table" return PERCENT_TOKEN_TABLE;
"%type" return PERCENT_TYPE;
"%union" return PERCENT_UNION;
"%verbose" return PERCENT_VERBOSE;
"%yacc" return PERCENT_YACC;
"=" return EQUAL;
":" return COLON;
"|" return PIPE;
";" return SEMICOLON;
{eols} YY_LINES; YY_STEP;
{blanks} YY_STEP;
{id} {
YY_INIT; YY_GROW; YY_FINISH;
yylval->symbol = getsym (yylval->string);
return ID;
}
{int} yylval->integer = strtol (yytext, 0, 10); return INT;
/* Characters. We don't check there is only one. */
\' YY_INIT; YY_GROW; yy_push_state (SC_ESCAPED_CHARACTER);
/* Strings. */
\" YY_INIT; YY_GROW; yy_push_state (SC_ESCAPED_STRING);
/* Comments. */
"/*" yy_push_state (SC_COMMENT);
"//".* YY_STEP;
/* Prologue. */
"%{" YY_INIT; yy_push_state (SC_PROLOGUE);
/* Code in between braces. */
"{" YY_INIT; YY_GROW; ++braces_level; yy_push_state (SC_BRACED_CODE);
/* A type. */
"<"[^>]+">" YY_INIT; obstack_grow (&string_obstack, yytext + 1, yyleng - 2); YY_FINISH; return TYPE;
"%%" {
if (++percent_percent_count == 2)
yy_push_state (SC_EPILOGUE);
return PERCENT_PERCENT;
}
. {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": invalid character: `%c'\n", *yytext);
YY_STEP;
}
}
/*------------------------------------------------------------.
| Whatever the start condition (but those which correspond to |
| entity `swallowed' by Bison: SC_ESCAPED_STRING and |
| SC_ESCAPED_CHARACTER), no M4 character must escape as is. |
`------------------------------------------------------------*/
<SC_COMMENT,SC_STRING,SC_CHARACTER,SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
{
\[ obstack_sgrow (&string_obstack, "@<:@");
\] obstack_sgrow (&string_obstack, "@:>@");
}
/*-----------------------------------------------------------.
| Scanning a C comment. The initial `/ *' is already eaten. |
`-----------------------------------------------------------*/
<SC_COMMENT>
{
"*/" { /* End of the comment. */
if (yy_top_state () == INITIAL)
{
YY_STEP;
}
else
{
YY_GROW;
}
yy_pop_state ();
}
[^\[\]*\n\r]+ if (yy_top_state () != INITIAL) YY_GROW;
{eols} if (yy_top_state () != INITIAL) YY_GROW; YY_LINES;
. /* Stray `*'. */if (yy_top_state () != INITIAL) YY_GROW;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a comment\n");
yy_pop_state ();
}
}
/*----------------------------------------------------------------.
| Scanning a C string, including its escapes. The initial `"' is |
| already eaten. |
`----------------------------------------------------------------*/
<SC_ESCAPED_STRING>
{
\" {
assert (yy_top_state () == INITIAL);
YY_GROW;
YY_FINISH;
yy_pop_state ();
return STRING;
}
[^\"\n\r\\]+ YY_GROW;
{eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a string\n");
assert (yy_top_state () == INITIAL);
YY_FINISH;
yy_pop_state ();
return STRING;
}
}
/*---------------------------------------------------------------.
| Scanning a C character, decoding its escapes. The initial "'" |
| is already eaten. |
`---------------------------------------------------------------*/
<SC_ESCAPED_CHARACTER>
{
\' {
YY_GROW;
assert (yy_top_state () == INITIAL);
{
char c;
YY_FINISH;
c = yylval->string[1];
yylval->symbol = getsym (yylval->string);
symbol_class_set (yylval->symbol, token_sym);
symbol_user_token_number_set (yylval->symbol, (unsigned int) c);
yy_pop_state ();
return ID;
}
}
[^\'\n\r\\] YY_GROW;
{eols} obstack_1grow (&string_obstack, '\n'); YY_LINES;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a character\n");
assert (yy_top_state () == INITIAL);
YY_FINISH;
yy_pop_state ();
return CHARACTER;
}
}
/*----------------------------.
| Decode escaped characters. |
`----------------------------*/
<SC_ESCAPED_STRING,SC_ESCAPED_CHARACTER>
{
\\[0-7]{3} {
long c = strtol (yytext + 1, 0, 8);
if (c > 255)
{
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": invalid escape: %s\n", yytext);
YY_STEP;
}
else
obstack_1grow (&string_obstack, c);
}
\\x[0-9a-fA-F]{2} {
obstack_1grow (&string_obstack, strtol (yytext + 2, 0, 16));
}
\\a obstack_1grow (&string_obstack, '\a');
\\b obstack_1grow (&string_obstack, '\b');
\\f obstack_1grow (&string_obstack, '\f');
\\n obstack_1grow (&string_obstack, '\n');
\\r obstack_1grow (&string_obstack, '\r');
\\t obstack_1grow (&string_obstack, '\t');
\\v obstack_1grow (&string_obstack, '\v');
\\[\\""] obstack_1grow (&string_obstack, yytext[1]);
\\. {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unrecognized escape: %s\n", yytext);
YY_GROW;
}
}
/*----------------------------------------------------------.
| Scanning a C character without decoding its escapes. The |
| initial "'" is already eaten. |
`----------------------------------------------------------*/
<SC_CHARACTER>
{
\' {
YY_GROW;
assert (yy_top_state () != INITIAL);
yy_pop_state ();
}
[^\[\]\'\n\r\\] YY_GROW;
\\. YY_GROW;
{eols} YY_GROW; YY_LINES;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a character\n");
assert (yy_top_state () != INITIAL);
yy_pop_state ();
}
}
/*----------------------------------------------------------------.
| Scanning a C string, without decoding its escapes. The initial |
| `"' is already eaten. |
`----------------------------------------------------------------*/
<SC_STRING>
{
\" {
assert (yy_top_state () != INITIAL);
YY_GROW;
yy_pop_state ();
}
[^\[\]\"\n\r\\]+ YY_GROW;
\\. YY_GROW;
{eols} YY_GROW; YY_LINES;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a string\n");
assert (yy_top_state () != INITIAL);
yy_pop_state ();
}
}
/*---------------------------------------------------.
| Strings, comments etc. can be found in user code. |
`---------------------------------------------------*/
<SC_BRACED_CODE,SC_PROLOGUE,SC_EPILOGUE>
{
/* Characters. We don't check there is only one. */
\' YY_GROW; yy_push_state (SC_CHARACTER);
/* Strings. */
\" YY_GROW; yy_push_state (SC_STRING);
/* Comments. */
"/*" YY_GROW; yy_push_state (SC_COMMENT);
"//".* YY_GROW;
}
/*---------------------------------------------------------------.
| Scanning some code in braces (%union and actions). The initial |
| "{" is already eaten. |
`---------------------------------------------------------------*/
<SC_BRACED_CODE>
{
"}" {
YY_GROW;
if (--braces_level == 0)
{
yy_pop_state ();
YY_FINISH;
return BRACED_CODE;
}
}
"{" YY_GROW; braces_level++;
"$"("<".*">")?(-?[0-9]+|"$") { handle_dollar (yytext); }
"@"(-?[0-9]+|"$") { handle_at (yytext); }
[^\[\]$/\'\"@\{\}\n\r]+ YY_GROW;
{eols} YY_GROW; YY_LINES;
/* A lose $, or /, or etc. */
. YY_GROW;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a braced code\n");
yy_pop_state ();
YY_FINISH;
return PROLOGUE;
}
}
/*--------------------------------------------------------------.
| Scanning some prologue: from "%{" (already scanned) to "%}". |
`--------------------------------------------------------------*/
<SC_PROLOGUE>
{
"%}" {
yy_pop_state ();
YY_FINISH;
return PROLOGUE;
}
[^\[\]%\n\r]+ YY_GROW;
"%"+[^%\}\n\r]+ YY_GROW;
{eols} YY_GROW; YY_LINES;
<<EOF>> {
LOCATION_PRINT (stderr, *yylloc);
fprintf (stderr, ": unexpected end of file in a prologue\n");
yy_pop_state ();
YY_FINISH;
return PROLOGUE;
}
}
/*---------------------------------------------------------------.
| Scanning the epilogue (everything after the second "%%", which |
| has already been eaten. |
`---------------------------------------------------------------*/
<SC_EPILOGUE>
{
([^\[\]]|{eols})+ YY_GROW;
<<EOF>> {
yy_pop_state ();
YY_FINISH;
return EPILOGUE;
}
}
%%
/*------------------------------------------------------------------.
| CP is pointing to a wannabee semantic value (i.e., a `$'). |
| |
| Possible inputs: $[<TYPENAME>]($|integer) |
| |
| Output to the STRING_OBSTACK a reference to this semantic value. |
`------------------------------------------------------------------*/
static void
handle_dollar (char *cp)
{
const char *type_name = NULL;
/* RULE_LENGTH is the number of values in the current rule so far,
which says where to find `$0' with respect to the top of the
stack. It is not the same as the rule->length in the case of mid
rule actions. */
int rule_length = 0;
symbol_list *rhs;
for (rhs = current_rule->next; rhs; rhs = rhs->next)
++rule_length;
++cp;
/* Get the type name if explicit. */
if (*cp == '<')
{
type_name = ++cp;
while (*cp != '>')
++cp;
*cp = '\0';
++cp;
}
if (*cp == '$')
{
if (!type_name)
type_name = get_type_name (0, current_rule);
if (!type_name && typed)
complain (_("$$ of `%s' has no declared type"),
current_rule->sym->tag);
if (!type_name)
type_name = "";
obstack_fgrow1 (&string_obstack,
"]b4_lhs_value([%s])[", type_name);
}
else if (isdigit (*cp) || *cp == '-')
{
int n = strtol (cp, &cp, 10);
if (n > rule_length)
complain (_("invalid value: %s%d"), "$", n);
else
{
if (!type_name && n > 0)
type_name = get_type_name (n, current_rule);
if (!type_name && typed)
complain (_("$%d of `%s' has no declared type"),
n, current_rule->sym->tag);
if (!type_name)
type_name = "";
obstack_fgrow3 (&string_obstack,
"]b4_rhs_value([%d], [%d], [%s])[",
rule_length, n, type_name);
}
}
else
{
char buf[] = "$c";
buf[1] = *cp;
complain (_("%s is invalid"), quote (buf));
}
}
/*-------------------------------------------------------.
| CP is pointing to a location (i.e., a `@'). Output to |
| STRING_OBSTACK a reference to this location. |
`-------------------------------------------------------*/
static void
handle_at (char *cp)
{
/* RULE_LENGTH is the number of values in the current rule so far,
which says where to find `$0' with respect to the top of the
stack. It is not the same as the rule->length in the case of mid
rule actions. */
int rule_length = 0;
symbol_list *rhs;
for (rhs = current_rule->next; rhs; rhs = rhs->next)
++rule_length;
locations_flag = 1;
++cp;
if (*cp == '$')
{
obstack_sgrow (&string_obstack, "]b4_lhs_location[");
}
else if (isdigit (*cp) || *cp == '-')
{
int n = strtol (cp, &cp, 10);
if (n > rule_length)
complain (_("invalid value: %s%d"), "@", n);
else
obstack_fgrow2 (&string_obstack, "]b4_rhs_location([%d], [%d])[",
rule_length, n);
}
else
{
char buf[] = "@c";
buf[1] = *cp;
complain (_("%s is invalid"), quote (buf));
}
}

View File

@@ -54,36 +54,46 @@ symbol_new (const char *tag)
res->class = unknown_sym; res->class = unknown_sym;
nsyms++; nsyms++;
return res; return res;
} }
/*-----------------------------------------. /*------------------------------------------------------------------.
| Set the TYPE_NAME associated to SYMBOL. | | Set the TYPE_NAME associated to SYMBOL. Does nothing if passed 0 |
`-----------------------------------------*/ | as TYPE_NAME. |
`------------------------------------------------------------------*/
void void
symbol_type_set (symbol_t *symbol, char *type_name) symbol_type_set (symbol_t *symbol, char *type_name)
{ {
if (symbol->type_name) if (type_name)
complain (_("type redeclaration for %s"), symbol->tag); {
symbol->type_name = type_name; if (symbol->type_name)
complain (_("type redeclaration for %s"), symbol->tag);
symbol->type_name = type_name;
}
} }
/*------------------------------------------. /*------------------------------------------------------------------.
| Set the PRECEDENCE associated to SYMBOL. | | Set the PRECEDENCE associated to SYMBOL. Does nothing if invoked |
`------------------------------------------*/ | with UNDEF_ASSOC as ASSOC. |
`------------------------------------------------------------------*/
void void
symbol_precedence_set (symbol_t *symbol, symbol_precedence_set (symbol_t *symbol,
int prec, associativity assoc) int prec, associativity assoc)
{ {
if (symbol->prec != 0) if (assoc != undef_assoc)
complain (_("redefining precedence of %s"), symbol->tag); {
symbol->prec = prec; if (symbol->prec != 0)
symbol->assoc = assoc; complain (_("redefining precedence of %s"), symbol->tag);
symbol->prec = prec;
symbol->assoc = assoc;
}
/* Only terminals have a precedence. */
symbol_class_set (symbol, token_sym);
} }
@@ -176,7 +186,7 @@ symbol_check_defined (symbol_t *this)
`-------------------------------------------------------------------*/ `-------------------------------------------------------------------*/
void void
symbol_make_alias (symbol_t *symbol, symbol_t *symval, char *typename) symbol_make_alias (symbol_t *symbol, symbol_t *symval)
{ {
if (symval->alias) if (symval->alias)
warn (_("symbol `%s' used more than once as a literal string"), warn (_("symbol `%s' used more than once as a literal string"),
@@ -187,7 +197,6 @@ symbol_make_alias (symbol_t *symbol, symbol_t *symval, char *typename)
else else
{ {
symval->class = token_sym; symval->class = token_sym;
symval->type_name = typename;
symval->user_token_number = symbol->user_token_number; symval->user_token_number = symbol->user_token_number;
symbol->user_token_number = USER_NUMBER_ALIAS; symbol->user_token_number = USER_NUMBER_ALIAS;
symval->alias = symbol; symval->alias = symbol;
@@ -226,8 +235,12 @@ symbol_check_alias_consistence (symbol_t *this)
if (this->assoc != this->alias->assoc) if (this->assoc != this->alias->assoc)
{ {
if (this->assoc != 0 && this->alias->assoc != 0) /* FIXME: For some reason (probably the S/R => keep the S),
complain (_("conflicting assoc values for %s and %s"), the right assoc is chosen has the ``not set''. This is
not nice, fix this! */
if (this->assoc != right_assoc
&& this->alias->assoc != right_assoc)
complain (_("conflicting associativities for %s and %s"),
this->tag, this->alias->tag); this->tag, this->alias->tag);
if (this->assoc != 0) if (this->assoc != 0)
this->alias->assoc = this->assoc; this->alias->assoc = this->assoc;

View File

@@ -29,6 +29,7 @@
/* Associativity values for tokens and rules. */ /* Associativity values for tokens and rules. */
typedef enum typedef enum
{ {
undef_assoc,
right_assoc, right_assoc,
left_assoc, left_assoc,
non_assoc non_assoc
@@ -84,15 +85,15 @@ struct symbol_s
/* Fetch (or create) the symbol associated to KEY. */ /* Fetch (or create) the symbol associated to KEY. */
symbol_t *getsym PARAMS ((const char *key)); symbol_t *getsym PARAMS ((const char *key));
/* Declare the new SYMBOL. Make it an alias of SYMVAL, and type */ /* Declare the new SYMBOL. Make it an alias of SYMVAL. */
/* them with TYPENAME. */ void symbol_make_alias PARAMS ((symbol_t *symbol, symbol_t *symval));
void symbol_make_alias PARAMS ((symbol_t *symbol, symbol_t *symval,
char *typename));
/* Set the TYPE_NAME associated to SYMBOL. */ /* Set the TYPE_NAME associated to SYMBOL. Does nothing if passed 0 as
TYPE_NAME. */
void symbol_type_set PARAMS ((symbol_t *symbol, char *type_name)); void symbol_type_set PARAMS ((symbol_t *symbol, char *type_name));
/* Set the PRECEDENCE associated to SYMBOL. */ /* Set the PRECEDENCE associated to SYMBOL. Ensures that SYMBOL is a
terminal. Does nothing if invoked with UNDEF_ASSOC as ASSOC. */
void symbol_precedence_set PARAMS ((symbol_t *symbol, void symbol_precedence_set PARAMS ((symbol_t *symbol,
int prec, associativity assoc)); int prec, associativity assoc));
@@ -131,8 +132,8 @@ void symbols_do PARAMS ((symbol_processor processor, void *processor_data));
/* Free all the memory allocated for symbols. */ /* Free all the memory allocated for symbols. */
void symbols_free PARAMS ((void)); void symbols_free PARAMS ((void));
/* Check that all the symbols are defined. Report any undefined */ /* Check that all the symbols are defined. Report any undefined
/* symbols and consider them nonterminals. */ symbols and consider them nonterminals. */
void symbols_check_defined PARAMS ((void)); void symbols_check_defined PARAMS ((void));
/* Perform various sanity checks, assign symbol numbers, and set up /* Perform various sanity checks, assign symbol numbers, and set up

View File

@@ -144,14 +144,22 @@ void *memrchr PARAMS ((const void *s, int c, size_t n));
(__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__
# define __attribute__(Spec) /* empty */ # define __attribute__(Spec) /* empty */
# endif # endif
/* The __-protected variants of `format' and `printf' attributes
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __format__ format
# define __printf__ printf
# endif
#endif #endif
/* The __-protected variants of `format' and `printf' attributes
are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */
#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7)
# define __format__ format
# define __printf__ printf
#endif
#ifndef ATTRIBUTE_NORETURN
# define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#endif
#ifndef ATTRIBUTE_UNUSED
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#endif
/*------. /*------.
| NLS. | | NLS. |

View File

@@ -89,7 +89,7 @@ char quote[] = "@:>@@:>@,";
%type <ival> exp %type <ival> exp
/* Exercise quotes in strings. */ /* Exercise quotes in strings. */
%token "fake @>:@@>:@," %token FAKE "fake @>:@@>:@,"
%nonassoc '=' /* comparison */ %nonassoc '=' /* comparison */
%left '-' '+' %left '-' '+'

View File

@@ -204,6 +204,7 @@ not_reachable: useful { /* A not reachable action. */ }
non_productive: non_productive useless_token non_productive: non_productive useless_token
{ /* Another non productive action. */ } { /* Another non productive action. */ }
; ;
%%
]]) ]])
AT_CHECK([[bison not-reduced.y]], 0, [], AT_CHECK([[bison not-reduced.y]], 0, [],
@@ -244,6 +245,7 @@ exp: useful { /* A useful action. */ }
//non_productive: non_productive useless_token //non_productive: non_productive useless_token
// { /* Another non productive action. */ } // { /* Another non productive action. */ }
// ; // ;
%%
]]) ]])
AT_CHECK([[bison reduced.y]]) AT_CHECK([[bison reduced.y]])

View File

@@ -287,40 +287,23 @@ AT_DATA([input.y],
[[%% [[%%
? ?
default: 'a' } default: 'a' }
%{
%& %&
%a %a
%- %-
%{
]]) ]])
AT_CHECK([bison input.y], [1], [], AT_CHECK([bison input.y], [1], [],
[[input.y:2: invalid input: `?' [[input.y:2.1: invalid character: `?'
input.y:3: invalid input: `}' input.y:3.14: invalid character: `}'
input.y:4: invalid input: `%{' input.y:4.1: invalid character: `%'
input.y:5: invalid input: `%&' input.y:4.2: invalid character: `&'
input.y:6: invalid input: `%a' input.y:5.1: invalid character: `%'
input.y:7: invalid input: `%-' input.y:6.1: invalid character: `%'
]]) input.y:6.2: invalid character: `-'
input.y:7.1-8.0: unexpected end of file in a prologue
AT_CLEANUP input.y:7.1-8.0: parse error, unexpected PROLOGUE, expecting ";" or "|"
input.y:8: symbol a is used, but is not defined as a token and has no rules
## -------------------- ##
## Invalid %directive. ##
## -------------------- ##
AT_SETUP([Invalid %directive])
AT_DATA([input.y],
[[%invalid
]])
AT_CHECK([bison input.y], [1], [],
[[input.y:1: unrecognized: %invalid
input.y:1: Skipping to next %
input.y:2: fatal error: no input grammar
]]) ]])
AT_CLEANUP AT_CLEANUP
@@ -340,13 +323,11 @@ AT_DATA([input.y],
void yyerror (const char *s); void yyerror (const char *s);
int yylex (void); int yylex (void);
%} %}
[%token "end of file" [%token YYEOF 0 "end of file"
%token 'a' "a" %token 'a' "a"
%token "b" 'b' %token b "b"
%token "c" c %token c 'c'
%token d "d" %token 'd' d
%token e 'e'
%token 'f' e
%% %%
exp: "a"; exp: "a";
]]) ]])

View File

@@ -33,7 +33,7 @@ AT_DATA([[input.y]],
[$2]) [$2])
AT_CHECK([bison input.y -o input.c]) AT_CHECK([bison input.y -o input.c])
AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -o input], 1, [], [stderr]) AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -c], 1, [], [stderr])
# In case GCC displays column information, strip it down. # In case GCC displays column information, strip it down.
# #
# input.y:4:2: #error "4" or input.y:4.2: #error "4" # input.y:4:2: #error "4" or input.y:4.2: #error "4"

View File

@@ -57,7 +57,7 @@ EOF
for my $size (1 .. $max) for my $size (1 .. $max)
{ {
print "%token \"$size\" ", $size, "\n"; print "%token t$size $size \"$size\"\n";
}; };
print <<EOF; print <<EOF;
@@ -128,7 +128,9 @@ AT_SETUP([Big triangle])
# I have been able to go up to 2000 on my machine. # I have been able to go up to 2000 on my machine.
# I tried 3000, a 29Mb grammar file, but then my system killed bison. # I tried 3000, a 29Mb grammar file, but then my system killed bison.
AT_DATA_TRIANGULAR_GRAMMAR([input.y], [500]) # With 500 and the new parser, which consume far too much memory,
# it gets killed too. Of course the parser is to be cleaned.
AT_DATA_TRIANGULAR_GRAMMAR([input.y], [200])
AT_CHECK([bison input.y -v -o input.c]) AT_CHECK([bison input.y -v -o input.c])
AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -o input], 0, [], [ignore]) AT_CHECK([$CC $CFLAGS $CPPFLAGS input.c -o input], 0, [], [ignore])
AT_CHECK([./input]) AT_CHECK([./input])
@@ -164,7 +166,7 @@ EOF
for my $size (1 .. $max) for my $size (1 .. $max)
{ {
print "%token \"$size\" ", $size, "\n"; print "%token t$size $size \"$size\"\n";
}; };
print <<EOF; print <<EOF;
@@ -272,12 +274,12 @@ EOF
print print
wrap ("%type <val> ", wrap ("%type <val> ",
" ", " ",
map { "token$_" } (1 .. $max)), map { "n$_" } (1 .. $max)),
"\n"; "\n";
for my $count (1 .. $max) for my $count (1 .. $max)
{ {
print "%token \"$count\" $count\n"; print "%token t$count $count \"$count\"\n";
}; };
print <<EOF; print <<EOF;
@@ -288,18 +290,18 @@ input:
; ;
exp: exp:
token1 "1" { assert (\@S|@1 == 1); } n1 "1" { assert (\@S|@1 == 1); }
EOF EOF
for my $count (2 .. $max) for my $count (2 .. $max)
{ {
print "| token$count \"$count\" { assert (\@S|@1 == $count); }\n"; print "| n$count \"$count\" { assert (\@S|@1 == $count); }\n";
}; };
print ";\n"; print ";\n";
for my $count (1 .. $max) for my $count (1 .. $max)
{ {
print "token$count: token { \$\$ = $count; };\n"; print "n$count: token { \$\$ = $count; };\n";
}; };
print <<EOF; print <<EOF;