mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-09 12:23:04 +00:00
* src/symtab.c (symbol_user_token_number_set): If the token has an alias, check and set its alias's user token number instead of its own, which is set to indicate the alias. Previously, every occurrence of the character token in the grammar overwrote that alias indicator with the character code. * tests/input.at (String aliases for character tokens): New test.
495 lines
12 KiB
Plaintext
495 lines
12 KiB
Plaintext
# Checking the Bison scanner. -*- Autotest -*-
|
|
# Copyright (C) 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
|
|
|
|
# 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
# 02110-1301, USA.
|
|
|
|
AT_BANNER([[Input Processing.]])
|
|
|
|
# Mostly test that we are robust to mistakes.
|
|
|
|
|
|
## ------------ ##
|
|
## Invalid $n. ##
|
|
## ------------ ##
|
|
|
|
AT_SETUP([Invalid \$n and @n])
|
|
|
|
AT_DATA([input.y],
|
|
[[%%
|
|
exp: { $$ = $1 ; };
|
|
exp: { @$ = @1 ; };
|
|
]])
|
|
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:2.13-14: integer out of range: `$1'
|
|
input.y:3.13-14: integer out of range: `@1'
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## -------------- ##
|
|
## Type Clashes. ##
|
|
## -------------- ##
|
|
|
|
AT_SETUP([Type Clashes])
|
|
|
|
AT_DATA([input.y],
|
|
[[%union { int bar; }
|
|
%token foo
|
|
%type <bar> exp
|
|
%%
|
|
exp: foo { $$; } foo { $2; } foo
|
|
| foo
|
|
| /* Empty. */
|
|
;
|
|
]])
|
|
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:5.12-13: $$ for the midrule at $2 of `exp' has no declared type
|
|
input.y:5.24-25: $2 of `exp' has no declared type
|
|
input.y:5.6-32: warning: type clash on default action: <bar> != <>
|
|
input.y:6.6-8: warning: type clash on default action: <bar> != <>
|
|
input.y:7.5: warning: empty rule for typed nonterminal, and no action
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
# _AT_UNUSED_VALUES_DECLARATIONS()
|
|
# --------------------------------------------
|
|
# Generate the token, type, and destructor
|
|
# declarations for the unused values tests.
|
|
|
|
m4_define([_AT_UNUSED_VALUES_DECLARATIONS],
|
|
[[[%token <integer> INT;
|
|
%type <integer> a b c d e f g h i j k l;
|
|
%destructor { destroy ($$); } INT a b c d e f g h i j k l;]]])
|
|
|
|
|
|
# AT_CHECK_UNUSED_VALUES(DECLARATIONS_AFTER)
|
|
# --------------------------------------------
|
|
# Generate a grammar to test unused values,
|
|
# compile it, run it. If DECLARATIONS_AFTER
|
|
# is set, then the token, type, and destructor
|
|
# declarations are generated after the rules
|
|
# rather than before.
|
|
|
|
m4_define([AT_CHECK_UNUSED_VALUES],
|
|
[AT_DATA([input.y],
|
|
m4_ifval($1, [
|
|
|
|
|
|
], [_AT_UNUSED_VALUES_DECLARATIONS
|
|
])[[%%
|
|
start:
|
|
'a' a { $]2[ } | 'b' b { $]2[ } | 'c' c { $]2[ } | 'd' d { $]2[ } | 'e' e { $]2[ }
|
|
| 'f' f { $]2[ } | 'g' g { $]2[ } | 'h' h { $]2[ } | 'i' i { $]2[ } | 'j' j { $]2[ }
|
|
| 'k' k { $]2[ } | 'l' l { $]2[ }
|
|
;
|
|
|
|
a: INT | INT { } INT { } INT { };
|
|
b: INT | /* empty */;
|
|
c: INT | INT { $]1[ } INT { } INT { };
|
|
d: INT | INT { } INT { $]1[ } INT { };
|
|
e: INT | INT { } INT { } INT { $]1[ };
|
|
f: INT | INT { } INT { } INT { $]$[ = $]1[ + $]3[ + $]5[; };
|
|
g: INT | INT { $<integer>$; } INT { $<integer>$; } INT { };
|
|
h: INT | INT { $<integer>$; } INT { $<integer>$ = $<integer>2; } INT { };
|
|
i: INT | INT INT { } { $]$[ = $]1[ + $]2[; };
|
|
j: INT | INT INT { $<integer>$ = 1; } { $]$[ = $]1[ + $]2[; };
|
|
k: INT | INT INT { $<integer>$; } { $<integer>$ = $<integer>3; } { };
|
|
l: INT | INT { $<integer>$ = $<integer>1; } INT { $<integer>$ = $<integer>2 + $<integer>3; } INT { $<integer>$ = $<integer>4 + $<integer>5; };]]m4_ifval($1, [
|
|
_AT_UNUSED_VALUES_DECLARATIONS])
|
|
)
|
|
|
|
AT_CHECK([bison input.y], [0], [],
|
|
[[input.y:11.10-32: warning: unset value: $]$[
|
|
input.y:11.10-32: warning: unused value: $]1[
|
|
input.y:11.10-32: warning: unused value: $]3[
|
|
input.y:11.10-32: warning: unused value: $]5[
|
|
input.y:12.9: warning: empty rule for typed nonterminal, and no action
|
|
input.y:13.10-35: warning: unset value: $]$[
|
|
input.y:13.10-35: warning: unused value: $]3[
|
|
input.y:13.10-35: warning: unused value: $]5[
|
|
input.y:14.10-35: warning: unset value: $]$[
|
|
input.y:14.10-35: warning: unused value: $]3[
|
|
input.y:14.10-35: warning: unused value: $]5[
|
|
input.y:15.10-36: warning: unset value: $]$[
|
|
input.y:15.10-36: warning: unused value: $]3[
|
|
input.y:15.10-36: warning: unused value: $]5[
|
|
input.y:17.10-58: warning: unset value: $]$[
|
|
input.y:17.10-58: warning: unused value: $]1[
|
|
input.y:17.10-58: warning: unused value: $]2[
|
|
input.y:17.10-58: warning: unused value: $]3[
|
|
input.y:17.10-58: warning: unused value: $]4[
|
|
input.y:17.10-58: warning: unused value: $]5[
|
|
input.y:18.10-72: warning: unset value: $]$[
|
|
input.y:18.10-72: warning: unused value: $]1[
|
|
input.y:18.10-72: warning: unused value: $]3[
|
|
input.y:18.10-72: warning: unused value: $]4[
|
|
input.y:18.10-72: warning: unused value: $]5[
|
|
input.y:20.10-55: warning: unused value: $]3[
|
|
input.y:21.10-68: warning: unset value: $]$[
|
|
input.y:21.10-68: warning: unused value: $]1[
|
|
input.y:21.10-68: warning: unused value: $]2[
|
|
input.y:21.10-68: warning: unused value: $]4[
|
|
]])])
|
|
|
|
|
|
## --------------- ##
|
|
## Unused values. ##
|
|
## --------------- ##
|
|
|
|
AT_SETUP([Unused values])
|
|
AT_CHECK_UNUSED_VALUES
|
|
AT_CLEANUP
|
|
|
|
|
|
## ------------------------------------------ ##
|
|
## Unused values before symbol declarations. ##
|
|
## ------------------------------------------ ##
|
|
|
|
AT_SETUP([Unused values before symbol declarations])
|
|
AT_CHECK_UNUSED_VALUES([1])
|
|
AT_CLEANUP
|
|
|
|
|
|
## --------------------------------------------- ##
|
|
## Default %printer and %destructor redeclared. ##
|
|
## --------------------------------------------- ##
|
|
|
|
AT_SETUP([Default %printer and %destructor redeclared])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%destructor { destroy ($$); }
|
|
%printer { destroy ($$); }
|
|
|
|
%destructor { destroy ($$); }
|
|
%printer { destroy ($$); }
|
|
|
|
%%
|
|
|
|
start: ;
|
|
|
|
%destructor { destroy ($$); };
|
|
%printer { destroy ($$); };
|
|
]])
|
|
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:4.13-29: redeclaration for default %destructor
|
|
input.y:1.13-29: previous declaration
|
|
input.y:5.10-26: redeclaration for default %printer
|
|
input.y:2.10-26: previous declaration
|
|
input.y:11.13-29: redeclaration for default %destructor
|
|
input.y:4.13-29: previous declaration
|
|
input.y:12.10-26: redeclaration for default %printer
|
|
input.y:5.10-26: previous declaration
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------------------------------- ##
|
|
## Unused values with default %destructor. ##
|
|
## ---------------------------------------- ##
|
|
|
|
AT_SETUP([Unused values with default %destructor])
|
|
|
|
AT_DATA([[input.y]],
|
|
[[%destructor { destroy ($$); }
|
|
|
|
%%
|
|
|
|
start: end end { $1; } ;
|
|
end: { } ;
|
|
]])
|
|
|
|
AT_CHECK([bison input.y], [0], [],
|
|
[[input.y:5.8-22: warning: unset value: $$
|
|
input.y:5.8-22: warning: unused value: $2
|
|
input.y:6.6-8: warning: unset value: $$
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------------- ##
|
|
## Incompatible Aliases. ##
|
|
## ---------------------- ##
|
|
|
|
AT_SETUP([Incompatible Aliases])
|
|
|
|
AT_DATA([input.y],
|
|
[[%token foo "foo"
|
|
|
|
%type <bar> foo
|
|
%printer {bar} foo
|
|
%destructor {bar} foo
|
|
%left foo
|
|
|
|
%type <baz> "foo"
|
|
%printer {baz} "foo"
|
|
%destructor {baz} "foo"
|
|
%left "foo"
|
|
|
|
%%
|
|
exp: foo;
|
|
]])
|
|
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:8.7-11: %type redeclaration for foo
|
|
input.y:3.7-11: previous declaration
|
|
input.y:10.13-17: %destructor redeclaration for foo
|
|
input.y:5.13-17: previous declaration
|
|
input.y:9.10-14: %printer redeclaration for foo
|
|
input.y:4.10-14: previous declaration
|
|
input.y:11.1-5: %left redeclaration for foo
|
|
input.y:6.1-5: previous declaration
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
|
|
## ----------------------- ##
|
|
## Torturing the Scanner. ##
|
|
## ----------------------- ##
|
|
|
|
# Be sure to compile and run, so that the C compiler checks what
|
|
# we do.
|
|
|
|
AT_SETUP([Torturing the Scanner])
|
|
|
|
|
|
AT_DATA([input.y], [])
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:1.1: syntax error, unexpected end of file
|
|
]])
|
|
|
|
|
|
AT_DATA([input.y],
|
|
[{}
|
|
])
|
|
AT_CHECK([bison input.y], [1], [],
|
|
[[input.y:1.1-2: syntax error, unexpected {...}
|
|
]])
|
|
|
|
|
|
AT_DATA_GRAMMAR([input.y],
|
|
[[%{
|
|
/* This is seen in GCC: a %{ and %} in middle of a comment. */
|
|
const char *foo = "So %{ and %} can be here too.";
|
|
|
|
#if 0
|
|
/* These examples test Bison while not stressing C compilers too much.
|
|
Many C compilers mishandle backslash-newlines, so this part of the
|
|
test is inside "#if 0". The comment and string are written so that
|
|
the "#endif" will be seen regardless of the C compiler bugs that we
|
|
know about, namely:
|
|
|
|
HP C (as of late 2002) mishandles *\[newline]\[newline]/ within a
|
|
comment.
|
|
|
|
The Apple Darwin compiler (as of late 2002) mishandles
|
|
\\[newline]' within a character constant.
|
|
|
|
*/
|
|
|
|
/\
|
|
* A comment with backslash-newlines in it. %} *\
|
|
\
|
|
/
|
|
/* { Close the above comment, if the C compiler mishandled it. */
|
|
|
|
char str[] = "\\
|
|
" A string with backslash-newlines in it %{ %} \\
|
|
\
|
|
"";
|
|
|
|
char apostrophe = '\'';
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
%}
|
|
/* %{ and %} can be here too. */
|
|
|
|
%{
|
|
/* Exercise pre-prologue dependency to %union. */
|
|
typedef int value;
|
|
%}
|
|
|
|
/* Exercise M4 quoting: '@:>@@:>@', 0. */
|
|
|
|
/* Also exercise %union. */
|
|
%union
|
|
{
|
|
value ival; /* A comment to exercise an old bug. */
|
|
};
|
|
|
|
|
|
/* Exercise post-prologue dependency to %union. */
|
|
%{
|
|
static YYSTYPE value_as_yystype (value val);
|
|
|
|
/* Exercise quotes in declarations. */
|
|
char quote[] = "@:>@@:>@,";
|
|
%}
|
|
|
|
%{
|
|
static void yyerror (const char *s);
|
|
static int yylex (void);
|
|
%}
|
|
|
|
%type <ival> '@<:@'
|
|
|
|
/* Exercise quotes in strings. */
|
|
%token FAKE "fake @<:@@:>@ \a\b\f\n\r\t\v\"\'\?\\\u005B\U0000005c ??!??'??(??)??-??/??<??=??> \x1\1"
|
|
|
|
%%
|
|
/* Exercise M4 quoting: '@:>@@:>@', @<:@, 1. */
|
|
exp: '@<:@' '\1' two '$' '@' '{' oline output.or.oline.opt
|
|
{
|
|
/* Exercise quotes in braces. */
|
|
char tmp[] = "@<:@%c@:>@,\n";
|
|
printf (tmp, $1);
|
|
}
|
|
;
|
|
|
|
two: '\x000000000000000000000000000000000000000000000000000000000000000000002';
|
|
oline: '@' 'o' 'l' 'i' 'n' 'e' '@' '_' '_' 'o' 'l' 'i' 'n' 'e' '_' '_';
|
|
output.or.oline.opt: ;|oline;;|output;;;
|
|
output: '#' 'o' 'u' 't' 'p' 'u' 't' ' ';
|
|
%%
|
|
/* Exercise M4 quoting: '@:>@@:>@', @<:@, 2. */
|
|
|
|
static YYSTYPE
|
|
value_as_yystype (value val)
|
|
{
|
|
YYSTYPE res;
|
|
res.ival = val;
|
|
return res;
|
|
}
|
|
|
|
static int
|
|
yylex (void)
|
|
{
|
|
static const char *input = "@<:@\1\2$@{@oline@__@&t@oline__\
|
|
#output "; /* "
|
|
*/
|
|
yylval = value_as_yystype (*input);
|
|
return *input++;
|
|
}
|
|
|
|
static void
|
|
yyerror (const char *msg)
|
|
{
|
|
fprintf (stderr, "%s\n", msg);
|
|
}
|
|
]])
|
|
|
|
# Pacify Emacs'font-lock-mode: "
|
|
|
|
AT_DATA([main.c],
|
|
[[typedef int value;
|
|
#include "input.h"
|
|
|
|
int yyparse (void);
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
return yyparse ();
|
|
}
|
|
]])
|
|
|
|
AT_CHECK([bison -d -v -o input.c input.y])
|
|
AT_COMPILE([input.o], [-c input.c])
|
|
AT_COMPILE([main.o], [-c main.c])
|
|
AT_COMPILE([input], [input.o main.o])
|
|
AT_PARSER_CHECK([./input], 0,
|
|
[[[@<:@],
|
|
]])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## ---------------------- ##
|
|
## Typed symbol aliases. ##
|
|
## ---------------------- ##
|
|
|
|
AT_SETUP([Typed symbol aliases])
|
|
|
|
# Bison 2.0 broke typed symbol aliases - ensure they work.
|
|
|
|
AT_DATA_GRAMMAR([input.y],
|
|
[[%union
|
|
{
|
|
int val;
|
|
};
|
|
%token <val> MY_TOKEN "MY TOKEN"
|
|
%type <val> exp
|
|
%%
|
|
exp: "MY TOKEN";
|
|
%%
|
|
]])
|
|
|
|
AT_CHECK([bison -o input.c input.y])
|
|
|
|
AT_CLEANUP
|
|
|
|
|
|
## --------- ##
|
|
## Require. ##
|
|
## --------- ##
|
|
|
|
m4_define([AT_CHECK_REQUIRE],
|
|
[AT_SETUP([Require $1])
|
|
AT_DATA_GRAMMAR([input.y],
|
|
[[%require "$1";
|
|
%%
|
|
empty_file:;
|
|
]])
|
|
AT_CHECK([bison -o input.c input.y], $2, [], ignore)
|
|
AT_CLEANUP
|
|
])
|
|
|
|
AT_CHECK_REQUIRE(1.0, 0)
|
|
AT_CHECK_REQUIRE(AT_PACKAGE_VERSION, 0)
|
|
## FIXME: Some day augment this version number.
|
|
AT_CHECK_REQUIRE(100.0, 63)
|
|
|
|
|
|
## ------------------------------------- ##
|
|
## String aliases for character tokens. ##
|
|
## ------------------------------------- ##
|
|
|
|
AT_SETUP([String aliases for character tokens])
|
|
|
|
# Bison once thought a character token and its alias were different symbols
|
|
# with the same user token number.
|
|
|
|
AT_DATA_GRAMMAR([input.y],
|
|
[[%token 'a' "a"
|
|
%%
|
|
start: 'a';
|
|
%%
|
|
]])
|
|
|
|
AT_CHECK([bison -o input.c input.y])
|
|
|
|
AT_CLEANUP
|