Parsing System (v0.5)
|
Static And Dynamic StylesGoldie supports two different styles of interfaces: a static-style and a dynamic-style. Both styles have pros and cons, and are suitable for different purposes. The differences are explained in the comparison chart and examples below. Note that if you use StaticLang to embed a language directly into your program, you can switch back and forth between static and dynamic styles however you wish. Which Style Should I Use?You can use whichever you want, but the recommended rule of thumb is: Use static-style unless what you're trying to do requires dynamic-style (such as Parse or Parse Anything). Comparison Chart
Types and InheritanceConsider this grammar: ! This is grammar "numberList.grm" "Start Symbol" = <List> Number = {Digit}+ <List> ::= <List> '+' Number | Number | In both dynamic-style and static-style, there are the types Language, Lexer and Parser. These classes work for any grammar. Static-style additionally subclasses those with the following types, which can *only* be used with the "numberList" grammar: Language_numberList, Lexer_numberList and Parser_numberList. These contain additional/modified functionality that provides better type-safety. The Token type works similarly, but with some extra subclasses: In dynamic-style, all of the language's symbols (ie, Number, <List> and the implicitly-defined Whitespace, Error and EOF) are represented by type Token. That is still true in static-style, but static-style also defines the following types: Subclass of Token:
Subclasses of Token_numberList:
Subclasses of Token_numberList!"Number":
Subclasses of Token_numberList!"<List>":
(Note: A future version of Goldie might be made to accept the actual rule, such as Token_numberList!"<List> ::= <List> '+' Number", instead of a list of separate strings.) See also Ambiguous Symbols. ExamplesThe following examples use the calc grammar. Example: Loading a LanguageStatic-style
// Run "goldie-staticlang calc.cgt /pack:myapp.mylangs" at the command-line
import goldie.all;
import myapp.mylangs.calc.all;
// Use 'language_calc'
Dynamic-styleDo the same as static-style, or: import goldie.all; Language language_calc = Goldie.loadCGT("calc.cgt"); // Use 'language_calc'Example: Parsing a sourceStatic-style
string src = ...;
Token_calc!"<Add Exp>" rootToken = language_calc.parseCode(src).parseTree;
See Token_ for details. ! Dynamic-style
string src = ...;
Token rootToken = language_calc.parseCodeX(src).parseTreeX;
Example: Checking a token's symbolStatic-style
// Check static/compile-time type (ie, not polymorphic)
bool isAddExp(Token_calc!"<Add Exp>" tok)
{
return true;
}
bool isAddExp(Token tok)
{
return false;
}
// Check run-time type (ie, polymorphic)
bool isAddExp(Token_calc tok)
{
return cast(Token_calc!"<Add Exp>")tok is null;
// Or to disambiguate (See the "Ambiguous Symbols" page):
return cast(Token_calc!(SymbolType.NonTerminal, "<Add Exp>"))tok is null;
}
Dynamic-style
bool isAddExp(Token tok)
{
return tok.name == "<Add Exp>";
// Or to disambiguate (See the "Ambiguous Symbols" page):
return tok.name == "<Add Exp>" && tok.type == SymbolType.NonTerminal;
}
Example: Checking a token's rule and retrieving a sub-tokenStatic-style
Token_calc!"<Mult Exp>" getMultExp(Token_calc!"<Add Exp>" tok)
{
// This represents the rule: <Add Exp> ::= <Add Exp> '+' <Mult Exp>
if( auto t = cast(Token_calc!("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>"))tok )
{
return t.sub!2;
}
}
Dynamic-style
Token getMultExp(Token tok)
{
// This represents the rule: <Add Exp> ::= <Add Exp> '+' <Mult Exp>
if( tok.matches("<Add Exp>", "<Add Exp>", "+", "<Mult Exp>") )
{
return tok.subX[2];
}
}
More ExamplesFor a full-program example of static-style versus dynamic-style, see Calculator Static and Calculator Dynamic. |