Citron Parser Generator
Citron is an LALR parser generator for Swift. For a given input grammar, Citron creates a reentrant type-safe parser in Swift.
Features
Parsers made with Citron are:
-
Swifty
Citron encapsulates parsing-related data and functions into a parser class, and uses protocols and generics to provide a Swift-friendly interface for parsing and lexing.
-
Reentrant
We can have different instances of a Citron-generated parser class in the same program, and the different instances can be used concurrently. We can also have different Citron-generated parser classes in the same program, and instances of those classes can be used concurrently.
However, we should not access the same instance of a parser class from multiple threads at the same time (i.e. Citron-generated parsers are not thread-safe).
-
Type-safe
The Citron-generated code enforces type checking on the inputs and outputs of every code block in the grammar file, ensuring that bugs are caught at build time rather than at runtime.
-
Error-handling
Parsers generated by parser generators aren’t usually very good at handling errors. That’s one reason why writing a parser by hand might be preferable to using a parser generator.
However, a Citron-generated parser can be configured to handle errors intelligently, almost as good as parsers written by hand. Using Citron’s error capturing feature, the generated parser can give out clear error messages, recover from errors to continue parsing, and produce partial parse trees.
Origins
Citron is adapted from the Lemon parser generator by Richard Hipp, the creator of SQLite. Lemon is used to generate the parser that parses SQL statements in SQLite.
Requirements
Using Citron requires Swift 4. The parser has no dependancies other than the Swift Standard Library. The lexer is additionally dependant on Foundation for the use of regular expressions.
Using Citron
To make use of Citron, we should:
-
Create a grammar file
The grammar file contains the input grammar for which we’d like Citron to create a parser. It contains grammar rules, code blocks associated with the rules and Citron directives.
See The Citron Grammar File for information on how to write a grammar file.
-
Generate the parser
To generate a parser, we should compile Citron and then run Citron on the grammar file.
See Generating the parser for the commands that can accomplish this.
-
Use the parser
We can then use the parser class in our code, and provide it with inputs. We can optionally use Citron’s lexer to generate the inputs for the parser.
See The parsing interface for information on how we can use the parser in our code.
-
Handle errors
The easy way to handle errors is to catch the thrown errors, as described in The parsing interface.
However, to be able to recover from errors, produce partial parse trees and generate contextual error messages, we should use Error capturing.
Examples
A few examples of how Citron is used for parsing can be found in the “examples” folder in the project repository.
See also
- Introducing Citron: A quick overview of Citron and how to use it