bisonc++(1)

πŸŽ€ bisonc++(1) β€” the parser generator that serves πŸ’…

okay bestie, welcome to bisonc++(1), the manual page for the bisonc++ parser generator. this one's long so we're doing it in parts, but buckle up because it's genuinely iconic.


✨ NAME ✨

bisonc++ β€” generate a C++ parser class and parsing function πŸ¦‹


🌸 SYNOPSIS 🌸

bisonc++ [OPTIONS] grammar-file

πŸ’– DESCRIPTION πŸ’–

okay so storytime, because the lore here is lowkey deep. Bisonc++ descends from earlier work on bison by Alain Coetmeur (coetmeur@icdc.fr), who back in the early ’90s made a C++ class that wrapped up the yyparse function as generated by the GNU-bison parser generator. a whole pioneer fr fr.

The early versions of bisonc++ (everything up to version 0.92) were basically Alain's program wearing a cuter fit: they offered a more modern user-interface and stripped out all the old-style (C) %define directives from bison++'s input specification file (there's a whole in-depth discussion of the differences between bison++ and bisonc++ below, don't worry). Then starting with version 0.98, bisonc++ got a full glow-up β€” a complete rebuild of the parser generator, closely following descriptions given in Aho, Sethi and Ullman's Dragon Book πŸ‰. And since version 0.98, bisonc++ is a C++ program, rather than a C program generating C++ code. no cap, it's giving evolution.

Bisonc++ expands the concepts initially implemented in bison and bison++, and it serves a cleaner setup of the generated parser class. The parser class is derived from a base-class, mainly containing the parser's token- and type-definitions as well as several member functions which should not be modified by the programmer. hands off, bestie.

Most of these base-class members might also be defined directly in the parser class, but they were defined in the parser's base-class instead. and honestly? the design eats. it results in a very lean parser class, declaring only members that are actually defined by the programmer or that have to be defined by bisonc++ itself (e.g., the member function parse as well as some support functions requiring access to facilities that are only available in the parser class itself, rather than in the parser's base class).

This design does not require any virtual members: the members which are not involved in the actual parsing process may always be (re)implemented directly by the programmer. Thus there is no need to apply or define virtual member functions. clean. minimalist. main character energy.

Before version 5.00.00, bisonc++ offered one single manual page. the advantage of one man-page is of course that you never have to look for which manual page contains which information. but on the other hand, bisonc++'s man-page grew into a huge man-page of about 2000 lines in which it was hard to find your way 😭. From release 5.00.00 onward, three man-pages. The index below relates manual pages to their specific contents.

🧚 Overview of the contents of bisonc++'s man-pages

This man-page concentrates on the bisonc++ program itself, offering the following sections:

  • DESCRIPTION: a short description of bisonc++ and its roots;
  • FROM BISONC++ < 6.00.00 TO BISONC++ >= 6.00.00: required modifications when re-generating parsers;
  • OPTIONS: options supported by bisonc++.
  • QUICK START: a quick start overview about how to use bisonc++;
  • GENERATED FILES: files generated by bisonc++ and their purposes
  • FILES: skeleton files used by bisonc++;
  • SEE ALSO: references to other programs and documentation;
  • BUGS: some additional stuff that should not qualify as bugs.
  • ABOUT bisonc++: Some history;
  • AUTHOR: at the end of this man-page. )

The bisonc++input(7) man-page covers the details of the grammar-specification file. This man-page offers these sections:

  • DESCRIPTION: a short description of bisonc++ and its grammar file(s);
  • DIRECTIVES: bisonc++'s grammar-specification directives;
  • POLYMORPHIC SEMANTIC VALUES: how to use polymorphic semantic values in parsers generated by bisonc++;
  • DOLLAR NOTATIONS: available $-shorthand notations with single, union, and polymorphic semantic value types.
  • RESTRICTIONS ON TOKEN NAMES: name restrictions for user-defined symbols;
  • OBSOLETE SYMBOLS: symbols available to bison(1), but not to bisonc++;
  • USING SYMBOLIC TOKENS IN CLASSES OTHER THAN THE PARSER CLASS; how to refer to tokens defined in the grammar;
  • EXAMPLE: an example of using bisonc++;
  • SEE ALSO: references to other programs and documentation;
  • AUTHOR: at the end of this man-page.

The bisonc++api(3) describes the application programmer's interface, containing these sections:

  • DESCRIPTION: a short description of bisonc++ and its application programmer's interface;
  • PUBLIC SYMBOLS: constructor, enums, members, and types that can be used by calling software;
  • PRIVATE ENUMS AND -TYPES: enumerations and types only available to the Parser class;
  • PRIVATE MEMBER FUNCTIONS: member functions that are only available to the Parser class;
  • PRIVATE DATA MEMBERS: data members that are only available to the Parser class;
  • TYPES AND VARIABLES IN THE ANONYMOUS NAMESPACE: an overview of the types and variables that are used to define and store the grammar-tables generated by bisonc++;
  • SEE ALSO: references to other programs and documentation;
  • AUTHOR: at the end of this man-page.

🌈 FROM BISONC++ < 6.00.00 TO BISONC++ >= 6.00.00 🌈

okay this section is only relevant when re-generating parser code previously generated by bisonc++ versions before 6.00.00. if that's not you, you can scroll past, but honestly it's kind of fascinating so stay a sec.

Bisonc++ version 6.00.00 generates code that significantly differs from code generated by earlier versions. The identifiers of all members (both data and functions) that are generated by bisonc++ and accessible to the generated parser-class end in an underscore character. Member functions whose identifiers end in an underscore are owned' by bisonc++, are rewritten each time bisonc++is run, and should <red>**not**</red> be modified. Some members are defined as members of the generated parser-class, and are declared in the parser class header file (e.g.,parser.h) and some members are given default implementations in the parser's internal header file (e.g., parser.ih). Once generated, these files are left alone by bisonc++. so, when using bisonc++version <yellow>6.00.00</yellow> or beyond to re-generate a parser which was originally generated by an earlierbisonc++` version, the existing parser header and internal header files need some minor modifications πŸ’…:

  • void error(char const *) was changed to void error(). A default implementation is provided in the parser's internal header file. The current implementation directly inserts the text Syntax error into the standard output stream;
  • void exceptionHandler_(std::exception const &exc) was changed to void exceptionHandler(std::exception const &exc). A default implementation is provided in the parser's internal header file, and only its trailing underscore characters need to be removed;
  • int lookup(bool recovery): remove this member declaration from the previously generated parser class;
  • The following members are declared without a trailing underscore character in the generated parser class. An underscore character should be added to their identifiers: executeAction, errorRecovery, nextToken.
  • The member void nextCycle_() must be declared in the private section of the generated parser class.

Previously, several data members of the parser's base class were directly accessible to the parser class. Bisonc++ version 6.00.00 restricts access to those members. They can still be read, but no longer modified by the parser class. This applies to the following members:

  • d_token_: use int token_() instead;
  • d_state_: use size_t state_() instead;

✨ OPTIONS ✨

Where available, single letter options are listed between parentheses beyond their associated long-option variants. Single letter options require arguments if their associated long options also require arguments. Options affecting the class- or implementation header files are ignored if these files already exist. Options accepting a filename do not accept path names, i.e., they cannot contain directory separators (/); options accepting a 'pathname' may contain directory separators.

Some options may cause errors. This happens when they conflict with the contents of a file which bisonc++ cannot modify (e.g., a parser class header file exists, but doesn't define a namespace, but a --namespace option was specified).

To solve the error the offending option could be omitted; the existing file could be removed; or the existing file could be hand-edited according to the option's specification.

heads up bestie: bisonc++ currently does not handle the opposite error condition: if a previously used option is omitted, then bisonc++ does not report an inconsistency. In those cases compilation errors may be observed. 😭
  • --analyze-only (-A) β€” Only analyze the grammar. No files are (re)written. This option can be used to test the grammatic correctness of modification in situ, without overwriting previously generated files. If the grammar contains syntactic errors only syntax analysis is performed.
  • --baseclass-header=filename (-b) β€” Filename defines the name of the file to contain the parser's base class. This class defines, e.g., the parser's symbolic tokens. Defaults to the name of the parser class plus the suffix base.h. It is generated, unless otherwise indicated (see --no-baseclass-header and --dont-rewrite-baseclass-header below).

It is an error if this option is used and an already existing parser class header file does not contain #include "filename".

  • --baseclass-preinclude=pathname (-H) β€” Pathname defines the path to the file preincluded in the parser's base-class header. This option is needed in situations where the base class header file refers to types which might not yet be known. E.g., with polymorphic semantic values a std::string value type might be used. Since the string header file is not by default included in parserbase.h we somehow need to inform the compiler about this and possibly other headers. The suggested procedure is to use a pre-include header file declaring the required types. By default header is surrounded by double quotes: #include "header" is used when the option -H header is specified. When the argument is surrounded by pointed brackets #include <header> is included. In the latter case, quotes might be required to escape interpretation by the shell (e.g., using -H '<header>').
  • -B, --baseclass-skeleton=pathname β€” bestie, pathname is the path to the file that holds the skeleton of your parser's base class πŸ’…. Skip it and it defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++base.h). no stress 🫢
  • -c, --class-header=filename β€” filename is the name of the file that's gonna contain the parser class πŸŽ€. Defaults to the name of the parser class plus the suffix .h.
It is an error if this option is used and an already existing implementation header file does not contain #include "filename". πŸ’€
  • --class-name className β€” sets the name of the C++ class that gets generated ✨. If neither this option nor the %class-name directive is specified, then the default class name (Parser) is used, periodt.
It is an error if this option is used and className differs from the name of the class that is defined in an already existing parser-class header file, and/or if an already existing implementation header file does not define members of the class className. 😭
  • -C, --class-skeleton=pathname β€” pathname is the path to the file containing the skeleton of the parser class πŸ¦‹. Defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++.h).
  • --construction β€” all the tea β˜• about how the parsing tables are constructed gets written to the same file as the --verbose option writes (i.e., <grammar>.output, where <grammar> is the input file read by bisonc++). This is lowkey for developers πŸ‘‘ β€” it augments the information written to the verbose grammar output file generated by --verbose.
  • --debug β€” hooks your generated parse and its support functions up with debugging code, optionally showing the actual parsing process on the standard output stream πŸ’–. When it's included, the debugging output is active by default, but its activity may be controlled using the setDebug(bool on-off) member. bisonc++ does not use #ifdef DEBUG macros, no cap. Wanna remove the debugging code? Rerun bisonc++ without the --debug option.

Note that this option does not show the actions of bisonc++'s own parser, its own lexical scanner, or merely the numbers of the case-entries executed by the parser's parse function πŸ™ˆ. If that's the vibe you want, use the --own-debug, --action-cases, --scanner-debug and/or --own-tokens options.

When polymorphic semantic values are used (see section POLYMORPHIC SEMANTIC VALUES) then the generated parser might attempt to retrieve an incorrect polymorphic value πŸ‘€. In that case a fatal error is generated, ending bisonc++'s run πŸ’€. The error message itself cannot refer to the action block where the error occurred. If this situation is encountered, rerun bisonc++, specifying --debug and call parser.setDebug(Parser::ACTIONCASES): as a debugging aid the generated parser then shows the executeAction switch's case entry numbers just before their execution. slay.

  • -d, --default-actions=off|quiet|warn β€” three moods, pick one πŸŽ€:
    • warn (which is the default): an action block executing $$ = $1 (or $$ = STYPE_{} for empty production rules) is added to production rules that do not explicitly define their own final action blocks, while issuing a warning.
    • quiet: these action blocks are silently added. 🀫
    • off: no action blocks are added (issuing a warning unless the option/directive tag-mismatches off has been specified).
It is an error when the types of $$ and $1 differ (but it is OK if neither $$ nor $1 is associated with a specific type). 😭
  • --error-verbose β€” when a syntactic error is reported, the generated parse function dumps the parser's state stack to the standard output stream πŸ’…. The stack dump shows on separate lines a stack index followed by the state stored at the indicated stack element. The first stack element is the stack's top element. iconic.
  • -f, --filenames=filename β€” filename is a generic file name that's used for all header files generated by bisonc++ 🌈. Options defining specific file names are also available (and those, in turn, overrule the name specified by this option). fr fr.
  • --flex β€” bisonc++ generates code calling d_scanner.yylex() to obtain the next lexical token, and calling d_scanner.YYText() for the matched text, unless overruled by options or directives explicitly defining these functions ✨. By default, the interface defined by flexc++(1) is used. This option is only interpreted if the --scanner option or %scanner directive is also used β€” iykyk.
  • -h, --help β€” writes basic usage information to the standard output stream and terminates 🫢.
  • -i, --implementation-header=filename β€” filename is the name of the file that's gonna hold the implementation header πŸ’–. It defaults to the name of the generated parser class plus the suffix .ih.

The implementation header should contain all directives and declarations only used by the implementations of the parser's member functions. It is the only header file that is included by the source file containing parse's implementation. User defined implementation of other class members may use the same convention, thus concentrating all directives and declarations that are required for the compilation of other source files belonging to the parser class in one header file. one file, all the vibes ✨

  • -I, --implementation-skeleton=pathname β€” pathname is the path to the file containing the skeleton of the implementation header πŸ¦‹. It defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++.ih).
  • --insert-stype β€” this one is only effective if the debug option (or %debug directive) has been specified πŸ‘€. When insert-stype has been specified the parsing function's debug output also shows selected semantic values. It should only be used if objects or variables of the semantic value type STYPE_ can be inserted into ostreams.
  • --max-inclusion-depth=value β€” sets the maximum number of nested grammar files 🌸. Defaults to 10.
  • --namespace identifier β€” defines all of the code generated by bisonc++ in the namespace identifier πŸ‘‘. By default no namespace is defined. If this option is used the implementation header is provided with a commented out using namespace declaration for the specified namespace. In addition, the parser and parser base class header files also use the specified namespace to define their include guard directives.
It is an error if this option is used and an already existing parser-class header file and/or implementation header file does not define namespace identifier. πŸ’€
  • --no-baseclass-header β€” do not write the file containing the parser class' base class, even if that file doesn't yet exist πŸ™ˆ. By default the file containing the parser's base class is (re)written each time bisonc++ is called.
Note that this option should normally be avoided, as the base class defines the symbolic terminal tokens that are returned by the lexical scanner. When the construction of this file is suppressed, modifications of these terminal tokens are not communicated to the lexical scanner. 😭
  • -D, --no-decoration β€” don't include user-defined or default actions when generating the parser's parse member πŸ’…. This effectively generates a parser which merely performs syntax checks, without performing the actions which are normally executed when rules have been matched. This may be useful in situations where a (partially or completely) decorated grammar is reorganized, and the syntactic correctness of the modified grammar must be verified, or in situations where the grammar has already been decorated, but functions which are called from the rules's actions have not yet been implemented. syntax check only, no chaos ✨
  • --no-lines β€” don't put #line preprocessor directives in the file containing the parser's parse function πŸŽ€. By default the file containing the parser's parse function also contains #line preprocessor directives. This option allows the compiler and debuggers to associate errors with lines in your grammar specification file, rather than with the source file containing the parse function itself. so handy 🫢
  • --no-parse-member β€” do not write the file containing the parser's predefined parser member functions, even if that file doesn't yet exist 😭. By default the file containing the parser's parse member function is (re)written each time bisonc++ is called.
Note that this option should normally be avoided, as this file contains parsing tables which are altered whenever the grammar definition is modified. πŸ’€
  • --own-debug β€” displays the actions performed by bisonc++'s parser when it processes the grammar specification file(s) (lots of output! 😡). This implies the --verbose option.
  • -T, --own-tokens β€” the tokens returned as well as the text matched by bisonc++'s lexical scanner are shown when this option is used πŸ‘€.

Note that this option does not result in the generated parsing function displaying returned tokens and matched text. If that's what you want, use the --print-tokens option. fr fr, different things.

  • -P, --parsefun-skeleton=pathname β€” pathname is the path name of the file containing the parsing member function's skeleton πŸ¦‹. It defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++.cc).
  • -p, --parsefun-source=filename β€” filename is the name of the source file that's gonna contain the parser member function parse πŸ’–. Defaults to parse.cc.
  • -L, --polymorphic-code-skeleton=pathname β€” pathname is the path name of the file containing the non-template members of the polymorphic Base class πŸ‘‘. It defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++polymorphic.code).
  • --polymorphic-skeleton=pathame, -M β€” bestie this one tells bisonc++ where the file lives that holds the skeleton of the polymorphic template classes 🧚. It defaults to the installation-defined default path name (e.g., /usr/share/bisonc++/ plus bisonc++polymorphic).
  • --print-tokens, -t β€” okay so when you turn this on, the generated parsing function implements a function print_ that displays (on the standard output stream) the tokens returned by the parser's scanner and the corresponding matched text ✨. This implementation is suppressed when the parsing function is generated without using this option. The member print_ is called from Parser::print, which is defined in-line in the the parser's class header. So calling Parser::print_ can be super easily controlled from print, using, e.g., a variable that set by the program using the parser generated by bisonc++ πŸ’….
heads up though: this option does not show the tokens returned and text matched by bisonc++ itself when it is reading its input file(s). If that's what you want, use the --own-tokens option πŸ™ˆ.
  • --prompt β€” when you're adding debugging code (using the debug option or directive) the debug information is displayed continuously while the parser processes its input. When using the prompt option (or directive) the generated parser displays a prompt (a question mark ❓) at each step of the parsing process. Caveat: when using this option the parser's input cannot be provided at the parser's standard input stream 😭.
  • --required-tokens=number β€” following a syntactic error, require at least number successfully processed tokens before another syntactic error can be reported. By default number is zero.
  • --scanner=pathname, -s β€” pathname defines the path name to the file defining the scanner's class interface (e.g., "../scanner/scanner.h"). When this option is used the parser's member int lex() is predefined as
int Parser::lex()
{
    return d_scanner.lex();
}

and an object Scanner d_scanner is composed into the parser (but see also option scanner-class-name). The example shows the function that's called by default. When the --flex option (or %flex directive) is specified the function d_scanner.yylex() is called. Any other function to call can be specified using the --scanner-token-function option (or %scanner-token-function directive).

By default bisonc++ surrounds pathname by double quotes (using, e.g., #include "pathname"). When pathname is surrounded by pointed brackets #include <pathname> is included πŸŽ€.

It is an error if this option is used and an already existing parser class header file does not include pathname.
  • --scanner-class-name scannerClassName β€” defines the name of the scanner class, declared by the pathname header file that is specified at the scanner option or directive. By default the class name Scanner is used πŸ‘‘.
It is an error if this option is used and either the scanner option was not provided, or the parser class interface in an already existing parser class header file does not declare a scanner class d_scanner object.
  • --scanner-debug β€” shows the scanner's matched rules and returned tokens πŸ¦‹. This extensively displays the rules and tokens matched and returned by bisonc++'s scanner, instead of just showing the tokens and matched text which are received by bisonc++. If you want the latter, use the option --own-tokens.
  • --scanner-matched-text-function=function-call β€” the scanner function returning the text that was matched at the last call of the scanner's token function. A complete function call expression should be provided (including a scanner object, if used). This option overrules the d_scanner.matched() call used by default when the %scanner directive is specified, and it overrules the d_scanner.YYText() call used when the %flex directive is provided. Example:
--scanner-matched-text-function "myScanner.matchedText()"
  • --scanner-token-function=function-call β€” the scanner function returning the next token, called from the parser's lex function. A complete function call expression should be provided (including a scanner object, if used). This option overrules the d_scanner.lex() call used by default when the %scanner directive is specified, and it overrules the d_scanner.yylex() call used when the %flex directive is provided. Example:
--scanner-token-function "myScanner.nextToken()"
It is an error if this option is used and the scanner token function is not called from the code in an already existing implementation header.
  • --show-filenames β€” writes the names of the generated files to the standard error stream πŸ“’.
  • --skeleton-directory=directory, -S β€” specifies the directory containing the skeleton files. In addition to specifying a common names for the skeleton files the locations of individual skeleton files can be specified using the options (-B -C, -H, -I, -L and -M).
  • --stack-expansion(size) β€” defines the number of elements to be added to the generated parser's semantic value stack when it must be enlarged. By default 10 elements are added to the stack. This option/directive is interpreted only once, and only if size at least equals the default stack expansion size of 10 πŸ’œ.
  • --tag-mismatches off|on β€” when on is specified (which is the default), a warning is issued if no $$ assignment was detected in an action block, or if adding a default $$ = ... action was suppressed (cf. the default-actions off option or directive) ⚠️.
  • --target-directory=pathname β€” pathname defines the directory where generated files should be written. By default this is the directory where bisonc++ is called 🌸.
  • --thread-safe β€” only used with polymorphic semantic values, and then only required when the parser is used in multiple threads: it ensures that each thread's polymorphic code only accesses its own parser's error counting variable 🧡.
  • --token-class=classname, -K β€” classname defines the name of the Tokens class that is defined when token-path (see below) is specified. If token-path isn't specified then this option is ignored. By default the class name Tokens is used.
  • --token-namespace=namespace, -N β€” if token-path is specified (see below) then namespace defines the namespace of the Tokens class. By default no namespace is used.
  • --token-path=pathname, -F β€” pathname defines the path name of the file to contain the struct Tokens defining the enumeration Tokens_ containing the symbolic tokens of the generated grammar. If this option is specified the ParserBase class is derived from it, thus making the tokens available to the generated parser class. The name of the struct Tokens can be altered using the token-class directive or option. By default (i.e., if token_path is not specified) the tokens are defined as the enum Tokens_ in the ParserBase class. If pathname doesn't exist it is created by bisonc++. If the pathname file already exists it is rewritten at each new run of bisonc++ πŸ”₯.
  • --usage β€” writes basic usage information to the standard output stream and terminates.
  • --verbose, -V β€” writes a file containing verbose descriptions of the parser states and what is done for each type of look-ahead token in that state. This file also describes all conflicts detected in the grammar, both those resolved by operator precedence and those that remain unresolved. It is not created by default, but if requested the information is written on <grammar>.output, where <grammar> is the grammar specification file passed to bisonc++ πŸ“.
  • --version, -v β€” displays bisonc++'s version number and terminates.

🌈 QUICK START 🌈

bisonc++ may be used as follows, bestie, step by step 🫢:

  1. First, define a plain grammar: no actions, just the rules. Refer to bisonc++'s manual and other sources (like Aho, Sethi and Ullman's book) for details about how to define and decorate grammars πŸ“š.
  2. Having defined the grammar and (usually) some directives (advice: always use the %oken-path directive) bisonc++ is run, generating the essential elements of a parser class. See the next section for details about the files generated by bisonc++.
  3. No macro style %define declarations are required. Instead, the normal practice of defining class members in source files and declaring them in class header files can be followed when using bisonc++. bisonc++ concentrates on its main tasks: defining a parser class and implementing the parsing function int parse, leaving all other parts of the parser class' definition to the programmer πŸ‘‘.
  4. Next, members required in addition to the bisonc++-generated member parse and its support functions must be implemented by the programmer, and declared in the parser's class header. At the very least a member int lex must be defined (a default implementation can be generated by bisonc++) ✨.
  5. The generated parser can now be used in a program. A very simple example would be:
int main()
{
    Parser parser;
    return parser.parse();
}
like literally that's it, you have a parser, main character energy fr fr πŸ’…πŸ’–

✨ GENERATED FILES ✨

okay bestie, so when you run bisonc++, it's gonna manifest some files for you. here's the whole girlies line-up πŸ’…

  • A file holding the implementation of the member function parse plus all its little support functions. parse is a public member β€” you call it to parse a token-sequence according to a specified LALR1 type of grammar. Default name: parse.cc. πŸŽ€ And listen: do NOT touch this file. it gets rewritten every single time bisonc++ runs. it's not yours, it's hers.
  • A file with the initial setup of the parser class β€” the declaration of the public parse member and its (private) support members. Here's the tea: you can safely declare new members in the parser class, because bisonc++ only creates this file if it doesn't already exist. filename is <parser-class>.h (where <parser-class> = the name of your defined parser class). 🫢
  • A file with the parser class's base class. hands off this one too β€” the programmer should not modify it. it holds types defined by bisonc++, plus a bunch of (protected) data members and member functions that you should not redefine. all symbolic parser terminal tokens live in this class, which escalates those definitions into a separate class (cf. Lakos, (2001)) β€” and that's the whole point, because it prevents circular dependencies between the lexical scanner and the parser. like, those circles are SO easy to fall into: the parser needs access to the lexical scanner class when defining the scanner as one of its data members, and the scanner needs access to the parser class to know about the grammar's symbolic terminal tokens. escalation is the escape hatch. πŸ¦‹ by default this file gets (re)written every time bisonc++ is called, named <parser-class>base.h.
  • A file with an implementation header. this is the one your parser's source files should include (not the class header!) when implementing member functions you declared. it first includes the parser class's header file, then gives you default in-line implementations for its members error and print (you're free to change those). the member lex can also get a standard in-line implementation β€” or you can provide your own (see below). after that comes any directives and/or namespace directives needed to properly compile your parser's extra member functions. and fun fact: the file defining parse includes this implementation header. by default it's created if it doesn't exist yet, named <parser-class>.ih. ✨
  • A verbose description of the generated parser. it's comparable to the verbose output file originally generated by bison++. you get it when you pass --verbose or -V. when you do, bisonc++ writes <grammar>.output, where <grammar> is the name of the file containing the grammar definition. πŸ‘‘

🌸 FILES 🌸

these are the skeleton files chilling in the bisonc++ source directory, bestie:

  • bisonc++base.h β€” skeleton of the parser's base class;
  • bisonc++.h β€” skeleton of the parser class;
  • bisonc++.ih β€” skeleton of the implementation header;
  • bisonc++.cc β€” skeleton of the member parse;
  • bisonc++polymorphic β€” skeleton of the declarations used by %polymorphic;
  • bisonc++polymorphic.code β€” skeleton of the non-inline implementations of the members declared in bisonc++polymorphic.
  • debugdecl.in β€” skeleton declaring members of the parser's base class that are only required when the debug option or directive was specified.
  • debugfunctions1.in β€” skeleton defining the members declared in debugdecl.in.
  • debugfunctions2.in β€” skeleton implementing symbol_, which is only needed when the print-tokens option or directive was specified.
  • debugfunctions3.in β€” skeleton implementing errorVerbose_, which is only needed when the error-verbose option or directive was specified.
  • debugincludes.in β€” skeleton specifying the header files #include directives that are required when the debug option or directive was specified.
  • debuglookup.in β€” skeleton containing extra code required in the Parser::lookup member when the debug option of directive was specified.
  • lex.in β€” skeleton implementing the Parser::lex function.
  • ltypedata.in β€” skeleton declaring the location variables
  • ltype.in β€” skeleton defining the default or user defined LTYPE_.
  • print.in β€” skeleton implementing the actions of Parser::print if the print-tokens option or directive was specified.

πŸ” SEE ALSO πŸ”

bison(1), bison++(1), bisonc++api(3), bisonc++input(7), bison.info (using texinfo), flexc++(1), https://fbb-git.gitlab.io/bisoncpp/

Lakos, J. (2001) Large Scale C++ Software Design, Addison Wesley.

Aho, A.V., Sethi, R., Ullman, J.D. (1986) Compilers, Addison Wesley.


πŸ’€ BUGS πŸ’€

ngl, there's some stuff you gotta know before you come for bisonc++:

Parser-class header files (e.g., Parser.h) and parser-class internal header files (e.g., Parser.ih) generated with bisonc++ < 6.00.00 require several minor hand-modifications when re-generating the parser with bisonc++ >= 6.00.00. see the earlier section FROM BISONC++ < 6.00.00 TO BISONC++ >= 6.00.00 for the deets. 😭

also β€” to avoid collisions with names defined by the parser's (base) class, these identifiers should not be used as token names:

  • Identifiers ending in an underscore;
  • Any of the following identifiers: ABORT, ACCEPT, ERROR, debug, error, or setDebug.
fr fr do not name a token debug. it's giving collision. it's giving chaos. just don't. πŸ™ˆ

πŸ‘‘ ABOUT bisonc++ πŸ‘‘

history lesson time, bestie, sit down πŸ“

Bisonc++ was based on bison++, originally developed by Alain Coetmeur (coetmeur@icdc.fr), R&D department (RDT), Informatique-CDC, France, who based his work on bison, GNU version 1.21.

Bisonc++ version 0.98 and beyond is a complete rewrite of an LALR-1 parser generator, closely following the construction process as described in Aho, Sethi and Ullman's (1986) book Compilers (i.e., the Dragon book). πŸ‰ It uses the same grammar specification as bison and bison++, and it uses practically the same options and directives as bisonc++ versions earlier than 0.98. Variables, declarations and macros that are obsolete were removed. bye bye leftovers πŸ’…

Compared to bison and bison++, the number and functions of the various %define declarations was thoroughly modified. All of bison's %define declarations were replaced by their (former) first arguments. Furthermore, macro-style declarations are not supported or required. Finally, all directives only use lower-case characters and do not contain underscore characters (but sometimes hyphens). E.g., %define DEBUG is now declared as %debug; %define LSP_NEEDED is now declared as %lsp-needed (note the hyphen). ✨


🫢 AUTHOR 🫢

Frank B. Brokken (f.b.brokken@rug.nl).


and that's a wrap on the whole manpage, bestie!! πŸŽ€ you made it to the end, iconic behavior, no cap πŸ’– this was bisonc++.6.09.02, dated 2005-2025, and yes the page is literally called bisonc++(1). go write a parser, you absolute main character πŸ‘‘βœ¨πŸ¦‹

πŸ“¦ where this page comes from