Parsing a loop with ANTLR
I want to parse a simple matlab-like for-loop using ANTLR.
The loop is like:
for i=1:8
y(i) = a(i) + i;
end
I want to parse the loop and parse the instruction 8 times y(i) = a(i) + i
to do some actions for each statement.
My rule looks like this (actions are described in C #):
forloop
@init
{
string c = "";
int mark = input.Mark();
}
@after
{
if (constants[c] < $i2.value) {
SetConst(c, constants[c] + 1);
input.Rewind(mark);
}
}
: 'for' IDENT '=' i1=constant ':' i2=constant NEWLINE
{
c = $IDENT.text;
if (!IsConst(c)) {
AddConst(c, $i1.value);
}
}
statements?
'end'
;
Actually, when ANTLR analyzes a rule statements
, it triggers some action. So, here I will tell ANTLR what is i is a constant which value is 1
for starters, and then I want to repeat the parsing statements
, increasing the constant i
.
I repeat, I am using input.Mark () and input.Rewind (), but it does not work as I expect and some error is thrown by ANTLR, telling me that some NEWLINE tokens are missing for the "for" keyword.
How can I handle the par-syntax if I want to trigger some actions until the loop ends?
a source to share
I found a solution. In fact, it input.Rewind()
does not act goto
as I expected. It just simply restores the input buffer to the previous state defined input.Mark()
.
So when you reached the end of my for loop, if the condition was still true, I re-integrated the entire for loop into the input buffer.
BUT! In another rule, I told ANTLR that the loop MUST be followed by a NEWLINE. And in my case, through a re-install, the first pass for the loop was immediately followed by a loop of the second pass, resulting in this construct:
for i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
endfor i=1:8
y(i) = a(i) + i;
end
Of course, since no NEWLINE
followed the first 7th cycle, ANTLR reported an error.
The solution was to just tell ANTLR not to follow for the for loop NEWLINE
. It works like a charm, but I'm not that satisfied with this result ...
The last rule of the for-loop looks like (this is just a code cleanup):
forloop
@init {int mark = input.Mark();}
: 'for' IDENT '=' i1=constant ':' i2=constant NEWLINE
{
string c = $IDENT.text;
if (!IsConst(c)) {
AddConst(c, $i1.value);
}
}
statements? 'end'
{
if (constants[c] < $i2.value) {
SetConst(c, constants[c] + 1);
input.Rewind(mark);
}
}
;
a source to share