语法分析分析器的实现

本文详细介绍了编译器构造中的语法分析过程,包括抽象语法树(AST)的继承结构,如何通过递归方法构建AST,处理左递归,以及表达式的优先级控制。此外,还展示了如何实现表达式解析器,包括词法分析、语句块和语句的解析,并提供了具体代码实现。通过实例解析1+2+3+4的表达式,演示了整个语法分析器的工作流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

语法分析分析器的实现

  • 抽象语法树的继承关系

image.png

ASTNode:抽象语法树base、Factor:因子*—*所谓因子就是操作符两边可以计算的东西,变量或者数字都行、Expr:表达式

stmt:语句、Block:语句块、IfStmt:if语句、AssignStmt:赋值语句、DeclareStmt:声明语句、ForStmt:for循环语句、FunctionDeclareStmt:声明函数语句

  • 最简语法分析

    • 语法分析器(parser):根据语法规则,将符合(词法单元,lexeme,token),转换成抽象语法树
    • 类比:中文分析句子过程
    • 和自然语言不同,编译器只能识别[上下文无关文法]
    • 一个文法是上下文无关,也就是说,不需要理解这个语言,给定任意这个语言的句子,可以得到一个合理的抽象语法树
    • 语法规则
      • 通常用产生式描述语法规则

image.png

上述产生式可以生成1+1+1或1+1+1+1的句子

      • Expr是非终结符,1是终结符,终结符对应词法单元
    • 递归法求抽象1语法树
      • Expr -> Expr + 1|1可以拆分为两步
        • 非终结符(递归函数):parseExpr(生成一个非叶子节点)
        • 终结符:parseNumber(生成一个叶子节点)
      • 遇到左递归该如何处理
        • parseExpr -->parseExpr -->parseExpr…
      • 消除左递归 Expr -> Expr + 1|1变为Expr -> 1 + Expr | 1
      • 例如:解析1+1+1+1的过程

image.png image.png

    • 左结合和右结合
      • 同样是1+1+1有两颗不同的抽象语法树
      • 在这里插入图片描述
    • 实现1+2+3+4的Parser
      • ParseException
      • 封装PeekTokenIterator(继承于PeekIterator)
      • 实现1+2+3+4抽象语法树的解析
  • 左递归的处理

    • 例如A ->Aa|B的产生式,有没有通用方法转为非左递归形式?
      • 上述产生式只能以B开头
      • 可以产生B,Ba,Baa,…的语言
      • 因为存在左递归,因为无法使用自顶向下递归法
    • 结论:可以使用两个等效的产生式替代:
      • A ->BA`
      • A->aA| &(空 )
  • 一般情况的左递归处理

    • 例如A -> Aa|Ab|Ay|v的产生式,如何处理
      • 上述产生式只能产生v开头的句子
      • 可以产生如v[aby]*的句子
      • 存在左递归,无法使用递归向下分析法
    • 结论,可以使用下列产生式替代
      • A ->vA`
      • A-> aA|bA|yA|&
  • 表达式优先级控制

    image.png

    • 如何避免左递归

    image.png

推导出

image.png

    • 表达式优先级表

image.png

    • 表达式优先级判断

image.png

    • 递推和去左递归

在这里插入图片描述

  • 表达式解析实战

    • 要点
      • 采用递归向下方法,每个产生式的非终结符对应一个函数
        • E(),E_(),U(),F()
      • 产生式的关系对应一个高阶函数
        • 合并关系,如:E() E_() ->combine(() -> E(),() -> E_())
        • 竞争关系,如:E | F -> race(() ->E(),() -> F())
    • 优先级表
    • 按照优先级解析表达式
  • 表达式树的验证

    • 后序表达式
      • 我们通常用的表达式是表达式数的中序遍历结果
      • 后序表达式是表达式树的后序遍历结果

image.png

    • 根据后序表达式验证正确性
  • 语法分析器整体程序结构

    • 块和语句
      • 定义语句块和语句

Program ->Stmts -> Stmt Stmts | $

Stmt ->IfStmt | WhileStmt | ForStmt | Function…|Block

Block -> { Stmts }

      • 整体结构

image.png

      • 变量定义

DeclateStmt -> var Variable = Expr

image.png

      • 变量赋值

AssignStmt -> Variable = Expr

image.png

      • 提取公共前缀

简化下列if语句

image.png

简化后

IfStmt -> If(Expr)Block Tail

Tail -> else { Block } | else IfStmt | $

image.png

      • Function定义

    Function -> func(Args) Type Block

函数(参数) 返回类型 函数体

Args -> Type Variable,Args | Type Variable | $

ReturnType -> Type | $

Type:int | string | void | bool | string

  • 整体词法分析实现

    • 定义和赋值

表达式优先级表实现:

/**
 * @author :LY
 * @date :Created in 2021/4/22 16:41
 * @modified By:
 */
public class PriorityTable {
    private List<List<String>> table = new ArrayList<>();
    public PriorityTable(){
        table.add(Arrays.asList(new String[]{"&","|","^"}));
        table.add(Arrays.asList(new String[]{"==","!=",">","<",">=","<="}));
        table.add(Arrays.asList(new String[]{"+","-"}));
        table.add(Arrays.asList(new String[]{"*","/"}));
        table.add(Arrays.asList(new String[]{"<<",">>"}));
    }
    public int size(){
        return table.size();
    }
    public List<String> get(int level){
        return table.get(level);
    }
}

抽象语法树定义:

/**
 *抽象语法树
 * @author :LY
 * @date :Created in 2021/4/10 9:52
 * @modified By:
 */
public abstract class ASTNode {
    /* 树 */
    protected ArrayList<ASTNode> children = new ArrayList<>();
    protected ASTNode parent;
    /* 关键信息 */
    protected Token lexeme; // 词法单元
    protected String label; // 备注(标签)
    protected ASTNodeTypes type; // 类型
    private HashMap<String, Object> _props = new HashMap<>();
    public ASTNode() {
    }
    public ASTNode(ASTNodeTypes _type, String _label) {
        this.type = _type;
        this.label = _label;
    }
    public ASTNode getChild(int index) {
        if(index >= this.children.size()) {
            return null;
        }
        return this.children.get(index);
    }
    public void addChild(ASTNode node) {
        node.parent = this;
        children.add(node);
    }
    public Token getLexeme(){
        return lexeme;
    }
    public List<ASTNode> getChildren(){
        return children;
    }
    public void setLexeme(Token token) {
        this.lexeme = token;
    }
    public void setLabel(String s){
        this.label = s;
    }
    public ASTNodeTypes getType(){
        return this.type;
    }
    public void setType(ASTNodeTypes type) {
        this.type = type;
    }
    public void print(int indent) {
        if(indent == 0) {
            System.out.println("print:" + this);
        }
        System.out.println(StringUtils.leftPad(" ", indent *2) + label);
        for(ASTNode child : children) {
            child.print(indent + 1);
        }
    }
    public String getLabel() {
        return this.label;
    }
    public void replaceChild(int i, ASTNode node) {
        this.children.set(i, node);
    }
    public HashMap<String, Object> props() {
        return this._props;
    }
    public Object getProp(String key) {
        if(!this._props.containsKey(key)) {
            return null;
        }
        return this._props.get(key);
    }
    public void setProp(String key, Object value) {
        this._props.put(key, value);
    }
    public boolean isValueType() {
        return this.type == ASTNodeTypes.VARIABLE || this.type == ASTNodeTypes.SCALAR;
    }
    public void replace(ASTNode node) {
        if(this.parent != null) {
            int idx = this.parent.children.indexOf(this);
            this.parent.children.set(idx, node);
            //this.parent = null;
            //this.children = null;
        }
    }
}

各种类型的枚举定义

/**
 * @author :LY
 * @date :Created in 2021/4/10 17:31
 * @modified By:
 */
public enum  ASTNodeTypes {
    BLOCK,//代码块
    BINARY_EXPR,//二项表达式 1+1
    UNARY_EXPR,//一元表达式 ++i
    VARIABLE,//变量
    SCALAR,//值类型  1.0 true
    IF_STMT,//if语句
    WHILE_STMT,//while语句
    FOR_STMT,//for语句
    ASSIGN_STMT,//赋值语句
    FUNCTION_DECLARE_STMT,//定义函数的语句
    DECLARE_STMT ,//声明语句
    CALL_EXPR,
    RETURN_STMT
}
    • Program

解析入口类

/**
 * 程序
 * @author :LY
 * @date :Created in 2021/4/29 17:57
 * @modified By:
 */
public class Program extends Block {
    public Program() {
        super();
    }
    public static ASTNode parse( PeekTokenIterator it) throws ParseException {
        Program block = new Program();
        ASTNode stmt = null;
        //解析stmt的语句
        while ((stmt = Stmt.parseStmt(it)) != null){
            //解析{}中的语句
            block.addChild(stmt);
        }
        return block;
    }
}
    • Block

代码块解析类

/**
 * 代码块
 * @author :LY
 * @date :Created in 2021/4/10 17:41
 * @modified By:
 */
public  class Block extends Stmt {
    public Block() {
        super(ASTNodeTypes.BLOCK, "block");
    }
    public static ASTNode parse(PeekTokenIterator it) throws ParseException {
        it.nextMatch("{");
        Block block = new Block();
        ASTNode stmt = null;
        //解析stmt的语句
        while ((stmt = Stmt.parseStmt(it)) != null){
            //解析{}中的语句
            block.addChild(stmt);
        }
        it.nextMatch("}");
        return block;
    }
}
    • Stmt/IfStmt/FunctionStmt

其他都与上面类似,stmt语句解析:

/**
 * 语句
 * @author :LY
 * @date :Created in 2021/4/10 17:39
 * @modified By:
 */
public abstract class Stmt extends ASTNode {
    public Stmt( ASTNodeTypes _type, String _label) {
        super( _type, _label);
    }

    /**
     * 用来解析语句
     * @param it
     * @return
     * @throws ParseException
     */
    public static ASTNode parseStmt(PeekTokenIterator it) throws ParseException {
        if(!it.hasNext()) {
            return null;
        }
        //向下看两个元素
        Token token = it.next();
        Token lookahead = it.peek();
        it.putBack();
        //如果前一个是变量或者等于符号
        if (token.isVariable() &&  lookahead != null && lookahead.getValue().equals("=")){
            //产生一个赋值语句
            return AssignStmt.parse(it);
        }else if (token.getValue().equals("var")){
            //如果是var  那么产生一个声明语句
            return DeclareStmt.parse( it);
        }else if(token.getValue().equals("func")) {
            return FunctionDeclareStmt.parse( it);
        } else if(token.getValue().equals("return")) {
            //ReturnStmt.parse(it);
            return ReturnStmt.parse(it);
        } else if(token.getValue().equals("if")) {
            return IfStmt.parse(it);
        } else if(token.getValue().equals("{")) {
            return Block.parse(it);
        }else {
            return Expr.parse(it);
        }
    }
}

消除左递归核心代码逻辑

/**
 * 表达式消除左递归核心逻辑
 * @author :LY
 * @date :Created in 2021/4/10 19:13
 * @modified By:
 */
public class Expr extends ASTNode{

    private static PriorityTable  table = new PriorityTable();
    public Expr(){
        super();
    }

    public Expr( ASTNodeTypes type, Token lexeme) {
        super();
        this.type = type;
        this.label = lexeme.getValue();
        this.lexeme = lexeme;
    }

    //left:E(k) -> E(k) op(k) E(k+1) | E(k+1)
    //right:
    //    E(k) -> E(k+1) E_(K)
    //          var e = new Expr()  e.left=E(k+1); e.op = op(k);  e.right=E(k+1) E_(k)
    //    E_(k) -> op(k) E(k+1) E_(k) | &
    //最高优先级处理
    // E(t) -> F E_(k) | U E_(k)  (U代表括号之类的一元表达式)
    // E_(t) ->op(t) E(t) E_(k)| &
    public static ASTNode E( int k, PeekTokenIterator it) throws ParseException {

        if (k < table.size()-1){
            //具有延迟加载,一个函数不产生值,另一个不执行
            return combine(it,() ->E(k+1,it),() -> E_(k,it));
        }else {
            //最高优先级处理
            return race(it,
                    () -> combine(it, () ->F(it),() -> E_(k,it)),
                    () -> combine(it,() ->U(it), () -> E_(k,it)));
        }

    }

    public static ASTNode E_(int k, PeekTokenIterator it) throws ParseException {
        Token token = it.peek();
        String value = token.getValue();
        if (table.get(k).indexOf(value) != -1){
            Expr expr = new Expr(ASTNodeTypes.BINARY_EXPR,it.nextMatch(value));
            expr.addChild(
                    combine(it,
                            ()-> E(k+1, it),
                            ()->E_( k, it)));
            return expr;
        }
        return null;
    }
    private static ASTNode U(PeekTokenIterator it) throws ParseException {
        Token token = it.peek();
        String value = token.getValue();
        ASTNode expr = null;
        if (value.equals("(")){
            it.nextMatch("(");
            expr = E(0,it);
            it.nextMatch(")");
            return expr;
        }else if (value.equals("++")||value.equals("--") || value.equals("!")){
            Token t = it.peek();
            it.nextMatch(value);
            Expr unaryExpr = new Expr(ASTNodeTypes.UNARY_EXPR, t);
            unaryExpr.addChild(E(0,it));
            return unaryExpr;
        }
        return null;
    }
    private static ASTNode F(PeekTokenIterator it) throws ParseException {
//        Token token = it.peek();
//        if (token.isVariable()){
//            return new  Variable(token);
//        }else{
//            return new Scalar(token);
//        }
        //拿到参数因子
        ASTNode factor = Factor.parse(it);
        if(factor == null) {
            return null;
        }
        //确认是否为参数
        if(it.hasNext() && it.peek().getValue().equals("(")) {
            return CallExpr.parse(factor,it);
        }
        return factor;
    }

    /**
     * 合并函数  将两个表达式合为一体
     * @param it 流
     * @param aFunc 合并节点a
     * @param bFunc 合并节点b
     * @return
     * @throws ParseException
     */
    public static ASTNode combine(PeekTokenIterator it,ExprHOF aFunc,ExprHOF bFunc) throws ParseException {
        ASTNode a = aFunc.hoc();
        if (a == null){
            return it.hasNext()?bFunc.hoc():null;
        }
        ASTNode b = it.hasNext()?bFunc.hoc():null;
        if (b == null){
            return a;
        }

        Expr expr = new Expr(ASTNodeTypes.BINARY_EXPR,b.lexeme);
        expr.addChild(a);
        expr.addChild(b.getChild(0));
        return expr;
    }

    /**
     * 竞争函数  两个表达式只会存在一个
     * @param it
     * @param aFunc
     * @param bFunc
     * @return
     * @throws ParseException
     */
    private static ASTNode race(PeekTokenIterator it,ExprHOF aFunc,ExprHOF bFunc) throws ParseException {
        if (!it.hasNext()){
            return null;
        }
        ASTNode a = aFunc.hoc();
        if (a != null){
            return a;
        }
        return bFunc.hoc();
    }

    public static ASTNode parse(PeekTokenIterator peekTokenIterator) throws ParseException {
        return E(0,peekTokenIterator);
    }

}

基本代码编写完成,测试代码

    • 测试

主要测试三段代码

第一段:

   PeekTokenIterator it = createTokenIt("if(a){\n" +
                "a = 1\n" +
                "} else{\n" +
                "a = 2\n" +
                "a = a * 3" +
                "}");

        IfStmt stmt = (IfStmt)IfStmt.parse( it);
//        parse.print(0);
        Variable expr = (Variable)stmt.getChild(0);
        Block block = (Block)stmt.getChild(1);
        AssignStmt assignStmt =(AssignStmt) block.getChild(0);
        Block elseBlock = (Block)stmt.getChild(2);
        AssignStmt assignStmt2 = (AssignStmt)elseBlock.getChild(0);
        assertEquals("a",expr.getLexeme().getValue());
        assertEquals("=",assignStmt.getLexeme().getValue());
        assertEquals("=",assignStmt2.getLexeme().getValue());
        assertEquals(2,elseBlock.getChildren().size());

测试结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值