在自上而下的解析器中处理分支

时间:2018-03-08 18:21:23

标签: compiler-construction javacc

我在JavaCC中实现了一个自上而下的解析器。所以我正在利用暴露给我的访客模式来行走AST。

如果我忽略控制流程,我已经解决了整个问题。我对控制流程的问题是如何管理分支机构以及它们指向的位置。具体来说,在IR生成中,这是我的情况:

// This is just to make my example explicit.
honorary_source_statement()
if (expression()) {
    statements...
} else if(expression'()) {
    statements...'
} else {
    statements...''
}
// This just to make my example explicit.
honorary_sink_statement()
statements()...'''

我可以将honorary_source_statement()绑定到前导if。我可以在if语句中将所有语句绑定到需要的位置。我还可以将所有后续分支绑定在一起:

  • if的确属于statements...
  • if的错误归else if
  • else如果属于statements...'
  • else if的错误归else
  • else转到statements...''

上述方法适用于if-statements的n-nesting。

我遇到的问题是采用statements...statements...'statements...''的最后一条指令并将其与honorary_sink_statement()相关联,它们各自的落空。我读过Appel书,龙书和Louden书。所有这些都只是手动波动,并没有深入了解管理它的细节。

我正在构建混合IR。所以它的结构是图形式,它使用修改后的3地址IR。

我甚至试图跳过一个步骤并使用基本块来表示这一点,但问题仍然存在:如何将接收器绑定到分支内的最终直通指令。

我的JavaCC的相关部分如下所示。

void Statement() :
{}
{
    LOOKAHEAD(AssignmentInstruction())
    AssignmentInstruction()
    /* omitted rest of statements for brevity */
    |   BranchStatement()
    |   FunctionInvoke()
}

void BranchStatement() :
{}
{
    <IF> <LPAREN> Expression() <RPAREN> <LBRACE> Statement() <RBRACE>
    (<ELSE_IF> <LPAREN> Expression() <RPAREN> <LBRACE> Statement()<RBRACE>)*
    (<ELSE> <LBRACE> Statement() <RBRACE>)?
}

这让我有一个访客结构:

 /**
  * f0 -> IfStatement()
  * f1 -> ( ElseIfStatement() )*
  * f2 -> ( ElseStatement() )?
  */
@Override
public BSVisitor visit(BranchInstruction n) {
    n.f0.accept(this);
    if(n.f1.present()) {
        n.f1.accept(this);
    }
    if(n.f2.present()) {
        n.f2.accept(this);
    }
}

/**
 * f0 -> <IF>
 * f1 -> <LPAREN>
 * f2 -> Expression()
 * f3 -> <RPAREN>
 * f4 -> <LBRACE>
 * f5 -> Statement()
 * f6 -> <RBRACE>
 */
@Override
public BSVisitor visit(IfStatement n) {
    // parse it!
}

/**
 * f0 -> <ELSE_IF>
 * f1 -> <LPAREN>
 * f2 -> Expression()
 * f3 -> <RPAREN>
 * f4 -> <LBRACE>
 * f5 -> Statement()
 * f6 -> <RBRACE>
 */
@Override
public BSVisitor visit(ElseIfStatement n) {
    // parse it!
}

/**
 * f0 -> <ELSE>
 * f1 -> <LBRACE>
 * f2 -> Statement()
 * f3 -> <RBRACE>
 */
@Override
public BSVisitor visit(ElseStatement n) {
    // parse it!
}

1 个答案:

答案 0 :(得分:0)

我不确定我是否完全理解这个问题,但无论如何我都会尝试回答。

首先,我会以不同的方式构建AST。如果我们代表

,那会更好
if( condition0 ) { statement1 }
elseif( condition1 ) {statement2}
elseif( condition2 ) { statement3 }
else { statement4 }

用这样的树

 IF -+-- Condition0
     |
     +-- Statement1
     |
     +-- IF -+-- Condition1
             |
             +-- Statement2
             |
             +-- IF -+-- Condition2
                     |
                     +-- Statement3
                     |
                     +-- Statement4

如果没有ELSE,只需将最终语句作为SKIP语句,即不执行任何操作的语句。

我假设您的IR是某种控制流图,由一堆由一堆边连接的节点组成。如果可以在目标节点之前创建边缘,则会有所帮助。

现在假设您有一些语句的访问者将一组边(尚未定位)作为输入,并生成一组边(尚未定位)作为输出。 SKIP语句的访问者将获取一组边并返回相同的集。赋值语句的访问者将获取一组边,生成一个节点,将所有这些边指向节点,然后生成一个离开节点并输出一组仅包含该边的边。

还假设条件的访问者采用一组尚未定向的边并返回两组尚未定向的边 - 一个用于条件为真时,一个用于条件为假时。

IF的访问者看起来像这样

visit( IF(c, s, t), S)
    (A, B) := visit( c, S )
    T := visit(s, A )
    U := visit(t, B )
    output T union U

您的示例代码连续有三个语句,您可以使用顺序组合节点在AST中表示,该节点只需要2个这样的子项

SEQCOMP -+-- statement0
         |
         +-- SEQCOMP -+-- statement1
                      |
                      +-- statement2

然后

visit( SEQCOMP(s, t), S)
    T := visit(s, S )
    U := visit(t, T )
    output U

或者,您可以使用具有可变数量子节点的单个节点表示三个语句的块:

BLOCK -+-- statement0
       |
       +-- statement1
       |
       +-- statement2

访客

visit( BLOCK( ss ), S)
    var T := S
    for t in ss
        T := visit(t, T )
    output T