Continuing our parser improvements, we can follow Dominus's lead and use operator overloading to cut down the syntactical clutter:
Operators added to Parser
public static Parser operator -(Parser a, Parser b)
{
return new Concatenate(a, b);
}
public static Parser operator |(Parser a, Parser b)
{
return new Alternate(a, b);
}
public static Parser operator >(Parser p, ValuesTransform map)
{
return new T(p, map);
}
// C# forces us to overload < and > in pairs
public static Parser operator <(Parser p, ValuesTransform map)
{
return new T(p, map);
}
Add a few more static helpers, and we have the following much nicer looking generator.
static Parser MakeParser()
{
ParserStub exprstub = new ParserStub(new StubToReal(GetExpression));
ParserStub termstub = new ParserStub(new StubToReal(GetTerm));
ParserStub factstub = new ParserStub(new StubToReal(GetFactor));
expression =
termstub - _(Tokens.Operator, "+") - exprstub > TOpFirst |
termstub;
term =
factstub - _(Tokens.Operator, "*") - termstub > TOpFirst |
factstub;
Parser open = _(Tokens.Operator, "(");
Parser close = _(Tokens.Operator, ")");
Parser comma = _(Tokens.Operator, ",");
Parser arglist =
open - exprstub - new Star(comma - exprstub) - close;
factor =
_(Tokens.Identifier) - (arglist | new Nothing()) > TTagVarOrFunction |
open - exprstub - close > TStripParens |
_(Tokens.Integer);
return exprstub - new EndOfInput() > TOnlyExpression;
}
In Higher-Order Perl, Dominus overloads right-shift to generate a transformation instead of greater-than as above, but C# requires the second operand of >> to be an int. Note also that C# requires overloading both the less-than and greater-than operators if either is defined.
Using binary operators changes the structure of the AST. This has the effect of beating OpFirst with an ugly stick:
static private ArrayList OpFirst(ArrayList values)
{
ArrayList result = new ArrayList(3);
result.Add(((ArrayList)values[0])[1]); // ugh
result.Add(((ArrayList)values[0])[0]);
result.Add(values[1]);
return result;
}
No comments:
Post a Comment