在建立对递归下降语法分析方法的直观理解后,我们将通过减法表达式计算(即文法6-9)这一实例展开进一步探讨。相较于前文案例,该实例的复杂度有所提升,主要体现在对左递归问题的处理上。在自顶向下的语法分析框架下,必须对左递归进行消除处理,尽管转换后的文法可读性可能降低,但其是保证分析过程终止性的必要条件。

        为保持示例的简明性,本案例暂不涉及语义模型构建及错误处理机制,但会演示如何在语法分析过程中同步完成表达式求值,即实现简单的语法制导翻译。需要说明的是,常规减法表达式通常支持括号运算,但为避免增加复杂度,相关扩展内容将留作读者的实践探索。

        考虑到文法6-9中符号命名的复杂性可能对函数设计产生影响,我们对其进行简化处理,形成如文法6-14所示的等价表示。对于减法表达式这类问题,理想的解决方案是采用完整的语法制导翻译技术,这涉及符号综合属性、继承属性等概念,相关内容将在第7章详细阐述。在当前案例中,我们聚焦于左递归消除方法及其在递归下降分析器中的实现策略,通过简化模型展示核心处理流程。

文法6-14

E -> DIGIT R
R -> '-' DIGIT R | ε
DIGIT -> '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'

        同上一个案例,我们并不会展示词法分析器的代码,您可参考第二七篇文章的案例。不过词法单元的类型出现了些许变化,如代码6-3所示:

代码6-3

enum TokenType {
    DIGIT(""),
    MINUS("-"),
    EOF("<EOF>"),
    UNKNOWN("<unknown>");
}

        笔者对语法分析器的实现代码,尤其是与前一个案例有交集的部分进行了省略,以避免对读者的阅读体验产生影响,余留下的核心片段如代码6-4所示。另外值得注意的是,笔者给出的实现方案不允许表达式出现单数字的情况,比如“1”、“2”等,合法的输入必须至少包含一个减法符号,如“3-2”、“3-2-1”等。

代码6-4

class SubtractionParser {
    ...
    int result;

    void parse() {
        result = digit();
        r();
    }

    void r() {
        if (lookahead.type == TokenType.EOF) {
            return;
        }
        if (lookahead.type == TokenType.MINUS) {
            matchAndMove(TokenType.MINUS);
            int value = digit();
            result -= value;//代码1
            r();
            return;
        }
        throw new ParseException();//代码2
    }

    int digit() {
        Token token = lookahead;
        matchAndMove(TokenType.DIGIT);
        return Integer.valueOf(token.lexeme);
    }

    void matchAndMove(TokenType target) {
        if (this.lookahead.type == target) {
            lookahead = this.lexer.scanNext();
            return;
        }
        throw new ParseException();
    }
}

        可以看到,虽然文法经过了去左递归处理,但并不影响语法分析程序的实现,其执行逻辑仍然与文法是一一对应的。

        方法r()的实现逻辑要相对复杂一点,主要体现在如下两点上:

  1. 语法分析的过程中同步对减法表达式的值进行计算,计算后的结果会被存储到类变量result中,见“代码1”处。
  2. 执行到该方法的时候,向前看符号的类型必须为TokenType.MINUS,也就是减号“-”。否则的话应该让程序报错,见“代码2”处。这样的处理是为了避免输入表达式为单个数字的情况,即未包含减号。

        其它方法的含义与上一个案例基本相同,笔者不再赘述。

上一章  下一章

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐