Instantiating in-line parsers

Once an application-specific parser class has been written, and its parser grammar made available as a runtime resource, an instance of it needs to be created. This is done by invoking a method of a static parser factory class, which causes the grammar to be parsed as part of its initialisation. The application can thereafter invoke the CreateInstance method of the parser factory class to create each parser instance.

Creating factories from grammar descriptions

Before any instance of an in-line parser can be created, a parser factory must be initialised from its input grammar description, and from a pre-existing application-specific parser class that implements any non-inline action and guard functions required by the parser. The details for the parser factory initialisation method and its parameters are given below:


public static void ParserFactory<TParser>.InitializeFromGrammar
(
    TextReader input,
    TextWriter tabOut,
    bool compressParser,
    bool supportErrorRecovery,
    bool generalisedParser,
    TextWriter sourceOutput = null
);

The method reads a character stream that contains the input grammar description in ParseLR grammar format, and creates a template of a state machine driven parser that is capable of parsing that grammar. This state machine is compiled to a dynamic assembly, and loaded into the current application, all within the method.

ARGUMENT DESCRIPTION
TParser This generic type parameter should be substituted with the class name for the application-specific parser class that is expected by the input grammar. This parser class is described elsewhere, but basically should provide any named action and guard functions needed by the grammar description, and not written as inline code directly in the grammar.
input The text stream containing the grammar description. The parser will be constructed from this grammar description. Note that any references to DLLs needed by the inline actions or guards written in the grammar will need to be included in the options section of the grammar.
tabOut An output text stream to which a tabular document describing the states, transitions and productions the parser works from will be written. If this parameter is null, no output tabular document is generated.
compressParser Set this parameter to true to turn on Pager's algorithm for compressing the size of the parsing tables. With this flag set to false, the parser generator creates a full LR(1) parser. Since Pager's algorithm does not remove any functionality from the parser, and does not restrict the range of unambiguous grammars that can be parsed, unlike the LALR(1) algorithm, there is little reason to not set this flag to true.
supportErrorRecovery When set to true, this enables the parser features that allow popping the parser state stack and discarding input tokens until a resynchronisation point in the grammar is reached. When set to false, the first unacceptable input parser token will cause the parser to halt the parsing before all the input tokens have been consumed. Only enable this flag if you are using the error keyword in your input grammar, as it degrades parser performance slightly to enable support for error recovery.
generalisedParser When set to true, this enables the parser to ignore shift/reduce and reduce/reduce conflicts in the grammar. This is necessary when building a generalised LR parser rather than one with a single lookahead token to resolve rule ambiguity.
sourceOutput An output text stream to which the autogenerated source code for the parser grammar will be written. If this optional parameter is left out, or set to null, no source code will be written out for you. Useful if trying to debug an inline parser.

If successful, the ParserFactory<TParser> class will have been initialised, and will therefore become the static runtime factory for creating instances of the parser. If unsuccessful, an ArgumentException is thrown, whose Message property is set to the combined error messages from the parser generation process.

Instantiating parser objects

The static ParserFactory<TParser>.CreateInstance() method allows a new parser instance of type TParser to be created. Remember that the ParseLR library is designed with workflow engines in mind. The initialisation of a parser factory is an expensive runtime operation. Creation of parser instances however is extremely fast. Hence a scenario in which many parser instances might be created, as in workflow applications for example, is directly supported by this parser factory design.

The method is described below:


public static TParser CreateInstance();

When this method is invoked, it uses the parser state machine structure from the parser factory to create a new instance of a parser that can parse input tokens conforming to the grammar.

The new parser inherits from the factory the state machine structure and hence the compression flag value and the error handling value. It does not inherit anything else. Hence the new parser has initially no output error or debug stream, and begins life with no input token stream connected.

Parser output messages

Parser objects have an ErrorLevel property that can be set to one of the levels NONE, ERROR, WARN, VERBOSE, or DEBUG. These levels are members of the MessageLevel enumeration. Later levels in the list include all messages that are rendered by the earlier (lower) levels. NONE forces the parser to remain silent, even in the presence of errors. ERROR reports errors, but skips warnings. WARN includes non-fatal warnings in the output, while VERBOSE describes all the shifts and reductions executed by the parser, albeit in a more succinct form than DEBUG. The DEBUG level is always used on the parser's DebugStream if this is not null. The default level if not otherwise set is WARN. See the example below:


MyParser p = ParserFactory<MyParser>.CreateInstance();
p.ErrorLevel = MessageLevel.VERBOSE;