Rule integer, factor, expression, term;
integer = +Parser.digit_p();
factor = integer
| Parser.ch_p('(') + expression + Parser.ch_p(')')
| (Parser.ch_p('-') + factor)
| (Parser.ch_p('+') + factor);
term = factor *((Parser.ch_p('*') + factor) | (Parser.ch_p('/') + factor));
expression = term * ((Parser.ch_p('+') + factor) | (Parser.ch_p('-') + factor));
This makes sense because we cannot use the rules before they have been initialized !
In C++ we'd just take a reference or pointer to the rule until they are defined; but this does not work in C#.
Instead I had to create a simple RuleRef class as follow:
public class RuleRef
{
private Rule ptr;
public Rule Value
{
get
{
return ptr;
}
set
{
ptr = value;
}
}
public static implicit operator Rule(RuleRef r)
{
return r.Value;
}
public RuleRef()
{
}
public RuleRef(Rule value)
{
ptr = value;
}
public static RuleRef operator +(RuleRef lhs, RuleRef rhs)
{
return new Sequence(lhs, rhs);
}
public static RuleRef operator +(RuleRef lhs)
{
return new OneOrMore(lhs);
}
public static RuleRef operator |(RuleRef lhs, RuleRef rhs)
{
return new Or(lhs, rhs);
}
public static RuleRef operator &(RuleRef lhs, RuleRef rhs)
{
return new Sequence(lhs, rhs);
}
public static RuleRef operator *(RuleRef lhs, RuleRef rhs)
{
return new Sequence(lhs, new ZeroOrMore(rhs));
}
}
This allow me to then write:
RuleRef integer = new RuleRef();
RuleRef factor = new RuleRef();
RuleRef expression = new RuleRef();
RuleRef term = new RuleRef();
integer = +Parser.digit_p();
Rule _factor = integer.Value.WithAction(DebugPrint)
| Parser.ch_p('(') + expression + Parser.ch_p(')')
| (Parser.ch_p('-') + factor)
| (Parser.ch_p('+') + factor);
Rule _term = factor *((Parser.ch_p('*') + factor) | (Parser.ch_p('/') + factor));
Rule _expression = term * ((Parser.ch_p('+') + factor) | (Parser.ch_p('-') + factor));
// Resolve the references to their correct values
factor.Value = _factor;
term.Value = _term;
expression.Value = _expression;
In the next post I will detail my simple recursive descent parser entirely written in C#/Linq.
Aucun commentaire:
Enregistrer un commentaire