0

0

C++如何实现一个简单的AST解析器_C++编译原理与抽象语法树解析器实现

下次还敢

下次还敢

发布时间:2025-11-18 12:08:12

|

241人浏览过

|

来源于php中文网

原创

首先实现词法分析器将源码拆分为Token,接着设计AST节点表示数字与二元操作,再通过递归下降解析器按优先级构建表达式树,最终组合Lexer与Parser完成对“2 + 3 * 4”等算术表达式的AST解析。

c++如何实现一个简单的ast解析器_c++编译原理与抽象语法树解析器实现

实现一个简单的AST(抽象语法树)解析器,需要从词法分析开始,逐步构建语法结构。C++中可以通过手动编写递归下降解析器来完成这一过程。下面是一个简化但完整的流程,帮助你理解编译原理中的核心环节:词法分析、语法分析和AST构建。

词法分析器(Lexer)

词法分析器负责将源代码拆分为一个个有意义的“记号”(Token)。例如,表达式 2 + 3 * 4 可以被分解为数字、操作符等Token。

定义Token类型:

enum TokenType {
    TOKEN_NUMBER,
    TOKEN_PLUS,
    TOKEN_MINUS,
    TOKEN_STAR,
    TOKEN_SLASH,
    TOKEN_EOF
};

每个Token包含类型和可能的数值(如数字的值):

struct Token {
    TokenType type;
    double value; // 仅用于数字
};

Lexer类读取输入字符串,逐字符扫描并生成Token序列:

立即学习C++免费学习笔记(深入)”;

class Lexer {
public:
    Lexer(const std::string& src) : source(src), pos(0) {}
Token nextToken() {
    if (pos >= source.length()) return {TOKEN_EOF, 0};

    char c = source[pos];

    if (isdigit(c)) {
        std::string num;
        while (pos < source.length() && isdigit(source[pos])) {
            num += source[pos++];
        }
        return {TOKEN_NUMBER, std::stod(num)};
    }

    if (c == '+') { pos++; return {TOKEN_PLUS, 0}; }
    if (c == '-') { pos++; return {TOKEN_MINUS, 0}; }
    if (c == '*') { pos++; return {TOKEN_STAR, 0}; }
    if (c == '/') { pos++; return {TOKEN_SLASH, 0}; }

    pos++; // 跳过未知字符
    return nextToken();
}

private: std::string source; size_t pos; };

AST节点设计

抽象语法树由不同类型的节点构成。常见的有数字节点和二元操作节点。

struct ASTNode {
    virtual ~ASTNode() = default;
};

数字节点存储常量值:

struct NumberNode : ASTNode {
    double value;
    NumberNode(double v) : value(v) {}
};

二元操作节点保存左右子节点和操作符:

struct BinaryOpNode : ASTNode {
    std::unique_ptr left;
    std::unique_ptr right;
    TokenType op;
BinaryOpNode(TokenType o, std::unique_ptr l, std::unique_ptr r)
    : op(o), left(std::move(l)), right(std::move(r)) {}

};

LALALAND
LALALAND

AI驱动的时尚服装设计平台

下载

递归下降解析器(Parser)

解析器根据语法规则从Token流构建AST。我们实现最简单的算术表达式解析,支持加减乘除,并遵循优先级。

语法大致如下:

  • expr → term (('+' | '-') term)*
  • term → factor (('*' | '/') factor)*
  • factor → NUMBER

解析器代码:

class Parser {
public:
    Parser(Lexer l) : lexer(std::move(l)) {
        currentToken = lexer.nextToken();
    }
std::unique_ptr parse() {
    return parseExpr();
}

private: Lexer lexer; Token currentToken;

void consume(TokenType expected) {
    if (currentToken.type == expected) {
        currentToken = lexer.nextToken();
    } else {
        throw std::runtime_error("Unexpected token");
    }
}

std::unique_ptr parseExpr() {
    auto node = parseTerm();
    while (currentToken.type == TOKEN_PLUS || currentToken.type == TOKEN_MINUS) {
        TokenType op = currentToken.type;
        consume(op);
        auto rhs = parseTerm();
        node = std::make_unique(op, std::move(node), std::move(rhs));
    }
    return node;
}

std::unique_ptr parseTerm() {
    auto node = parseFactor();
    while (currentToken.type == TOKEN_STAR || currentToken.type == TOKEN_SLASH) {
        TokenType op = currentToken.type;
        consume(op);
        auto rhs = parseFactor();
        node = std::make_unique(op, std::move(node), std::move(rhs));
    }
    return node;
}

std::unique_ptr parseFactor() {
    if (currentToken.type == TOKEN_NUMBER) {
        auto node = std::make_unique(currentToken.value);
        consume(TOKEN_NUMBER);
        return node;
    }
    throw std::runtime_error("Expected number");
}

};

测试与使用

将各部分组合起来,测试一个简单表达式:

int main() {
    std::string source = "2 + 3 * 4";
    Lexer lexer(source);
    Parser parser(std::move(lexer));
try {
    auto ast = parser.parse();
    // 这里可以添加遍历AST并求值的逻辑
    std::cout << "AST parsed successfully.\n";
} catch (const std::exception& e) {
    std::cerr << "Parse error: " << e.what() << '\n';
}

return 0;

}

你可以进一步扩展这个解析器,加入变量、函数调用、控制流等结构。关键在于分层处理:先分词,再按优先级解析语法,最后构造树形结构。

基本上就这些。不复杂但容易忽略细节,比如Token消费时机和内存管理(这里用了unique_ptr自动释放)。理解这个流程后,就能在此基础上实现更完整的语言前端

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

315

2023.08.02

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1463

2023.10.24

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

6074

2023.09.14

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

795

2023.09.14

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

1056

2023.12.21

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

1199

2024.03.01

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

253

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

206

2023.09.04

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

25

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 6.4万人学习

C 教程
C 教程

共75课时 | 4万人学习

C++教程
C++教程

共115课时 | 11.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号