bison-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

FYI: lalr1.cc: First documentation


From: Akim Demaille
Subject: FYI: lalr1.cc: First documentation
Date: Wed, 22 Jun 2005 16:53:03 -0000
User-agent: Gnus/5.1007 (Gnus v5.10.7) Emacs/21.4 (gnu/linux)

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  <address@hidden>

        * 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
 
address@hidden ================================================= Invoking Bison
address@hidden ================================================= C++ Bison
+
address@hidden C++ Language Interface
address@hidden C++ Language Interface
+
address@hidden
+* C++ Parsers::                 The interface to generate C++ parser classes
+* A Complete C++ Example::      Demonstrating their use
address@hidden menu
+
address@hidden C++ Parsers
address@hidden C++ Parsers
+
address@hidden
+* 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
address@hidden menu
+
address@hidden C++ Bison Interface
address@hidden C++ Bison Interface
address@hidden - %skeleton "lalr1.cc"
address@hidden - Always pure
address@hidden - 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:
address@hidden @file
address@hidden position.hh
address@hidden location.hh
+The definition of the classes @code{position} and @code{location},
+used for location tracking.  @xref{C++ Location Values}.
+
address@hidden stack.hh
+An auxiliary class @code{stack} used by the parser.
+
address@hidden @var{filename}.hh
address@hidden @var{filename}.cc
+The declaration and implementation of the C++ parser class.
address@hidden is the name of the output file.  It follows the same
+rules as with regular C parsers.
+
+Note that @address@hidden 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
address@hidden directive.
address@hidden table
+
+All these files are documented using Doxygen; run @command{doxygen}
+for a complete and accurate documentation.
+
address@hidden C++ Semantic Values
address@hidden C++ Semantic Values
address@hidden - No objects in unions
address@hidden - YSTYPE
address@hidden - 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
address@hidden@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++.
address@hidden @minus
address@hidden
+The name @code{YYSTYPE} also denotes @samp{union YYSTYPE}.  You may
+forward declare it just with @samp{union YYSTYPE;}.
address@hidden
+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.
address@hidden 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}.
+
+
address@hidden C++ Location Values
address@hidden C++ Location Values
address@hidden - %locations
address@hidden - class Position
address@hidden - class Location
address@hidden - %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
address@hidden (possibly spanning several files).
+
address@hidden {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 @address@hidden using @samp{%define
+"filename_type" "@var{type}"}.
address@hidden deftypemethod
+
address@hidden {position} {unsigned int} line
+The line, starting at 1.
address@hidden deftypemethod
+
address@hidden {position} {unsigned int} lines (int @var{height} = 1)
+Advance by @var{height} lines, resetting the column number.
address@hidden deftypemethod
+
address@hidden {position} {unsigned int} column
+The column, starting at 0.
address@hidden deftypemethod
+
address@hidden {position} {unsigned int} columns (int @var{width} = 1)
+Advance by @var{width} columns, without changing the line number.
address@hidden deftypemethod
+
address@hidden {position} {position&} operator+= (position& @var{pos}, int 
@var{width})
address@hidden {position} {position} operator+ (const position& @var{pos}, int 
@var{width})
address@hidden {position} {position&} operator-= (const position& @var{pos}, 
int @var{width})
address@hidden {position} {position} operator- (position& @var{pos}, int 
@var{width})
+Various forms of syntactic sugar for @code{columns}.
address@hidden deftypemethod
+
address@hidden {position} {position} operator<< (std::ostream @var{o}, const 
position& @var{p})
+Report @var{p} on @var{o} like this:
address@hidden@var{filename}:@address@hidden, or
address@hidden@address@hidden if @var{filename} is null.
address@hidden deftypemethod
+
address@hidden {location} {position} begin
address@hidden {location} {position} end
+The first, inclusive, position of the range, and the first beyond.
address@hidden deftypemethod
+
address@hidden {location} {unsigned int} columns (int @var{width} = 1)
address@hidden {location} {unsigned int} lines (int @var{height} = 1)
+Advance the @code{end} position.
address@hidden deftypemethod
+
address@hidden {location} {location} operator+ (const location& @var{begin}, 
const location& @var{end})
address@hidden {location} {location} operator+ (const location& @var{begin}, 
int @var{width})
address@hidden {location} {location} operator+= (const location& @var{loc}, int 
@var{width})
+Various forms of syntactic sugar.
address@hidden deftypemethod
+
address@hidden {location} {void} step ()
+Move @code{begin} onto @code{end}.
address@hidden deftypemethod
+
+
address@hidden C++ Parser Interface
address@hidden C++ Parser Interface
address@hidden - define parser_class_name
address@hidden - Ctor
address@hidden - parse, error, set_debug_level, debug_level, set_debug_stream,
address@hidden   debug_stream.
address@hidden - Reporting errors
+
+The output files @address@hidden and @address@hidden
+declare and define the parser class in the namespace @code{yy}.  The
+class name defaults to @code{parser}, but may be changed using
address@hidden "parser_class_name" "@var{name}"}.  The interface of
+this class is detailled below.  It can be extended using the
address@hidden feature: its semantics is slightly changed since
+it describes an additional member of the parser class, and an
+additional argument for its constructor.
+
address@hidden {parser} {semantic_value_type}
address@hidden {parser} {location_value_type}
+The types for semantics value and locations.
address@hidden FIXME: deftypemethod pour des types ???
address@hidden deftypemethod
+
address@hidden {parser} {} parser (@var{type1} @var{arg1}, ...)
+Build a new parser object.  There are no arguments by default, unless
address@hidden @address@hidden @address@hidden was used.
address@hidden deftypemethod
+
address@hidden {parser} {int} parse ()
+Run the syntactic analysis, and return 0 on success, 1 otherwise.
address@hidden deftypemethod
+
address@hidden {parser} {std::ostream&} debug_stream ()
address@hidden {parser} {void} set_debug_stream (std::ostream& @var{o})
+Get or set the stream used for tracing the parsing.  It defaults to
address@hidden::cerr}.
address@hidden deftypemethod
+
address@hidden {parser} {debug_level_type} debug_level ()
address@hidden {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.
address@hidden deftypemethod
+
address@hidden {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}.
address@hidden deftypemethod
+
+
address@hidden C++ Scanner Interface
address@hidden C++ Scanner Interface
address@hidden - prefix for yylex.
address@hidden - Pure interface to yylex
address@hidden - %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
address@hidden directive.  Therefore the interface is as follows.
+
address@hidden {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
address@hidden @address@hidden @address@hidden yield additional arguments.
address@hidden deftypemethod
+
+
address@hidden A Complete C++ Example
address@hidden 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.
+
address@hidden
+* 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
address@hidden menu
+
address@hidden Calc++ --- C++ Calculator
address@hidden 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
address@hidden and @code{two}, is exchanged with the parser.  An example
+of valid input follows.
+
address@hidden
+three := 3
+seven := one + two * three
+seven * seven
address@hidden example
+
address@hidden Calc++ Parsing Driver
address@hidden Calc++ Parsing Driver
address@hidden - An env
address@hidden - A place to store error messages
address@hidden - 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
address@hidden 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.
+
address@hidden
+#ifndef CALCXX_DRIVER_HH
+# define CALCXX_DRIVER_HH
+# include <string>
+# include <map>
address@hidden example
+
address@hidden
+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.
+
address@hidden
+// Forward declarations.
+union YYSTYPE;
+namespace yy @{ class calcxx_parser; @}
+class calcxx_driver;
address@hidden example
+
address@hidden
+Then comes the declaration of the scanning function.  Flex expects
+the signature of @code{yylex} to be defined in the macro
address@hidden, and the C++ parser expects it to be declared.  We can
+factor both as follows.
address@hidden
+// 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;
address@hidden example
+
address@hidden
+The @code{calcxx_driver} class is then declared with its most obvious
+members.
+
address@hidden
+// Conducting the whole scanning and parsing of Calc++.
+class calcxx_driver
address@hidden
+public:
+  calcxx_driver ();
+  virtual ~calcxx_driver ();
+
+  std::map<std::string, int> variables;
+
+  int result;
address@hidden example
+
address@hidden
+To encapsulate the coordination with the Flex scanner, it is useful to
+have two members function to open and close the scanning phase.
+members.
+
address@hidden
+  // Handling the scanner.
+  void scan_begin ();
+  void scan_end ();
+  bool trace_scanning;
address@hidden example
+
address@hidden
+Similarly for the parser itself.
+
address@hidden
+  // Handling the parser.
+  void parse (const std::string& f);
+  std::string file;
+  bool trace_parsing;
address@hidden example
+
address@hidden
+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.
+
address@hidden
+  // Error handling.
+  void error (const yy::location& l, const std::string& m);
+  void error (const std::string& m);
address@hidden;
+#endif // ! CALCXX_DRIVER_HH
address@hidden 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.
+
address@hidden
+#include "calc++-driver.hh"
+#include "calc++-parser.hh"
+
+calcxx_driver::calcxx_driver ()
+  : trace_scanning (false), trace_parsing (false)
address@hidden
+  variables["one"] = 1;
+  variables["two"] = 2;
address@hidden
+
+calcxx_driver::~calcxx_driver ()
address@hidden
address@hidden
+
+void
+calcxx_driver::parse (const std::string &f)
address@hidden
+  file = f;
+  scan_begin ();
+  yy::calcxx_parser parser (*this);
+  parser.set_debug_level (trace_parsing);
+  parser.parse ();
+  scan_end ();
address@hidden
+
+void
+calcxx_driver::error (const yy::location& l, const std::string& m)
address@hidden
+  std::cerr << l << ": " << m << std::endl;
address@hidden
+
+void
+calcxx_driver::error (const std::string& m)
address@hidden
+  std::cerr << m << std::endl;
address@hidden
address@hidden example
+
address@hidden Calc++ Parser
address@hidden 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.
address@hidden
+%skeleton "lalr1.cc"                          /*  -*- C++ -*- */
+%define "parser_class_name" "calcxx_parser"
+%defines
address@hidden
+# include <string>
+# include "calc++-driver.hh"
address@hidden
address@hidden example
+
address@hidden
+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.
+
address@hidden
+// The parsing context.
+%parse-param @{ calcxx_driver& driver @}
+%lex-param   @{ calcxx_driver& driver @}
address@hidden example
+
address@hidden
+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.
+
address@hidden
+%locations
+%initial-action
address@hidden
+  // Initialize the initial location.
+  @@$.begin.filename = @@$.end.filename = &driver.file;
address@hidden;
address@hidden example
+
address@hidden
+Use the two following directives to enable parser tracing and verbose
+error messages.
+
address@hidden
+%debug
+%error-verbose
address@hidden example
+
address@hidden
+Semantic values cannot use ``real'' objects, but only pointers to
+them.
+
address@hidden
+// Symbols.
+%union
address@hidden
+  int          ival;
+  std::string *sval;
address@hidden;
address@hidden example
+
address@hidden
+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.
+
address@hidden
+%token        YYEOF          0 "end of file"
+%token        TOKEN_ASSIGN     ":="
+%token <sval> TOKEN_IDENTIFIER "identifier"
+%token <ival> TOKEN_NUMBER     "number"
+%type  <ival> exp              "expression"
address@hidden example
+
address@hidden
+To enable memory deallocation during error recovery, use
address@hidden
+
address@hidden
+%printer    @{ debug_stream () << *$$; @} "identifier"
+%destructor @{ delete $$; @} "identifier"
+
+%printer    @{ debug_stream () << $$; @} "number" "expression"
address@hidden example
+
address@hidden
+The grammar itself is straightforward.
+
address@hidden
+%%
+%start unit;
+unit: assignments exp  @{ driver.result = $2; @};
+
+assignments: assignments assignment @address@hidden
+           | /* Nothing. */         @address@hidden;
+
+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; @};
+%%
address@hidden example
+
address@hidden
+Finally the @code{error} member function registers the errors to the
+driver.
+
address@hidden
+void
+yy::calcxx_parser::error (const location_type& l, const std::string& m)
address@hidden
+  driver.error (l, m);
address@hidden
address@hidden example
+
address@hidden Calc++ Scanner
address@hidden Calc++ Scanner
+
+The Flex scanner first includes the driver declaration, then the
+parser's to get the set of defined tokens.
+
address@hidden
address@hidden                                            /* -*- C++ -*- */
+# include <string>
+# include "calc++-driver.hh"
+# include "calc++-parser.hh"
address@hidden
address@hidden example
+
address@hidden
+Because there is no @code{#include}-like feature we don't need
address@hidden, 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.
+
address@hidden
+%option noyywrap nounput batch debug
address@hidden example
+
address@hidden
+Abbreviations allow for more readable rules.
+
address@hidden
+id    [a-zA-Z][a-zA-Z_0-9]*
+int   [0-9]+
+blank [ \t]
address@hidden example
+
address@hidden
+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.
+
address@hidden
+%%
address@hidden
+  yylloc->step ();
+# define YY_USER_ACTION  yylloc->columns (yyleng);
address@hidden
address@hidden@}+   yylloc->step ();
+[\n]+      yylloc->lines (yyleng); yylloc->step ();
address@hidden example
+
address@hidden
+The rules are simple, just note the use of the driver to report
+errors.
+
address@hidden
+[-+*/]     return yytext[0];
+":="       return TOKEN_ASSIGN;
address@hidden@}      yylval->ival = atoi (yytext); return TOKEN_NUMBER;
address@hidden@}       yylval->sval = new std::string (yytext); return 
TOKEN_IDENTIFIER;
+.          driver.error (*yylloc, "invalid character");
+%%
address@hidden example
+
address@hidden
+Finally, because the scanner related driver's member function depend
+on the scanner's data, it is simpler to implement them in this file.
+
address@hidden
+void
+calcxx_driver::scan_begin ()
address@hidden
+  yy_flex_debug = trace_scanning;
+  if (!(yyin = fopen (file.c_str (), "r")))
+    error (std::string ("cannot open ") + file);
address@hidden
+
+void
+calcxx_driver::scan_end ()
address@hidden
+  fclose (yyin);
address@hidden
address@hidden example
+
address@hidden Calc++ Top Level
address@hidden Calc++ Top Level
+
+The top level file, @file{calc++.cc}, poses no problem.
+
address@hidden
+#include <iostream>
+#include "calc++-driver.hh"
+
+int
+main (int argc, const char* argv[])
address@hidden
+  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;
+      @}
address@hidden
address@hidden example
+
address@hidden ================================================= 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
 
 
address@hidden C++ Parsers
address@hidden C++ Parsers
-
address@hidden
-How can I generate parsers in C++?
address@hidden 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
address@hidden, use pointers to classes.
-
-
 @node Implementing Gotos/Loops
 @section Implementing Gotos/Loops
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]