Loops 循环';在ANTLR中迭代

Loops 循环';在ANTLR中迭代,loops,antlr,grammar,interpreter,pascal,Loops,Antlr,Grammar,Interpreter,Pascal,我正在尝试使用ANTLR制作一个Pascal解释器,目前在遍历AST树时处理循环时遇到了一些问题。 例如,For循环被解析为: parametricLoop : FOR IDENTIFIER ASSIGN start = integerExpression TO end = integerExpression DO statement -> ^( PARAMETRIC_LOOP IDENTIFIER $start $end statement ) ; (忽

我正在尝试使用ANTLR制作一个Pascal解释器,目前在遍历AST树时处理循环时遇到了一些问题。 例如,For循环被解析为:

parametricLoop
    : FOR IDENTIFIER ASSIGN start = integerExpression TO end = integerExpression DO
    statement
    -> ^( PARAMETRIC_LOOP IDENTIFIER $start $end statement )
    ;
(忽略带有DOWNTO的变量)。 我怎样才能让walker根据需要重复循环执行如此多次?我知道我应该使用input.Mark()和input.Rewind()来实现这一点。但它们究竟应该放在哪里呢?我当前的错误变体看起来是这样的(目标语言是C#):

parametricLoop
:
^(
参数环
标识符
开始=整数表达式
{
变量参数=Members.Variable($IDENTIFIER.text);
parameter.value=$start.result;
}
end=integerExpression
{
int end_值=$end.result;
如果((int)parameter.value>end_value)转到EndLoop;
参数化_loop_start=input.Mark();
}
陈述
{
parameter.value=(int)parameter.value+1;

if((int)parameter.value我没有使用ANTLR,但在我看来,您在解析程序时试图执行该程序,但这并不是解析器的真正目的(解析过程中可以执行简单的算术表达式,但正如您所发现的,循环是有问题的)。我强烈建议您仅使用解析来构造AST。因此,
parametricLoop
的解析器代码应该只构造一个表示循环的树节点,子节点表示变量、条件和主体。然后,在一个单独的常规C#类中(向其提供解析器生成的AST),通过以某种方式遍历树来执行代码,然后您可以完全自由地在节点之间来回跳跃,以模拟循环执行。

刚刚解决了一个类似的问题,有几点:

  • 似乎您需要使用BufferedTreeNodeStream而不是CommonTreeNodeStream,CommonTreeNodeStream对我来说从来都不起作用(花了很长时间才发现)

  • 使用seek对我来说似乎更清楚

  • 下面是我的列表命令代码,非常确定您的命令可以轻松更改为这种样式:

    list returns [Object r]
        :   ^(LIST ID
              {int e_index = input.Index;}
              exp=.
              {int s_index = input.Index;}
              statements=.
             )
            {
                int next = input.Index;
                input.Seek(e_index);
                object list = expression();
                foreach(object o in (IEnumerable<object>)list)
                {
                    model[$ID.Text] = o;
                    input.Seek(s_index);
                    $r += optional_block().ToString();
                }
                input.Seek(next);
            }
    
    list返回[objectr]
    :^(列表ID)
    {int e_index=input.index;}
    exp=。
    {int s_index=input.index;}
    语句=。
    )
    {
    int next=input.Index;
    输入搜索(e_索引);
    对象列表=表达式();
    foreach(对象o在(IEnumerable)列表中)
    {
    模型[$ID.Text]=o;
    输入搜索(s_索引);
    $r+=可选的_块().ToString();
    }
    输入。查找(下一步);
    }
    
    我使用ANTLR 3.4,并找到了一个使用CommonTreeNodeStream类的解决方案

    基本上,我分离了树解析器的新实例,树解析器又分析了所有子树。我的示例代码定义了一个while循环:

    tree grammar Interpreter;
    ...
    @members
    {
      ...
      private Interpreter (CommonTree node, Map<String, Integer> symbolTable)
      {
        this (new CommonTreeNodeStream (node));
        ...
      }
      ...
    }
    ...
    stmt    :   ...
            |   ^(WHILE c=. s1=.) // ^(WHILE cond stmt)
                {
                  for (;;)
                  {
                    Interpreter condition = new Interpreter (c, this.symbolTable);
                    boolean     result    = condition.cond ();
                    if (! result)
                      break;
    
                    Interpreter statement = new Interpreter (s1, this.symbolTable);
                    statement.stmt ();
                  }
                }
    ...
    cond returns [boolean result]
                              : ^(LT e1=expr e2=expr) {$result = ($e1.value < $e2.value);}
                              | ...
    
    树语法解释器;
    ...
    @成员
    {
    ...
    专用解释器(CommonTree节点,映射可符号化)
    {
    这个(新的CommonTreeNodeStream(节点));
    ...
    }
    ...
    }
    ...
    stmt:。。。
    |^(而c=.s1=)/^(而cond stmt)
    {
    对于(;;)
    {
    解释器条件=新解释器(c,this.symbolTable);
    布尔结果=condition.cond();
    如果(!结果)
    打破
    解释器语句=新解释器(s1,this.symbolTable);
    statement.stmt();
    }
    }
    ...
    cond返回[布尔结果]
    :^(LT e1=expr e2=expr){$result=($e1.value<$e2.value);}
    | ...
    
    Err,这些
    Mark()
    revind(…)
    方法是从树语法中调用的,对吗?我想它们也会引发异常?你说“知道使用input.Mark()和input.revind()”,但是谁告诉过你的呢?对于一个简单的基于树的解释器,请参阅:好的,那个人正试图用组合语法来实现这一点,而你正在用树语法来实现这一点(请注意,他/她正试图这样做,但没有成功!)。树语法是CommonTree对象的结构化集合,这些对象无权访问
    mark()
    倒带(…)
    方法,好吧。此外,在你的(树)语法中解释如此复杂的结构不是(IMHO)的方法,我真的看不到“快速修复”的方法。用“正确”的方法来做这件事会让一整页的文章变得相当大。
    tree grammar Interpreter;
    ...
    @members
    {
      ...
      private Interpreter (CommonTree node, Map<String, Integer> symbolTable)
      {
        this (new CommonTreeNodeStream (node));
        ...
      }
      ...
    }
    ...
    stmt    :   ...
            |   ^(WHILE c=. s1=.) // ^(WHILE cond stmt)
                {
                  for (;;)
                  {
                    Interpreter condition = new Interpreter (c, this.symbolTable);
                    boolean     result    = condition.cond ();
                    if (! result)
                      break;
    
                    Interpreter statement = new Interpreter (s1, this.symbolTable);
                    statement.stmt ();
                  }
                }
    ...
    cond returns [boolean result]
                              : ^(LT e1=expr e2=expr) {$result = ($e1.value < $e2.value);}
                              | ...