基于llvm自制编译器(2):解析器、抽象语法树

本文基于词法分析器为Kaleidoscope构建解析器,用于定义和构造抽象语法树(AST)。解析器采用递归下降分析法和算符优先分析法,介绍了表达式、函数等相关解析方法,还实现了驱动器对代码进行解析,最后可验证代码语法语义错误,且代码有扩展空间。

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


1.概述

提示:这里可以添加本文要记录的大概内容:

本章,我们将基于词法分析器,为Kaleidoscope构建一个完整的解析器(Parser)。通过解析器,我们可以定义并构造抽象语法树(Abstract Syntax Tree,AST)。
我们构造的解析器使用两种方法进行语法分析:

  • 递归下降分析法(Recursive Descent Parsing):用于基本表达式的解析。
  • 算符优先分析法(Operator-Precedence Parsing):用于二元表达式的解析。

在实现解析器之前,我们先介绍一下解析器的输出——抽象语法树。

2.抽象语法树

抽象语法树(AST)为编译器后续的哥哥阶段提供了一种异域解析的表示形式,比如:代码生成。通常,我们希望编程语言中的每一种结构都有一个对应的表示对象。为了实现这种映射关系,我们使用AST对语言进行分析建模。
在Kaleidoscope的AST中,我们设计了三种结构,分别是:

  • 表达式
  • 原型
  • 函数

2.1表达式

如下所示,ExprAST是AST中表达式的基类定义,其中包含了多种子类定义,分别用于对应不同的具体表达式。由于Kaleidoscope只有一种数据类型——双精度浮点类型,因此我们没必要存储类型信息。当然,现实的编程语言通常都包含多种类型,这种情况下ExprAST会包含一个用于存储类型信息的字段。

/// ExprAST - Base class for all expression nodes.
class ExprAST {
   
   
public:
    virtual ~ExprAST() = default;
};

如下所示为ExprAST的各种子类定义,分别是:

  • NumberExprAST:用于表示数值表达式,其捕获字面量的数值保存于Val中。
  • VariableExprAST:用于表示变量表达式,其捕获变量名保存于Name中。
  • BinaryExprAST:用于表示二元表达式,其使用Op保存操作符,如:+。使用LHSRHS 分别保存坐子表达式和右子表达式。
  • CallExprAST:用于表示函数调用表达式,其使用Callee保存函数名。使用Args 数组变量保存函数的各个参数。
    在这里插入图片描述
/// NumberExprAST - Expression class for numeric literals like "1.0".
class NumberExprAST : public ExprAST {
   
   
    double Val;

public:
    NumberExprAST(double Val) : Val(Val) {
   
   }
};

/// VariableExprAST - Expression class for referencing a variable, like "a".
class VariableExprAST : public ExprAST {
   
   
    std::string Name;

public:
    VariableExprAST(const std::string &Name) : Name(Name) {
   
   }
};

/// BinaryExprAST - Expression class for a binary operator.
class BinaryExprAST : public ExprAST {
   
   
    char Op;
    std::unique_ptr<ExprAST> LHS, RHS;

public:
    BinaryExprAST(char op, std::unique_ptr<ExprAST> LHS, std::unique_ptr<ExprAST> RHS) : Op(op), LHS(std::move(LHS)), RHS(std::move(RHS)) {
   
   }
};

/// CallExprAST - Expression class for function calls.
class CallExprAST : public ExprAST {
   
   
    std::string Callee;
    std::vector<std::unique_ptr<ExprAST>> Args;

public:
    CallExprAST(const std::string &Callee, std::vector<std::unique_ptr<ExprAST>> Args) : Callee(Callee), Args(std::move(Args)) {
   
   }
};

由于初步的Kaleidoscope仅仅包含基本功能,所以上述为全部的AST表达式节点定义。由于不包含条件控制流,因此这并不是图灵完整的;对此后续会再做进一步优化。

2.2原型

在这里插入图片描述
如下所示,PrototypeAST为AST中原型(Prototype)的定义。原型用于表示一个函数的原型,用于捕获函数的名称、各个函数的参数等。

class PrototypeAST{
   
   
	std::string Name;
	std::vector<std::string> Args;

public:
	PrototypeAST(const std::string &name, std::vector<std::string> Args):Name(name), Args(std::move(Args)){
   
   }
	
	const std::string &getName() const{
   
   return name;}
};

2.3函数

在这里插入图片描述
如下所示,FunctionAST为AST中的函数定义。函数由函数原型和函数组成,其分别使用ProtoBody进行存储。其中函数体是一个AST表达式结构。

class FunctionAST{
   
   
	std::unique_ptr<PrototypeAST> Proto;
	std::unique_ptr<ExprAST> Body;
public:
	FunctionAST(std::unique_ptr<PrototypeAST> Proto, std::unique_ptr<ExprAST> Body): Proto(std::move(Proto)), Body(std
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值