mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-20 09:43:03 +00:00
Support parametric types.
There are two issues to handle: first scanning nested angle bracket pairs to support types such as std::pair< std::string, std::list<std::string> > >. Another issue is to address idiosyncracies of C++: do not glue two closing angle brackets together (otherwise it's operator>>), and avoid sticking blindly a TYPE to the opening <, as it can result in '<:' which is a digraph for '['. * src/scan-gram.l (brace_level): Rename as... (nesting): this. (SC_TAG): New. Implement support for complex tags. (tag): Accept \n, but not <. * data/lalr1.cc (b4_symbol_value, b4_symbol_value_template) (b4_symbol_variant): Leave space around types as parameters. * examples/variant.yy: Use nested template types and leading ::. * src/parse-gram.y (TYPE, TYPE_TAG_ANY, TYPE_TAG_NONE, type.opt): Rename as... (TAG, TAG_ANY, TAG_NONE, tag.opt): these. * tests/c++.at: Test parametric types.
This commit is contained in:
25
ChangeLog
25
ChangeLog
@@ -1,3 +1,28 @@
|
|||||||
|
2008-11-15 Akim Demaille <demaille@gostai.com>
|
||||||
|
|
||||||
|
Support parametric types.
|
||||||
|
There are two issues to handle: first scanning nested angle bracket pairs
|
||||||
|
to support types such as std::pair< std::string, std::list<std::string> > >.
|
||||||
|
|
||||||
|
Another issue is to address idiosyncracies of C++: do not glue two closing
|
||||||
|
angle brackets together (otherwise it's operator>>), and avoid sticking
|
||||||
|
blindly a TYPE to the opening <, as it can result in '<:' which is a
|
||||||
|
digraph for '['.
|
||||||
|
|
||||||
|
* src/scan-gram.l (brace_level): Rename as...
|
||||||
|
(nesting): this.
|
||||||
|
(SC_TAG): New.
|
||||||
|
Implement support for complex tags.
|
||||||
|
(tag): Accept
|
||||||
|
, but not <.
|
||||||
|
* data/lalr1.cc (b4_symbol_value, b4_symbol_value_template)
|
||||||
|
(b4_symbol_variant): Leave space around types as parameters.
|
||||||
|
* examples/variant.yy: Use nested template types and leading ::.
|
||||||
|
* src/parse-gram.y (TYPE, TYPE_TAG_ANY, TYPE_TAG_NONE, type.opt):
|
||||||
|
Rename as...
|
||||||
|
(TAG, TAG_ANY, TAG_NONE, tag.opt): these.
|
||||||
|
* tests/c++.at: Test parametric types.
|
||||||
|
|
||||||
2008-11-15 Akim Demaille <akim@betelgeuse.gostai.ensta.fr>
|
2008-11-15 Akim Demaille <akim@betelgeuse.gostai.ensta.fr>
|
||||||
|
|
||||||
Test token.prefix.
|
Test token.prefix.
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ b4_variant_if([
|
|||||||
# ----------------------------
|
# ----------------------------
|
||||||
m4_define([b4_symbol_value],
|
m4_define([b4_symbol_value],
|
||||||
[m4_ifval([$2],
|
[m4_ifval([$2],
|
||||||
[$1.as<$2>()],
|
[$1.as< $2 >()],
|
||||||
[$1])])
|
[$1])])
|
||||||
|
|
||||||
# b4_symbol_value_template(VAL, [TYPE])
|
# b4_symbol_value_template(VAL, [TYPE])
|
||||||
@@ -80,7 +80,7 @@ b4_variant_if([
|
|||||||
# Same as b4_symbol_value, but used in a template method.
|
# Same as b4_symbol_value, but used in a template method.
|
||||||
m4_define([b4_symbol_value_template],
|
m4_define([b4_symbol_value_template],
|
||||||
[m4_ifval([$2],
|
[m4_ifval([$2],
|
||||||
[$1.template as<$2>()],
|
[$1.template as< $2 >()],
|
||||||
[$1])])
|
[$1])])
|
||||||
]) # b4_variant_if
|
]) # b4_variant_if
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ m4_map([b4_symbol_constructor_definition_], m4_defn([b4_symbol_numbers]))])])
|
|||||||
# YYTYPE.
|
# YYTYPE.
|
||||||
m4_define([b4_symbol_variant],
|
m4_define([b4_symbol_variant],
|
||||||
[m4_pushdef([b4_dollar_dollar],
|
[m4_pushdef([b4_dollar_dollar],
|
||||||
[$2.$3<$][3>(m4_shift3($@))])dnl
|
[$2.$3< $][3 >(m4_shift3($@))])dnl
|
||||||
switch ($1)
|
switch ($1)
|
||||||
{
|
{
|
||||||
m4_map([b4_type_action_], m4_defn([b4_type_names]))[]dnl
|
m4_map([b4_type_action_], m4_defn([b4_type_names]))[]dnl
|
||||||
|
|||||||
@@ -46,13 +46,14 @@ typedef std::list<std::string> strings_type;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
%token <std::string> TEXT;
|
%token <::std::string> TEXT;
|
||||||
%token <int> NUMBER;
|
%token <int> NUMBER;
|
||||||
%printer { debug_stream () << $$; } <int> <std::string> <strings_type>;
|
%printer { debug_stream () << $$; }
|
||||||
|
<int> <::std::string> <::std::list<std::string>>;
|
||||||
%token END_OF_FILE 0;
|
%token END_OF_FILE 0;
|
||||||
|
|
||||||
%type <std::string> item;
|
%type <::std::string> item;
|
||||||
%type <strings_type> list;
|
%type <::std::list<std::string>> list;
|
||||||
|
|
||||||
%%
|
%%
|
||||||
|
|
||||||
|
|||||||
@@ -167,9 +167,9 @@ static int current_prec = 0;
|
|||||||
%token PIPE "|"
|
%token PIPE "|"
|
||||||
%token PROLOGUE "%{...%}"
|
%token PROLOGUE "%{...%}"
|
||||||
%token SEMICOLON ";"
|
%token SEMICOLON ";"
|
||||||
%token TYPE "type"
|
%token TAG "<tag>"
|
||||||
%token TYPE_TAG_ANY "<*>"
|
%token TAG_ANY "<*>"
|
||||||
%token TYPE_TAG_NONE "<>"
|
%token TAG_NONE "<>"
|
||||||
|
|
||||||
%type <character> CHAR
|
%type <character> CHAR
|
||||||
%printer { fputs (char_name ($$), stderr); } CHAR
|
%printer { fputs (char_name ($$), stderr); } CHAR
|
||||||
@@ -183,8 +183,8 @@ static int current_prec = 0;
|
|||||||
%printer { fprintf (stderr, "{\n%s\n}", $$); }
|
%printer { fprintf (stderr, "{\n%s\n}", $$); }
|
||||||
braceless content.opt "{...}" "%{...%}" EPILOGUE
|
braceless content.opt "{...}" "%{...%}" EPILOGUE
|
||||||
|
|
||||||
%type <uniqstr> TYPE ID ID_COLON variable
|
%type <uniqstr> TAG ID ID_COLON variable
|
||||||
%printer { fprintf (stderr, "<%s>", $$); } TYPE
|
%printer { fprintf (stderr, "<%s>", $$); } TAG
|
||||||
%printer { fputs ($$, stderr); } ID variable
|
%printer { fputs ($$, stderr); } ID variable
|
||||||
%printer { fprintf (stderr, "%s:", $$); } ID_COLON
|
%printer { fprintf (stderr, "%s:", $$); } ID_COLON
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ symbol_declaration:
|
|||||||
current_class = unknown_sym;
|
current_class = unknown_sym;
|
||||||
current_type = NULL;
|
current_type = NULL;
|
||||||
}
|
}
|
||||||
| "%type" TYPE symbols.1
|
| "%type" TAG symbols.1
|
||||||
{
|
{
|
||||||
symbol_list *list;
|
symbol_list *list;
|
||||||
tag_seen = true;
|
tag_seen = true;
|
||||||
@@ -398,7 +398,7 @@ symbol_declaration:
|
|||||||
;
|
;
|
||||||
|
|
||||||
precedence_declaration:
|
precedence_declaration:
|
||||||
precedence_declarator type.opt symbols.prec
|
precedence_declarator tag.opt symbols.prec
|
||||||
{
|
{
|
||||||
symbol_list *list;
|
symbol_list *list;
|
||||||
++current_prec;
|
++current_prec;
|
||||||
@@ -419,9 +419,9 @@ precedence_declarator:
|
|||||||
| "%precedence" { $$ = precedence_assoc; }
|
| "%precedence" { $$ = precedence_assoc; }
|
||||||
;
|
;
|
||||||
|
|
||||||
type.opt:
|
tag.opt:
|
||||||
/* Nothing. */ { current_type = NULL; }
|
/* Nothing. */ { current_type = NULL; }
|
||||||
| TYPE { current_type = $1; tag_seen = true; }
|
| TAG { current_type = $1; tag_seen = true; }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Just like symbols.1 but accept INT for the sake of POSIX. */
|
/* Just like symbols.1 but accept INT for the sake of POSIX. */
|
||||||
@@ -451,15 +451,15 @@ generic_symlist:
|
|||||||
;
|
;
|
||||||
|
|
||||||
generic_symlist_item:
|
generic_symlist_item:
|
||||||
symbol { $$ = symbol_list_sym_new ($1, @1); }
|
symbol { $$ = symbol_list_sym_new ($1, @1); }
|
||||||
| TYPE { $$ = symbol_list_type_new ($1, @1); }
|
| TAG { $$ = symbol_list_type_new ($1, @1); }
|
||||||
| "<*>" { $$ = symbol_list_default_tagged_new (@1); }
|
| "<*>" { $$ = symbol_list_default_tagged_new (@1); }
|
||||||
| "<>" { $$ = symbol_list_default_tagless_new (@1); }
|
| "<>" { $$ = symbol_list_default_tagless_new (@1); }
|
||||||
;
|
;
|
||||||
|
|
||||||
/* One token definition. */
|
/* One token definition. */
|
||||||
symbol_def:
|
symbol_def:
|
||||||
TYPE
|
TAG
|
||||||
{
|
{
|
||||||
current_type = $1;
|
current_type = $1;
|
||||||
tag_seen = true;
|
tag_seen = true;
|
||||||
@@ -538,7 +538,7 @@ rhs:
|
|||||||
{ grammar_current_rule_prec_set ($3, @3); }
|
{ grammar_current_rule_prec_set ($3, @3); }
|
||||||
| rhs "%dprec" INT
|
| rhs "%dprec" INT
|
||||||
{ grammar_current_rule_dprec_set ($3, @3); }
|
{ grammar_current_rule_dprec_set ($3, @3); }
|
||||||
| rhs "%merge" TYPE
|
| rhs "%merge" TAG
|
||||||
{ grammar_current_rule_merge_set ($3, @3); }
|
{ grammar_current_rule_merge_set ($3, @3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ static void unexpected_newline (boundary, char const *);
|
|||||||
/* A identifier was just read in directives/rules. Special state
|
/* A identifier was just read in directives/rules. Special state
|
||||||
to capture the sequence `identifier :'. */
|
to capture the sequence `identifier :'. */
|
||||||
%x SC_AFTER_IDENTIFIER
|
%x SC_AFTER_IDENTIFIER
|
||||||
|
/* A complex tag, with nested angles brackets. */
|
||||||
|
%x SC_TAG
|
||||||
|
|
||||||
/* Three types of user code:
|
/* Three types of user code:
|
||||||
- prologue (code between `%{' `%}' in the first section, before %%);
|
- prologue (code between `%{' `%}' in the first section, before %%);
|
||||||
@@ -96,8 +98,10 @@ int [0-9]+
|
|||||||
|
|
||||||
/* POSIX says that a tag must be both an id and a C union member, but
|
/* POSIX says that a tag must be both an id and a C union member, but
|
||||||
historically almost any character is allowed in a tag. We disallow
|
historically almost any character is allowed in a tag. We disallow
|
||||||
NUL and newline, as this simplifies our implementation. */
|
NUL, as this simplifies our implementation. We disallow angle
|
||||||
tag [^\0\n>]+
|
bracket to match them in nested pairs: several languages use them
|
||||||
|
for generics/template types. */
|
||||||
|
tag [^\0<>]+
|
||||||
|
|
||||||
/* Zero or more instances of backslash-newline. Following GCC, allow
|
/* Zero or more instances of backslash-newline. Following GCC, allow
|
||||||
white space between the backslash and the newline. */
|
white space between the backslash and the newline. */
|
||||||
@@ -105,8 +109,9 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
|
|
||||||
%%
|
%%
|
||||||
%{
|
%{
|
||||||
/* Nesting level of the current code in braces. */
|
/* Nesting level. Either for nested braces, or nested angle brackets
|
||||||
int braces_level IF_LINT (= 0);
|
(but not mixed). */
|
||||||
|
int nesting IF_LINT (= 0);
|
||||||
|
|
||||||
/* Parent context state, when applicable. */
|
/* Parent context state, when applicable. */
|
||||||
int context_state IF_LINT (= 0);
|
int context_state IF_LINT (= 0);
|
||||||
@@ -205,8 +210,6 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
"=" return EQUAL;
|
"=" return EQUAL;
|
||||||
"|" return PIPE;
|
"|" return PIPE;
|
||||||
";" return SEMICOLON;
|
";" return SEMICOLON;
|
||||||
"<*>" return TYPE_TAG_ANY;
|
|
||||||
"<>" return TYPE_TAG_NONE;
|
|
||||||
|
|
||||||
{id} {
|
{id} {
|
||||||
val->uniqstr = uniqstr_new (yytext);
|
val->uniqstr = uniqstr_new (yytext);
|
||||||
@@ -235,18 +238,25 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
/* Code in between braces. */
|
/* Code in between braces. */
|
||||||
"{" {
|
"{" {
|
||||||
STRING_GROW;
|
STRING_GROW;
|
||||||
braces_level = 0;
|
nesting = 0;
|
||||||
code_start = loc->start;
|
code_start = loc->start;
|
||||||
BEGIN SC_BRACED_CODE;
|
BEGIN SC_BRACED_CODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A type. */
|
/* A type. */
|
||||||
|
"<*>" return TAG_ANY;
|
||||||
|
"<>" return TAG_NONE;
|
||||||
"<"{tag}">" {
|
"<"{tag}">" {
|
||||||
obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
|
obstack_grow (&obstack_for_string, yytext + 1, yyleng - 2);
|
||||||
STRING_FINISH;
|
STRING_FINISH;
|
||||||
val->uniqstr = uniqstr_new (last_string);
|
val->uniqstr = uniqstr_new (last_string);
|
||||||
STRING_FREE;
|
STRING_FREE;
|
||||||
return TYPE;
|
return TAG;
|
||||||
|
}
|
||||||
|
"<" {
|
||||||
|
nesting = 0;
|
||||||
|
token_start = loc->start;
|
||||||
|
BEGIN SC_TAG;
|
||||||
}
|
}
|
||||||
|
|
||||||
"%%" {
|
"%%" {
|
||||||
@@ -267,6 +277,17 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------.
|
||||||
|
| Supporting \0 complexifies our implementation for no expected |
|
||||||
|
| added value. |
|
||||||
|
`--------------------------------------------------------------*/
|
||||||
|
|
||||||
|
<SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING,SC_TAG>
|
||||||
|
{
|
||||||
|
\0 complain_at (*loc, _("invalid null character"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*-----------------------------------------------------------------.
|
/*-----------------------------------------------------------------.
|
||||||
| Scanning after an identifier, checking whether a colon is next. |
|
| Scanning after an identifier, checking whether a colon is next. |
|
||||||
`-----------------------------------------------------------------*/
|
`-----------------------------------------------------------------*/
|
||||||
@@ -386,11 +407,40 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<SC_ESCAPED_CHARACTER,SC_ESCAPED_STRING>
|
/*-----------------------------------------------------------.
|
||||||
{
|
| Scanning a Bison nested tag. The initial angle bracket is |
|
||||||
\0 complain_at (*loc, _("invalid null character"));
|
| already eaten. |
|
||||||
}
|
`-----------------------------------------------------------*/
|
||||||
|
|
||||||
|
<SC_TAG>
|
||||||
|
{
|
||||||
|
">" {
|
||||||
|
--nesting;
|
||||||
|
if (nesting < 0)
|
||||||
|
{
|
||||||
|
STRING_FINISH;
|
||||||
|
loc->start = token_start;
|
||||||
|
val->uniqstr = uniqstr_new (last_string);
|
||||||
|
STRING_FREE;
|
||||||
|
BEGIN INITIAL;
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
STRING_GROW;
|
||||||
|
}
|
||||||
|
|
||||||
|
[^<>]+ STRING_GROW;
|
||||||
|
"<"+ STRING_GROW; nesting += yyleng;
|
||||||
|
|
||||||
|
<<EOF>> {
|
||||||
|
unexpected_eof (token_start, ">");
|
||||||
|
STRING_FINISH;
|
||||||
|
loc->start = token_start;
|
||||||
|
val->uniqstr = uniqstr_new (last_string);
|
||||||
|
STRING_FREE;
|
||||||
|
BEGIN INITIAL;
|
||||||
|
return TAG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*----------------------------.
|
/*----------------------------.
|
||||||
| Decode escaped characters. |
|
| Decode escaped characters. |
|
||||||
@@ -509,13 +559,13 @@ splice (\\[ \f\t\v]*\n)*
|
|||||||
|
|
||||||
<SC_BRACED_CODE>
|
<SC_BRACED_CODE>
|
||||||
{
|
{
|
||||||
"{"|"<"{splice}"%" STRING_GROW; braces_level++;
|
"{"|"<"{splice}"%" STRING_GROW; nesting++;
|
||||||
"%"{splice}">" STRING_GROW; braces_level--;
|
"%"{splice}">" STRING_GROW; nesting--;
|
||||||
"}" {
|
"}" {
|
||||||
obstack_1grow (&obstack_for_string, '}');
|
obstack_1grow (&obstack_for_string, '}');
|
||||||
|
|
||||||
--braces_level;
|
--nesting;
|
||||||
if (braces_level < 0)
|
if (nesting < 0)
|
||||||
{
|
{
|
||||||
STRING_FINISH;
|
STRING_FINISH;
|
||||||
loc->start = code_start;
|
loc->start = code_start;
|
||||||
|
|||||||
24
tests/c++.at
24
tests/c++.at
@@ -51,7 +51,7 @@ typedef std::list<std::string> strings_type;
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
static
|
static
|
||||||
#if defined USE_LEX_SYMBOL
|
#if defined USE_LEX_SYMBOL
|
||||||
yy::parser::symbol_type yylex ();
|
yy::parser::symbol_type yylex ();
|
||||||
#else
|
#else
|
||||||
@@ -86,26 +86,30 @@ typedef std::list<std::string> strings_type;
|
|||||||
|
|
||||||
%token <std::string> TEXT;
|
%token <std::string> TEXT;
|
||||||
%token <int> NUMBER;
|
%token <int> NUMBER;
|
||||||
%printer { debug_stream() << $][$; } <int> <std::string> <strings_type>;
|
|
||||||
%token END_OF_FILE 0;
|
%token END_OF_FILE 0;
|
||||||
|
|
||||||
%type <std::string> item;
|
%type <std::string> item;
|
||||||
%type <strings_type> list result;
|
// Using the template type to exercize its parsing.
|
||||||
|
// Starting with :: to ensure we don't output "<::" which starts by the
|
||||||
|
// digraph for the left square bracket.
|
||||||
|
%type <::std::list<std::string>> list result;
|
||||||
|
|
||||||
|
%printer { debug_stream() << $][$; }
|
||||||
|
<int> <::std::string> <::std::list<::std::string>>;
|
||||||
%%
|
%%
|
||||||
|
|
||||||
result:
|
result:
|
||||||
list { std::cout << $][1; }
|
list { std::cout << $][1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
list:
|
list:
|
||||||
/* nothing */ { /* Generates an empty string list */ }
|
/* nothing */ { /* Generates an empty string list */ }
|
||||||
| list item { std::swap($][$,$][1); $$.push_back($][2); }
|
| list item { std::swap($][$,$][1); $$.push_back($][2); }
|
||||||
;
|
;
|
||||||
|
|
||||||
item:
|
item:
|
||||||
TEXT { std::swap($][$,$][1); }
|
TEXT { std::swap($][$,$][1); }
|
||||||
| NUMBER { $][$ = string_cast($][1); }
|
| NUMBER { $][$ = string_cast($][1); }
|
||||||
;
|
;
|
||||||
%%
|
%%
|
||||||
|
|
||||||
@@ -164,7 +168,7 @@ yy::parser::token_type yylex(yy::parser::semantic_type* yylval,
|
|||||||
|
|
||||||
void
|
void
|
||||||
yy::parser::error(const yy::parser::location_type&,
|
yy::parser::error(const yy::parser::location_type&,
|
||||||
const std::string& message)
|
const std::string& message)
|
||||||
{
|
{
|
||||||
std::cerr << message << std::endl;
|
std::cerr << message << std::endl;
|
||||||
}
|
}
|
||||||
@@ -363,5 +367,5 @@ AT_CHECK_NAMESPACE([[foo: :bar]], [[-]])
|
|||||||
# contains single occurrences of `:'.
|
# contains single occurrences of `:'.
|
||||||
AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]])
|
AT_CHECK_NAMESPACE([[foo[3]::bar::baz]], [[-]])
|
||||||
AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]])
|
AT_CHECK_NAMESPACE([[foo::bar,baz]], [[-]])
|
||||||
AT_CHECK_NAMESPACE([[foo::bar::(baz]], [[-]])
|
AT_CHECK_NAMESPACE([[foo::bar::(baz /* Pacify Emacs ) */]], [[-]])
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|||||||
Reference in New Issue
Block a user