Much remains to be done. For instance I have not checked yet the uses
of @deftypemethod etc. Also, I want to extract example/calc++ from
the documentation.
Maybe the FAQ should an appendix too? The actual order of the
appendix and the menu disagreed: I fixed the menu, but maybe moving
the FAQ last is preferable.
Index: ChangeLog
from Akim Demaille <[EMAIL PROTECTED]>
* doc/bison.texinfo (C++ Language Interface): First stab.
(C++ Parsers): Remove.
Index: doc/bison.texinfo
===================================================================
RCS file: /cvsroot/bison/bison/doc/bison.texinfo,v
retrieving revision 1.144
diff -u -u -r1.144 bison.texinfo
--- doc/bison.texinfo 14 May 2005 06:49:46 -0000 1.144
+++ doc/bison.texinfo 22 Jun 2005 16:49:04 -0000
@@ -117,9 +117,10 @@
messy for Bison to handle straightforwardly.
* Debugging:: Understanding or debugging Bison parsers.
* Invocation:: How to run Bison (to produce the parser source file).
+* C++ Language Interface:: Creating C++ parser objects.
+* FAQ:: Frequently Asked Questions
* Table of Symbols:: All the keywords of the Bison language are explained.
* Glossary:: Basic concepts are explained.
-* FAQ:: Frequently Asked Questions
* Copying This Manual:: License for copying this manual.
* Index:: Cross-references to the text.
@@ -292,12 +293,32 @@
* Option Cross Key:: Alphabetical list of long options.
* Yacc Library:: Yacc-compatible @code{yylex} and @code{main}.
+C++ Language Interface
+
+* C++ Parsers:: The interface to generate C++ parser classes
+* A Complete C++ Example:: Demonstrating their use
+
+C++ Parsers
+
+* C++ Bison Interface:: Asking for C++ parser generation
+* C++ Semantic Values:: %union vs. C++
+* C++ Location Values:: The position and location classes
+* C++ Parser Interface:: Instantiating and running the parser
+* C++ Scanner Interface:: Exchanges between yylex and parse
+
+A Complete C++ Example
+
+* Calc++ --- C++ Calculator:: The specifications
+* Calc++ Parsing Driver:: An active parsing context
+* Calc++ Parser:: A parser class
+* Calc++ Scanner:: A pure C++ Flex scanner
+* Calc++ Top Level:: Conducting the band
+
Frequently Asked Questions
* Parser Stack Overflow:: Breaking the Stack Limits
* How Can I Reset the Parser:: @code{yyparse} Keeps some State
* Strings are Destroyed:: @code{yylval} Loses Track of Strings
-* C++ Parsers:: Compiling Parsers with C++ Compilers
* Implementing Gotos/Loops:: Control Flow in the Calculator
Copying This Manual
@@ -6737,7 +6758,650 @@
int yyparse (void);
@end example
[EMAIL PROTECTED] ================================================= Invoking
Bison
[EMAIL PROTECTED] ================================================= C++ Bison
+
[EMAIL PROTECTED] C++ Language Interface
[EMAIL PROTECTED] C++ Language Interface
+
[EMAIL PROTECTED]
+* C++ Parsers:: The interface to generate C++ parser classes
+* A Complete C++ Example:: Demonstrating their use
[EMAIL PROTECTED] menu
+
[EMAIL PROTECTED] C++ Parsers
[EMAIL PROTECTED] C++ Parsers
+
[EMAIL PROTECTED]
+* C++ Bison Interface:: Asking for C++ parser generation
+* C++ Semantic Values:: %union vs. C++
+* C++ Location Values:: The position and location classes
+* C++ Parser Interface:: Instantiating and running the parser
+* C++ Scanner Interface:: Exchanges between yylex and parse
[EMAIL PROTECTED] menu
+
[EMAIL PROTECTED] C++ Bison Interface
[EMAIL PROTECTED] C++ Bison Interface
[EMAIL PROTECTED] - %skeleton "lalr1.cc"
[EMAIL PROTECTED] - Always pure
[EMAIL PROTECTED] - initial action
+
+The C++ parser LALR(1) skeleton is named @file{lalr1.cc}. To select
+it, you may either pass the option @option{--skeleton=lalr1.cc} to
+Bison, or include the directive @samp{%skeleton "lalr1.cc"} in the
+grammar preamble. When run, @command{bison} will create several
+files:
[EMAIL PROTECTED] @file
[EMAIL PROTECTED] position.hh
[EMAIL PROTECTED] location.hh
+The definition of the classes @code{position} and @code{location},
+used for location tracking. @xref{C++ Location Values}.
+
[EMAIL PROTECTED] stack.hh
+An auxiliary class @code{stack} used by the parser.
+
[EMAIL PROTECTED] @var{filename}.hh
[EMAIL PROTECTED] @var{filename}.cc
+The declaration and implementation of the C++ parser class.
[EMAIL PROTECTED] is the name of the output file. It follows the same
+rules as with regular C parsers.
+
+Note that @[EMAIL PROTECTED] is @emph{mandatory}, the C++ cannot
+work without the parser class declaration. Therefore, you must either
+pass @option{-d}/@option{--defines} to @command{bison}, or use the
[EMAIL PROTECTED] directive.
[EMAIL PROTECTED] table
+
+All these files are documented using Doxygen; run @command{doxygen}
+for a complete and accurate documentation.
+
[EMAIL PROTECTED] C++ Semantic Values
[EMAIL PROTECTED] C++ Semantic Values
[EMAIL PROTECTED] - No objects in unions
[EMAIL PROTECTED] - YSTYPE
[EMAIL PROTECTED] - Printer and destructor
+
+The @code{%union} directive works as for C, see @ref{Union Decl, ,The
+Collection of Value Types}. In particular it produces a genuine
[EMAIL PROTECTED]@footnote{In the future techniques to allow complex types
+within pseudo-unions (variants) might be implemented to alleviate
+these issues.}, which have a few specific features in C++.
[EMAIL PROTECTED] @minus
[EMAIL PROTECTED]
+The name @code{YYSTYPE} also denotes @samp{union YYSTYPE}. You may
+forward declare it just with @samp{union YYSTYPE;}.
[EMAIL PROTECTED]
+Non POD (Plain Old Data) types cannot be used. C++ forbids any
+instance of classes with constructors in unions: only @emph{pointers}
+to such objects are allowed.
[EMAIL PROTECTED] itemize
+
+Because objects have to be stored via pointers, memory is not
+reclaimed automatically: using the @code{%destructor} directive is the
+only means to avoid leaks. @xref{Destructor Decl, , Freeing Discarded
+Symbols}.
+
+
[EMAIL PROTECTED] C++ Location Values
[EMAIL PROTECTED] C++ Location Values
[EMAIL PROTECTED] - %locations
[EMAIL PROTECTED] - class Position
[EMAIL PROTECTED] - class Location
[EMAIL PROTECTED] - %define "filename_type" "const symbol::Symbol"
+
+When the directive @code{%locations} is used, the C++ parser supports
+location tracking, see @ref{Locations, , Locations Overview}. Two
+auxiliary classes define a @code{position}, a single point in a file,
+and a @code{location}, a range composed of a pair of
[EMAIL PROTECTED] (possibly spanning several files).
+
[EMAIL PROTECTED] {position} {std::string*} filename
+The name of the file. It will always be handled as a pointer, the
+parser will never duplicate nor deallocate it. As an experimental
+feature you may change it to @[EMAIL PROTECTED] using @samp{%define
+"filename_type" "@var{type}"}.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {unsigned int} line
+The line, starting at 1.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {unsigned int} lines (int @var{height} = 1)
+Advance by @var{height} lines, resetting the column number.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {unsigned int} column
+The column, starting at 0.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {unsigned int} columns (int @var{width} = 1)
+Advance by @var{width} columns, without changing the line number.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {position&} operator+= (position& @var{pos}, int
@var{width})
[EMAIL PROTECTED] {position} {position} operator+ (const position& @var{pos},
int @var{width})
[EMAIL PROTECTED] {position} {position&} operator-= (const position& @var{pos},
int @var{width})
[EMAIL PROTECTED] {position} {position} operator- (position& @var{pos}, int
@var{width})
+Various forms of syntactic sugar for @code{columns}.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {position} {position} operator<< (std::ostream @var{o}, const
position& @var{p})
+Report @var{p} on @var{o} like this:
[EMAIL PROTECTED]@var{filename}:@[EMAIL PROTECTED], or
[EMAIL PROTECTED]@[EMAIL PROTECTED] if @var{filename} is null.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {location} {position} begin
[EMAIL PROTECTED] {location} {position} end
+The first, inclusive, position of the range, and the first beyond.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {location} {unsigned int} columns (int @var{width} = 1)
[EMAIL PROTECTED] {location} {unsigned int} lines (int @var{height} = 1)
+Advance the @code{end} position.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {location} {location} operator+ (const location& @var{begin},
const location& @var{end})
[EMAIL PROTECTED] {location} {location} operator+ (const location& @var{begin},
int @var{width})
[EMAIL PROTECTED] {location} {location} operator+= (const location& @var{loc},
int @var{width})
+Various forms of syntactic sugar.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {location} {void} step ()
+Move @code{begin} onto @code{end}.
[EMAIL PROTECTED] deftypemethod
+
+
[EMAIL PROTECTED] C++ Parser Interface
[EMAIL PROTECTED] C++ Parser Interface
[EMAIL PROTECTED] - define parser_class_name
[EMAIL PROTECTED] - Ctor
[EMAIL PROTECTED] - parse, error, set_debug_level, debug_level,
set_debug_stream,
[EMAIL PROTECTED] debug_stream.
[EMAIL PROTECTED] - Reporting errors
+
+The output files @[EMAIL PROTECTED] and @[EMAIL PROTECTED]
+declare and define the parser class in the namespace @code{yy}. The
+class name defaults to @code{parser}, but may be changed using
[EMAIL PROTECTED] "parser_class_name" "@var{name}"}. The interface of
+this class is detailled below. It can be extended using the
[EMAIL PROTECTED] feature: its semantics is slightly changed since
+it describes an additional member of the parser class, and an
+additional argument for its constructor.
+
[EMAIL PROTECTED] {parser} {semantic_value_type}
[EMAIL PROTECTED] {parser} {location_value_type}
+The types for semantics value and locations.
[EMAIL PROTECTED] FIXME: deftypemethod pour des types ???
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {parser} {} parser (@var{type1} @var{arg1}, ...)
+Build a new parser object. There are no arguments by default, unless
[EMAIL PROTECTED] @[EMAIL PROTECTED] @[EMAIL PROTECTED] was used.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {parser} {int} parse ()
+Run the syntactic analysis, and return 0 on success, 1 otherwise.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {parser} {std::ostream&} debug_stream ()
[EMAIL PROTECTED] {parser} {void} set_debug_stream (std::ostream& @var{o})
+Get or set the stream used for tracing the parsing. It defaults to
[EMAIL PROTECTED]::cerr}.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {parser} {debug_level_type} debug_level ()
[EMAIL PROTECTED] {parser} {void} set_debug_level (debug_level @var{l})
+Get or set the tracing level. Currently its value is either 0, no trace,
+or non-zero, full tracing.
[EMAIL PROTECTED] deftypemethod
+
[EMAIL PROTECTED] {parser} {void} error (const location_type& @var{l}, const
std::string& @var{m})
+The definition for this member function must be supplied by the user:
+the parser uses it to report a parser error occurring at @var{l},
+described by @var{m}.
[EMAIL PROTECTED] deftypemethod
+
+
[EMAIL PROTECTED] C++ Scanner Interface
[EMAIL PROTECTED] C++ Scanner Interface
[EMAIL PROTECTED] - prefix for yylex.
[EMAIL PROTECTED] - Pure interface to yylex
[EMAIL PROTECTED] - %lex-param
+
+The parser invokes the scanner by calling @code{yylex}. Contrary to C
+parsers, C++ parsers are always pure: there is no point in using the
[EMAIL PROTECTED] directive. Therefore the interface is as follows.
+
[EMAIL PROTECTED] {parser} {int} yylex (semantic_value_type& @var{yylval},
location_type& @var{yylloc}, @var{type1} @var{arg1}, ...)
+Return the next token. Its type is the return value, its semantic
+value and location being @var{yylval} and @var{yylloc}. Invocations of
[EMAIL PROTECTED] @[EMAIL PROTECTED] @[EMAIL PROTECTED] yield additional
arguments.
[EMAIL PROTECTED] deftypemethod
+
+
[EMAIL PROTECTED] A Complete C++ Example
[EMAIL PROTECTED] A Complete C++ Example
+
+This section demonstrates the use of a C++ parser with a simple but
+complete example. This example should be available on your system,
+ready to compile, in the directory @dfn{../bison/examples/calc++}. It
+focuses on the use of Bison, therefore the design of the various C++
+classes is very naive: no accessors, no encapsulation of members etc.
+We will use a Lex scanner, and more precisely, a Flex scanner, to
+demonstrate the various interaction. A hand written scanner is
+actually easier to interface with.
+
[EMAIL PROTECTED]
+* Calc++ --- C++ Calculator:: The specifications
+* Calc++ Parsing Driver:: An active parsing context
+* Calc++ Parser:: A parser class
+* Calc++ Scanner:: A pure C++ Flex scanner
+* Calc++ Top Level:: Conducting the band
[EMAIL PROTECTED] menu
+
[EMAIL PROTECTED] Calc++ --- C++ Calculator
[EMAIL PROTECTED] Calc++ --- C++ Calculator
+
+Of course the grammar is dedicated to arithmetics, a single
+expression, possibily preceded by variable assignments. An
+environment containing possibly predefined variables such as
[EMAIL PROTECTED] and @code{two}, is exchanged with the parser. An example
+of valid input follows.
+
[EMAIL PROTECTED]
+three := 3
+seven := one + two * three
+seven * seven
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] Calc++ Parsing Driver
[EMAIL PROTECTED] Calc++ Parsing Driver
[EMAIL PROTECTED] - An env
[EMAIL PROTECTED] - A place to store error messages
[EMAIL PROTECTED] - A place for the result
+
+To support a pure interface with the parser (and the scanner) the
+technique of the ``parsing context'' is convenient: a structure
+containing all the data to exchange. Since, in addition to simply
+launch the parsing, there are several auxiliary tasks to execute (open
+the file for parsing, instantiate the parser etc.), we recommend
+transforming the simple parsing context structure into a fully blown
[EMAIL PROTECTED] driver} class.
+
+The declaration of this driver class, @file{calc++-driver.hh}, is as
+follows. The first part includes the CPP guard and imports the
+required standard library components.
+
[EMAIL PROTECTED]
+#ifndef CALCXX_DRIVER_HH
+# define CALCXX_DRIVER_HH
+# include <string>
+# include <map>
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Then come forward declarations. Because the parser uses the parsing
+driver and reciprocally, simple inclusions of header files will not
+do. Because the driver's declaration is the one that will be imported
+by the rest of the project, it is saner to forward declare the
+parser's information here.
+
[EMAIL PROTECTED]
+// Forward declarations.
+union YYSTYPE;
+namespace yy @{ class calcxx_parser; @}
+class calcxx_driver;
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Then comes the declaration of the scanning function. Flex expects
+the signature of @code{yylex} to be defined in the macro
[EMAIL PROTECTED], and the C++ parser expects it to be declared. We can
+factor both as follows.
[EMAIL PROTECTED]
+// Announce to Flex the prototype we want for lexing function, ...
+# define YY_DECL \
+ int yylex (YYSTYPE* yylval, yy::location* yylloc, calcxx_driver& driver)
+// ... and declare it for the parser's sake.
+YY_DECL;
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The @code{calcxx_driver} class is then declared with its most obvious
+members.
+
[EMAIL PROTECTED]
+// Conducting the whole scanning and parsing of Calc++.
+class calcxx_driver
[EMAIL PROTECTED]
+public:
+ calcxx_driver ();
+ virtual ~calcxx_driver ();
+
+ std::map<std::string, int> variables;
+
+ int result;
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+To encapsulate the coordination with the Flex scanner, it is useful to
+have two members function to open and close the scanning phase.
+members.
+
[EMAIL PROTECTED]
+ // Handling the scanner.
+ void scan_begin ();
+ void scan_end ();
+ bool trace_scanning;
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Similarly for the parser itself.
+
[EMAIL PROTECTED]
+ // Handling the parser.
+ void parse (const std::string& f);
+ std::string file;
+ bool trace_parsing;
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+To demonstrate pure handling of parse errors, instead of simply
+dumping them on the standard error output, we will pass them to the
+compiler driver using the following two member functions. Finally, we
+close the class declaration and CPP guard.
+
[EMAIL PROTECTED]
+ // Error handling.
+ void error (const yy::location& l, const std::string& m);
+ void error (const std::string& m);
[EMAIL PROTECTED];
+#endif // ! CALCXX_DRIVER_HH
[EMAIL PROTECTED] example
+
+The implementation of the driver is straightforward. The @code{parse}
+member function deserves some attention. The @code{error} functions
+are simple stubs, they should actually register the located error
+messages and set error state.
+
[EMAIL PROTECTED]
+#include "calc++-driver.hh"
+#include "calc++-parser.hh"
+
+calcxx_driver::calcxx_driver ()
+ : trace_scanning (false), trace_parsing (false)
[EMAIL PROTECTED]
+ variables["one"] = 1;
+ variables["two"] = 2;
[EMAIL PROTECTED]
+
+calcxx_driver::~calcxx_driver ()
[EMAIL PROTECTED]
[EMAIL PROTECTED]
+
+void
+calcxx_driver::parse (const std::string &f)
[EMAIL PROTECTED]
+ file = f;
+ scan_begin ();
+ yy::calcxx_parser parser (*this);
+ parser.set_debug_level (trace_parsing);
+ parser.parse ();
+ scan_end ();
[EMAIL PROTECTED]
+
+void
+calcxx_driver::error (const yy::location& l, const std::string& m)
[EMAIL PROTECTED]
+ std::cerr << l << ": " << m << std::endl;
[EMAIL PROTECTED]
+
+void
+calcxx_driver::error (const std::string& m)
[EMAIL PROTECTED]
+ std::cerr << m << std::endl;
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] Calc++ Parser
[EMAIL PROTECTED] Calc++ Parser
+
+The parser definition file @file{calc++-parser.yy} starts by asking
+for the C++ skeleton, the creation of the parser header file, and
+specifies the name of the parser class. It then includes the required
+headers.
[EMAIL PROTECTED]
+%skeleton "lalr1.cc" /* -*- C++ -*- */
+%define "parser_class_name" "calcxx_parser"
+%defines
[EMAIL PROTECTED]
+# include <string>
+# include "calc++-driver.hh"
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The driver is passed by reference to the parser and to the scanner.
+This provides a simple but effective pure interface, not relying on
+global variables.
+
[EMAIL PROTECTED]
+// The parsing context.
+%parse-param @{ calcxx_driver& driver @}
+%lex-param @{ calcxx_driver& driver @}
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Then we request the location tracking feature, and initialize the
+first location's file name. Afterwards new locations are computed
+relatively to the previous locations: the file name will be
+automatically propagated.
+
[EMAIL PROTECTED]
+%locations
+%initial-action
[EMAIL PROTECTED]
+ // Initialize the initial location.
+ @@$.begin.filename = @@$.end.filename = &driver.file;
[EMAIL PROTECTED];
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Use the two following directives to enable parser tracing and verbose
+error messages.
+
[EMAIL PROTECTED]
+%debug
+%error-verbose
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Semantic values cannot use ``real'' objects, but only pointers to
+them.
+
[EMAIL PROTECTED]
+// Symbols.
+%union
[EMAIL PROTECTED]
+ int ival;
+ std::string *sval;
[EMAIL PROTECTED];
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The token numbered as 0 corresponds to end of file; the following line
+allows for nicer error messages referring to ``end of file'' instead
+of ``$end''. Similarly user friendly named are provided for each
+symbol. Note that the tokens names are prefixed by @code{TOKEN_} to
+avoid name clashes.
+
[EMAIL PROTECTED]
+%token YYEOF 0 "end of file"
+%token TOKEN_ASSIGN ":="
+%token <sval> TOKEN_IDENTIFIER "identifier"
+%token <ival> TOKEN_NUMBER "number"
+%type <ival> exp "expression"
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+To enable memory deallocation during error recovery, use
[EMAIL PROTECTED]
+
[EMAIL PROTECTED]
+%printer @{ debug_stream () << *$$; @} "identifier"
+%destructor @{ delete $$; @} "identifier"
+
+%printer @{ debug_stream () << $$; @} "number" "expression"
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The grammar itself is straightforward.
+
[EMAIL PROTECTED]
+%%
+%start unit;
+unit: assignments exp @{ driver.result = $2; @};
+
+assignments: assignments assignment @[EMAIL PROTECTED]
+ | /* Nothing. */ @[EMAIL PROTECTED];
+
+assignment: TOKEN_IDENTIFIER ":=" exp @{ driver.variables[*$1] = $3; @};
+
+%left '+' '-';
+%left '*' '/';
+exp: exp '+' exp @{ $$ = $1 + $3; @}
+ | exp '-' exp @{ $$ = $1 - $3; @}
+ | exp '*' exp @{ $$ = $1 * $3; @}
+ | exp '/' exp @{ $$ = $1 / $3; @}
+ | TOKEN_IDENTIFIER @{ $$ = driver.variables[*$1]; @}
+ | TOKEN_NUMBER @{ $$ = $1; @};
+%%
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Finally the @code{error} member function registers the errors to the
+driver.
+
[EMAIL PROTECTED]
+void
+yy::calcxx_parser::error (const location_type& l, const std::string& m)
[EMAIL PROTECTED]
+ driver.error (l, m);
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] Calc++ Scanner
[EMAIL PROTECTED] Calc++ Scanner
+
+The Flex scanner first includes the driver declaration, then the
+parser's to get the set of defined tokens.
+
[EMAIL PROTECTED]
[EMAIL PROTECTED] /* -*- C++ -*- */
+# include <string>
+# include "calc++-driver.hh"
+# include "calc++-parser.hh"
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Because there is no @code{#include}-like feature we don't need
[EMAIL PROTECTED], we don't need @code{unput} either, and we parse an
+actual file, this is not an interactive session with the user.
+Finally we enable the scanner tracing features.
+
[EMAIL PROTECTED]
+%option noyywrap nounput batch debug
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Abbreviations allow for more readable rules.
+
[EMAIL PROTECTED]
+id [a-zA-Z][a-zA-Z_0-9]*
+int [0-9]+
+blank [ \t]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The following paragraph suffices to track locations acurately. Each
+time @code{yylex} is invoked, the begin position is moved onto the end
+position. Then when a pattern is matched, the end position is
+advanced of its width. In case it matched ends of lines, the end
+cursor is adjusted, and each time blanks are matched, the begin cursor
+is moved onto the end cursor to effectively ignore the blanks
+preceding tokens. Comments would be treated equally.
+
[EMAIL PROTECTED]
+%%
[EMAIL PROTECTED]
+ yylloc->step ();
+# define YY_USER_ACTION yylloc->columns (yyleng);
[EMAIL PROTECTED]
[EMAIL PROTECTED]@}+ yylloc->step ();
+[\n]+ yylloc->lines (yyleng); yylloc->step ();
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+The rules are simple, just note the use of the driver to report
+errors.
+
[EMAIL PROTECTED]
+[-+*/] return yytext[0];
+":=" return TOKEN_ASSIGN;
[EMAIL PROTECTED]@} yylval->ival = atoi (yytext); return TOKEN_NUMBER;
[EMAIL PROTECTED]@} yylval->sval = new std::string (yytext); return
TOKEN_IDENTIFIER;
+. driver.error (*yylloc, "invalid character");
+%%
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED]
+Finally, because the scanner related driver's member function depend
+on the scanner's data, it is simpler to implement them in this file.
+
[EMAIL PROTECTED]
+void
+calcxx_driver::scan_begin ()
[EMAIL PROTECTED]
+ yy_flex_debug = trace_scanning;
+ if (!(yyin = fopen (file.c_str (), "r")))
+ error (std::string ("cannot open ") + file);
[EMAIL PROTECTED]
+
+void
+calcxx_driver::scan_end ()
[EMAIL PROTECTED]
+ fclose (yyin);
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] Calc++ Top Level
[EMAIL PROTECTED] Calc++ Top Level
+
+The top level file, @file{calc++.cc}, poses no problem.
+
[EMAIL PROTECTED]
+#include <iostream>
+#include "calc++-driver.hh"
+
+int
+main (int argc, const char* argv[])
[EMAIL PROTECTED]
+ calcxx_driver driver;
+ for (++argv; argv[0]; ++argv)
+ if (*argv == std::string ("-p"))
+ driver.trace_parsing = true;
+ else if (*argv == std::string ("-s"))
+ driver.trace_scanning = true;
+ else
+ @{
+ driver.parse (*argv);
+ std::cout << driver.result << std::endl;
+ @}
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] ================================================= FAQ
@node FAQ
@chapter Frequently Asked Questions
@@ -6751,7 +7415,6 @@
* Parser Stack Overflow:: Breaking the Stack Limits
* How Can I Reset the Parser:: @code{yyparse} Keeps some State
* Strings are Destroyed:: @code{yylval} Loses Track of Strings
-* C++ Parsers:: Compiling Parsers with C++ Compilers
* Implementing Gotos/Loops:: Control Flow in the Calculator
@end menu
@@ -6916,27 +7579,6 @@
@end example
[EMAIL PROTECTED] C++ Parsers
[EMAIL PROTECTED] C++ Parsers
-
[EMAIL PROTECTED]
-How can I generate parsers in C++?
[EMAIL PROTECTED] display
-
-We are working on a C++ output for Bison, but unfortunately, for lack of
-time, the skeleton is not finished. It is functional, but in numerous
-respects, it will require additional work which @emph{might} break
-backward compatibility. Since the skeleton for C++ is not documented,
-we do not consider ourselves bound to this interface, nevertheless, as
-much as possible we will try to keep compatibility.
-
-Another possibility is to use the regular C parsers, and to compile them
-with a C++ compiler. This works properly, provided that you bear some
-simple C++ rules in mind, such as not including ``real classes'' (i.e.,
-structure with constructors) in unions. Therefore, in the
[EMAIL PROTECTED], use pointers to classes.
-
-
@node Implementing Gotos/Loops
@section Implementing Gotos/Loops