diff options
author | Akim Demaille <akim.demaille@gmail.com> | 2018-12-19 17:51:10 +0100 |
---|---|---|
committer | Akim Demaille <akim.demaille@gmail.com> | 2018-12-22 14:55:07 +0100 |
commit | e5780041b97409de2a5ed38cfa5a2b823dd1dfd9 (patch) | |
tree | 31f8134ba50f6ef967d3d8d59a56b9842174d49b /doc/bison.texi | |
parent | 1f4dd2671a4dee1525b2681f4dbcb0cb3c34793e (diff) | |
download | bison-e5780041b97409de2a5ed38cfa5a2b823dd1dfd9.tar.gz |
c++: exhibit a safe symbol_type
Instead of introducing make_symbol (whose name, btw, somewhat
infringes on the user's "name space", if she defines a token named
"symbol"), let's make the construction of symbol_type safer, using
assertions.
For instance with:
%token ':' <std::string> ID <int> INT;
generate:
symbol_type (int token, const std::string&);
symbol_type (int token, const int&);
symbol_type (int token);
It does mean that now named token constructors (make_ID, make_INT,
etc.) go through a useless assert, but I think we can ignore this: I
assume any decent compiler will inline the symbol_type ctor inside the
make_TOKEN functions, which will show that the assert is trivially
verified, hence I expect no code will be emitted for it. And anyway,
that's an assert, NDEBUG controls it.
* data/c++.m4 (symbol_type): Turn into a subclass of
basic_symbol<by_type>.
Declare symbol constructors when variants are enabled.
* data/variant.hh (_b4_type_constructor_declare)
(_b4_type_constructor_define): Replace with...
(_b4_symbol_constructor_declare, _b4_symbol_constructor_def): these.
Generate symbol_type constructors.
* doc/bison.texi (Complete Symbols): Document.
* tests/types.at: Check.
Diffstat (limited to 'doc/bison.texi')
-rw-r--r-- | doc/bison.texi | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/doc/bison.texi b/doc/bison.texi index 89283be7..e1a5aaba 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -11500,6 +11500,57 @@ additional arguments. For each token type, Bison generates named constructors as follows. +@deftypeop {Constructor} {parser::symbol_type} {} {symbol_type} (int @var{token}, const @var{value_type}& @var{value}, const location_type& @var{location}) +@deftypeopx {Constructor} {parser::symbol_type} {} {symbol_type} (int @var{token}, const location_type& @var{location}) +@deftypeopx {Constructor} {parser::symbol_type} {} {symbol_type} (int @var{token}, const @var{value_type}& @var{value}) +@deftypeopx {Constructor} {parser::symbol_type} {} {symbol_type} (int @var{token}) +Build a complete terminal symbol for the token type @var{token} (including +the @code{api.token.prefix}), whose semantic value, if it has one, is +@var{value} of adequate @var{value_type}. Pass the @var{location} iff +location tracking is enabled. + +Consistency between @var{token} and @var{value_type} is checked via an +@code{assert}. +@end deftypeop + +For instance, given the following declarations: + +@example +%define api.token.prefix @{TOK_@} +%token <std::string> IDENTIFIER; +%token <int> INTEGER; +%token ':'; +@end example + +@noindent +you may use these constructors: + +@example +symbol_type (int token, const std::string&, const location_type&); +symbol_type (int token, const int&, const location_type&); +symbol_type (int token, const location_type&); +@end example + +@noindent +which should be used in a Flex-scanner as follows. + +@example +%% +[a-z]+ return yy::parser::symbol_type (TOK_IDENTIFIER, yytext, loc); +[0-9]+ return yy::parser::symbol_type (TOK_INTEGER, text_to_int (yytext), loc); +":" return yy::parser::symbol_type (':', loc); +<<EOF>> return yy::parser::symbol_type (0, loc); +@end example + +@sp 1 + +Note that it is possible to generate and compile type incorrect code +(e.g. @samp{symbol_type (':', yytext, loc)}). It will fail at run time, +provided the assertions are enabled (i.e., @option{-DNDEBUG} was not passed +to the compiler). Bison supports an alternative that guarantees that type +incorrect code will not even compile. Indeed, it generates @emph{named +constructors} as follows. + @deftypemethod {parser} {symbol_type} {make_@var{token}} (const @var{value_type}& @var{value}, const location_type& @var{location}) @deftypemethodx {parser} {symbol_type} {make_@var{token}} (const location_type& @var{location}) @deftypemethodx {parser} {symbol_type} {make_@var{token}} (const @var{value_type}& @var{value}) @@ -11531,7 +11582,7 @@ symbol_type make_EOF (const location_type&); @end example @noindent -which should be used in a Flex-scanner as follows. +which should be used in a scanner as follows. @example [a-z]+ return yy::parser::make_IDENTIFIER (yytext, loc); @@ -11544,6 +11595,7 @@ Tokens that do not have an identifier are not accessible: you cannot simply use characters such as @code{':'}, they must be declared with @code{%token}, including the end-of-file token. + @node A Complete C++ Example @subsection A Complete C++ Example |