【问题标题】:How to parse this grammar?如何解析这个语法?
【发布时间】:2019-12-09 08:20:27
【问题描述】:

我想在 java 中为以下语法创建一个递归后代解析器(我已设法创建标记)。这是语法的相关部分:

expression ::= numeric_expression | identifier | "null" 
identifier ::= "a..z,$,_"
numeric_expression ::= ( ( "-" | "++" | "--" ) expression )
      | ( expression ( "++" | "--" ) )
      | ( expression ( "+" | "+=" | "-" | "-=" | "*" | "*=" | "/" | "/=" | "%" | "%=" ) expression )
arglist ::= expression { "," expression } 

我已经编写了解析numeric_expression的代码(假设如果令牌无效,则返回null):

    NumericAST<? extends OpAST> parseNumericExpr() {
        OpAST op;
        if (token.getCodes() == Lexer.CODES.UNARY_OP) { //Check for unary operator like "++" or "--" etc
            op = new UnaryOpAST(token.getValue());

            token = getNextToken();
            AST expr = parseExpr();        // Method that returns expression node.
            if (expr == null) {
                op = null;
                return null;
            } else {
                if (checkSemi()) {
                    System.out.println("UNARY AST CREATED");
                    return new NumericAST<OpAST>(expr, op, false);
                }
                else {
                    return null;
                }
            }
        } else {   // Binary operation like "a+b", where a,b ->expression
            AST expr = parseExpr(); 
            if (expr == null) {
                return null;
            } else {
                token = getNextToken();
                if (token.getCodes() == Lexer.CODES.UNARY_OP) {
                    op = new UnaryOpAST(token.getValue());
                    return new NumericAST<OpAST>(expr, op, true);
                } else if (token.getCodes() == Lexer.CODES.BIN_OP) {
                    op = new BinaryOpAST(token.getValue());
                    token = getNextToken();

                    AST expr2 = parseExpr();
                    if (expr2 == null) {
                        op = null;
                        expr = null;
                        return null;
                    } else {
                        if (checkSemi()) {
                            System.out.println("BINARY AST CREATED");
                            return new NumericAST<OpAST>(expr, op, expr2);
                        }
                        else {
                            return null;
                        }

                    }
                } else {
                    expr = null;
                    return null;
                }
            }
        }
    }

现在,如果我得到像 ++ 这样的一元运算符,我可以直接调用此方法,但我不知道识别其他语法,从相同的产生开始,如 arglist 和 numeric_expression 具有“表达式”作为开始产生。

我的问题是:

如果我得到一个表达式令牌,如何识别是调用parseNumericExpr()还是parseArgList()(上面没有提到的方法)?

【问题讨论】:

  • 您好,澄清一下,这是您的完整语法定义吗?您似乎在代码中使用了UnaryOperatorAST,但一元运算符表达式似乎不是您语法中的构建块。
  • 这道题太笼统了,其实是多题合二为一。请将您的问题集中在 一个 特定问题上,并记住这不是代码审查网站。
  • @JoakimDanielson 我已经澄清了,请检查
  • @PaulBenn,没有提到完整的语法,只是其中的一部分

标签: java parsing grammar


【解决方案1】:

为了编写递归下降解析器,您需要一个适当的自顶向下语法,通常是 LL(1) grammar,尽管使用 EBNF 运算符编写语法很常见,如 Wikipedia's page on @987654322 上的示例语法所示@。

不幸的是,您的语法不是 LL(1),您提出的问题是该事实的结果。 LL(1) 语法具有这样的特性,即解析器始终可以通过仅检查下一个输入标记来确定使用哪个产生式,这对语法施加了一些严格的限制,包括:

  • 同一非终结符的两个产生式不能以相同的符号开头。
  • 产生式不能是左递归的(即右侧的第一个符号是定义的非终结符)。

下面是你的语法的一个小的重新排列,它会起作用:

-- I added number here in order to be explicit.
atom       ::= identifier | number | "null" | "(" expression ")"
-- I added function calls here, but it's arguable that this syntax accepts
-- a lot of invalid expressions
primary    ::= atom { "++" | "--" | "(" [ arglist ] ")" }
factor     ::= [ "-" | "++" | "--" ] primary
term       ::= factor { ( "*" | "/" | "%" ) factor }
value      ::= term { ( "+" | "-" ) term }
-- This adds the ordinary "=" assignment to the list in case it was
-- omitted by accident. Also, see the note below.
expression ::= { value ( "=" | "+#" | "-=" | "*=" | "/=" | "%=" ) } value
arglist    ::= expression { "," expression }

最后一个expression 规则试图捕获赋值运算符的常用语法(它关联到右侧,而不是左侧),但它受到highly related question 的经典问题解决的困扰。我认为我对这个问题没有比三年前写的更好的答案了,所以我希望它仍然有用。

【讨论】:

  • 感谢您的回答,我想我必须先将我的语法转换为 LL。如果可能的话,您能否分享一些资源,我可以从中学习如何正确转换它?
  • @dhs:你可以从我链接的维基百科页面开始。我认为他们有很好的参考。如果您查看我对您的语法摘录所做的更改,您会看到基本方法。
猜你喜欢
  • 2012-08-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多