我想使用ANTLR解析一个简单的类似matlab的for循环。
循环就像:
for i=1:8
y(i) = a(i) + i;
end
我想解析循环并解析y(i) = a(i) + i
语句的8倍,以便对每个语句执行一些操作。
我的规则如下(操作在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'
;
实际上,当ANTLR解析statements
规则时,它会触发一些操作。所以,在这里,我告诉ANTLR i is a constant which value is 1
为初学者,然后我想重申statements
解析,同时递增我的i
常数。
重申一下,我使用input.Mark()和input.Rewind(),但是它没有按照我的预期工作,并且ANTLR引发了一些错误,告诉我一些“NEWLINE”令牌不存在于'for'keyword。
如果我想在循环结束之前触发某些操作,我该如何处理循环解析?
答案 0 :(得分:2)
我找到了解决方案。
实际上,正如我最初的预料,input.Rewind()
并不像goto
那样行事。它只是简单地将输入缓冲区恢复到由input.Mark()
定义的先前状态。
因此,当到达for循环结束时,如果条件仍为真,我将整个for循环重新注入输入缓冲区。
但是!在另一个规则中,我告诉ANTLR必须在for循环后跟一个NEWLINE。在我的情况下,通过重新注入,第一次通过循环后立即进行第二次循环,导致这种结构:
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
当然,由于没有NEWLINE
跟随前7个循环,ANTLR报告错误。
解决方案是简单告诉ANTLR for循环不需要跟NEWLINE
。它就像一个魅力,但我对这个结果并不满意......
最终的for循环规则看起来像(这只是代码清理):
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);
}
}
;