|
ok, as far as I understood, a typical line starts with a label (somevar), then at fixed position there is 'line type' indicator like CS, then some expression.
Here's how you do it.
Write your grammar as if there no restrictions on positions. But do one thing: define Label terminal (as IdentifierTerminal) - use it as a special terminal that will match the beginning "somevar" labels. Do not use it anywhere else in the grammar, define
a different terminal "Variable" for identifiers inside expressions.
Define LineType and Line nonterminal :
LineType.Rule = ToTerm("S") | "C" | "D" .... ;
Line.Rule = label + lineType + someExpr;
Now, the trick to use is to intercept when label terminal is "scanned" and do some hand coding.
Hook to 'label.ValidateToken' event. Do the following in the handler:
void label_ValidateToken(object sender, ValidateTokenEventArgs e) {
//Assuming lineType is at position 25
var label = e.Context.CurrentToken;
if (label.Location.Column > 0) {
e.SetError("invalid position of label, must start at first column.");
return;
}
// (also check label length, check that there are only spaces until pos 25, etc)
// advance source to linetype position
var lineStart = label.Location.Position;
var src = e.Context.Source;
src.Position = lineStart + 25;
// Read current char
var lineTypeStr = src.PreviewChar.ToString();
//Manually produce lineType token
// _lineType is class-level field containing line type terminal used in grammar
Token lineTypeToken = new Token(_lineType, src.Location, lineTypeStr, lineTypeStr);
//Pack labelToken and lineTypeToken into Multitoken
var multi = new MultiToken(label, lineTypeToken);
//Replace current token (label) with multitoken
e.ReplaceToken(multi);
}
Also add the following constructor to MultiToken in Irony core (it's just easier clearer way to create it, I will push this change next time):
public MultiToken(params Token[] tokens) : this(tokens[0].Terminal, tokens[0].Location, new TokenList()) {
ChildTokens.AddRange(tokens);
}
That should do it. Note I did not test the code, you may need to debug and tweak it. I hope the idea is clear enough
Roman
|