我是否需要使用Stack来实现递归下降解析器?

时间:2019-02-11 00:31:34

标签: compiler-construction recursive-descent

我启动了递归下降解析器,到目前为止,它工作正常。解析输入后,它将返回“ ACCEPT”或“ REJECT”。但是,我在网上和另一本教科书中看到它们是“使用PDA进行自上而下的解析”。 因此,我只是想确认一下,这只是编码解析器的另一种方式,而不是THE方式。 我的解析器看起来像这样:

public class Parser {

private int n = 0;
private Tokens token = Main.TokenList.get(n);

public Parser() {
        Boolean bool = parse_Program();
        if (bool){
            System.out.println("ACCEPT");
        }else System.out.println("REJECT");

}

Boolean parse_Program(){
    if (!parse_DeclarationList()){
         return false;
    }
    return true;
}

private boolean parse_DeclarationList() {
    if (!parse_Declaration()){
        return false;
    }
    if(!parse_DeclarationListPrime()){
          return false;
    }
    return true;
}

private boolean parse_DeclarationListPrime() {
        if (token.getContents().equals("int") || token.getContents().equals("void") || token.getContents().equals("float")) {
            if (!parse_Declaration()) {
                return false;
            }else return true;
        }else if (token.getContents().equals("$")){
            return true;
        }

    return false;
}


private boolean parse_Declaration() {
    if (!parse_TypeSpecifier()){
        return false;
    }
    if (token.getType().equals("ID")){
        Accept();
    }else return false;

    if (!parse_DDD()){
        return false;
    }
    return true;
}

private boolean parse_DDD() {
    if (token.getContents().equals("(")){
        Accept();
        if(!parse_params()){
            return false;
        }
        if (token.getContents().equals(")")){
            Accept();
            if (!parse_compoundStmt()){
                return false;
            }else return true;
        }
    }else if (token.getContents().equals(";") || token.getContents().equals("[")){
        if (!parse_varDeclarationPrime()){
            return false;
        }else return true;
    }
    return false;
}

private boolean parse_compoundStmt() {
    if (token.getContents().equals("{")){
        Accept();
        if (!parse_localDeclarations()){
            return false;
        }
        if (token.getContents().equals("}")){
            Accept();
            return true;
        }
    }
    return false;
}

private boolean parse_localDeclarations() {
    if (!parse_localDeclarationsPrime()){
        return false;
    }else return true;
}

private boolean parse_localDeclarationsPrime() {
    if (!parse_varDeclaration()){
        return false;
    }
    return true;
}

private boolean parse_params() {
   if (token.getContents().equals("int") || token.getContents().equals("void") || token.getContents().equals("float")) {
        if (getNextToken().getContents().equals(")") && token.getContents().equals("void")) {
            Accept();
            return true;
        } else {
            if (!parse_paramList()) {
                return false;
            } else return true;
        }
    }
    return false;
}

private Tokens getNextToken() {
    Tokens nextToken = Main.TokenList.get(n+1);
    return nextToken;
}

private boolean parse_paramList() {
    if (!parse_param()){
        return false;
    }
    if (!parse_paramListPrime()){
        return false;
    }
    return true;
}

private boolean parse_paramListPrime() {
    if (token.getContents().equals(",")){
        Accept();
        if (!parse_param()){
            return false;
        }
        if (!parse_paramListPrime()){
            return false;
        }
        return true;
    }else if (token.getContents().equals(")")){
        return true;
    }
    return false;
}


private boolean parse_param() {
    if (token.getContents().equals("int") || token.getContents().equals("void") || token.getContents().equals("float")){
        Accept();
        if (token.getType().equals("ID")){
            Accept();
            if (!parse_paramPrime()){
                return false;
            }else return true;
        }
    }
    return false;
}

private boolean parse_paramPrime() {
    if (token.getContents().equals("[")){
        Accept();
        if (token.getContents().equals("]")){
            Accept();
            return true;
        }
    }else if (token.getContents().equals(")")){
        return true;
    }
    return false;
}

private boolean parse_varDeclaration() {
    if (!parse_TypeSpecifier()){
        return false;
    }
    if (token.getType().equals("ID")){
        Accept();
    }else
        return false;
    if (!parse_varDeclarationPrime()){
        return false;
    }
    return true;
}

private boolean parse_varDeclarationPrime() {
    if (token.getContents().equals(";")){
        Accept();
        return true;
    }else if (token.getContents().equals("[")){
        Accept();
        if (token.getType().equals("NUM")){
            Accept();
            if (token.getContents().equals("]")){
                Accept();
                if (token.getContents().equals(";")){
                    Accept();
                    return true;
                }
            }
        }
    }
    return false;
}

private void Accept() {
    try {
        if ((n + 1) <= Main.TokenList.size() - 1) {
            token = Main.TokenList.get(++n);
        } else {
            token.setContents("$");
        }
    }catch (Exception e){

    }
}

private boolean parse_TypeSpecifier() {
    if (token.getContents().equals("int") || token.getContents().equals("float") || token.getContents().equals("void")){
        Accept();
        return true;
    }
    return false;
}

这来自教科书:photo from textbook

1 个答案:

答案 0 :(得分:3)

自上而下的解析需要某种解析器堆栈。递归下降解析的重点是使用调用堆栈作为解析器堆栈。因此,您应该考虑教科书中的算法是递归下降的替代方法。

递归下降是一种流行的解析解决方案,但是在诸如C(或C ++)之类的语言中,它无法检测堆栈溢出(或无法可靠地检测到它),因此可能会出现问题。在这种情况下,您可能想将专用的解析器堆栈用于生产解析器,尤其是在以下情况下:

  • 您在多线程应用程序中运行解析器(因此堆栈很小);

  • 无论您要解析什么,都应该具有深层嵌套(可能是树状数据结构);

  • 您正在解析未验证的输入,并且担心攻击者提供了过多的嵌套输入;

  • 您还没有进行足够的工作来最小化堆栈帧的大小,这也许是因为您对动态内存分配过敏。

通常,您应该避免递归下降,并在预期的最大调用堆栈深度可能超过可用堆栈大小的任何情况下使用显式堆栈。

或者,您可以使用解析器生成器来生成具有受控堆栈大小的解析器。