讲师中心 微信公众号
AI工具推荐 视频效率加速

C++如何实现递归下降解析器?(手写语法分析)

夏枫君_1817

夏枫君_1817

发布时间:2026-02-22 17:25:03

|

305人浏览过

|

来源于php中文网

原创

递归下降解析器是一组相互调用的C++函数,每个函数对应一条语法规则,共享一个封装token流的类,通过前瞻一个token并手动推进位置来实现解析。

c++如何实现递归下降解析器?(手写语法分析)

递归下降解析器的核心结构长什么样

递归下降不是某种库或框架,它就是一组相互调用的 C++ 函数,每个函数对应一条语法规则。比如 expr() 解析表达式,term() 解析项,factor() 解析因子——这些函数名直接映射 BNF 中的非终结符。

关键在于:每个函数只向前看一个 token(即“前瞻一个”),靠这个 token 决定走哪条分支。这意味着你必须手动维护一个 current_token,并在每次匹配成功后调用 next_token() 推进。

常见错误现象是函数没推进 token 就返回,导致无限循环或跳过输入;或者推进了但没检查是否到结尾,引发越界访问。

  • 必须用一个类封装 token 流,包含 m_tokens 和 m_pos,所有解析函数共享同一实例
  • 每个函数开头先检查 current_token.type == expected_type,不匹配就报错或回退(如果支持回溯)
  • 匹配成功后立刻调用 consume()(即 m_pos++),不能靠调用方负责
Token current_token() const { 
  return m_pos < m_tokens.size() ? m_tokens[m_pos] : Token{EOF}; 
}
void consume() { ++m_pos; }

如何处理左递归导致的无限调用

C++ 里直接写 expr → expr '+' term 这种左递归规则,expr() 会无终止地调用自己,栈溢出是分分钟的事。

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

这不是语法设计失误,而是递归下降的硬约束:它天然不支持直接左递归。必须重写文法,把左递归转成右递归 + 循环。

典型做法是把加减运算提出来,用迭代方式处理:

  • 原规则 expr → term | expr '+' term | expr '-' term → 改成 expr → term { ('+' | '-') term }
  • 对应代码中,expr() 先调一次 term() 得到初始值,再用 while 循环反复检查 current_token.type == PLUS || MINUS
  • 每次匹配操作符后 consume,再调 term(),然后做实际运算

这样既避免栈爆炸,又保持了左结合性。别试图在 C++ 里模拟回溯或用 std::function 缓存状态来绕过——性能差、逻辑乱、调试难。

C++14
C++14

C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。

下载

什么时候该用 std::variant 而不是继承+虚函数

如果你的 AST 节点类型不多(比如 BinaryOp、Number、Identifier),用 std::variant 更轻量、更安全。

继承方案看似“面向对象”,但容易踩坑:忘了定义虚析构函数、误用裸指针管理生命周期、RTTI 开销不可控。而 std::variant 强制你在访问前做模式匹配,编译期就能拦住未覆盖的 case。

使用场景很明确:AST 构建完成后要遍历执行或打印,且节点种类稳定(少于 10 种)。这时 std::visit 配合 lambda 是最直白的写法。

  • 不要用 dynamic_cast 做运行时类型判断,那是给多态接口用的,不是给 AST 的
  • 如果节点需要携带位置信息(line, col),直接塞进每个 struct 里,别搞“基类带位置字段”那一套
  • std::variant 的构造开销几乎为零,但注意别在循环里反复拷贝大 variant
using Expr = std::variant<Number, BinaryOp, Identifier>;
Expr parse_expr() { /* ... */ }

错误恢复怎么做才不至于一崩到底

递归下降默认是“悲观式”解析:一个 token 错,后面全乱。但用户写代码时打错一个括号,你不该直接退出,而应尝试跳过坏 token、同步到下一个合理起点(比如 ; 或 })。

关键是定义“同步集”(synchronizing set):对每个函数,明确哪些 token 可以作为恢复锚点。比如 stmt() 的同步集通常是 SEMI、RBRACE、IF、WHILE。

  • 不要一遇到错误就 throw —— 异常打断控制流,让恢复逻辑难以插入
  • 在每个顶层函数(如 parse_function())入口加保护:若 current_token 是明显非法值(如 INVALID),先调用 skip_to_sync({SEMI, RBRACE})
  • skip_to_sync 就是 while 循环:只要 current_token.type 不在集合里,就 consume()

性能影响很小,但用户体验差别巨大。没人想每次少打个逗号就得重输整段。

真正麻烦的是错误嵌套:比如在 expr() 里出错,跳出去后又在 stmt() 里撞上另一个错。这时候同步集得有层级感——外层比内层更宽松。这点容易被忽略,结果是报错位置飘忽、信息错位。

热门AI工具

更多
Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

讯飞绘文

讯飞绘文是一款由科大讯飞推出的一站式 AIGC 内容运营平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

相关专题

更多
while的用法
while的用法

while的用法是“while 条件: 代码块”,条件是一个表达式,当条件为真时,执行代码块,然后再次判断条件是否为真,如果为真则继续执行代码块,直到条件为假为止。本专题为大家提供while相关的文章、下载、课程内容,供大家免费下载体验。

354

2023.09.25

go语言 面向对象
go语言 面向对象

本专题整合了go语言面向对象相关内容,阅读专题下面的文章了解更多详细内容。

7175

2025.09.05

java面向对象
java面向对象

本专题整合了java面向对象相关内容,阅读专题下面的文章了解更多详细内容。

362

2025.11.27

C++ 面向对象编程与设计模式实践
C++ 面向对象编程与设计模式实践

本专题整合了 C++ 面向对象编程的核心机制,涵盖类的定义与访问控制、构造函数与析构函数、拷贝语义与移动语义、继承与虚函数多态、抽象类与接口、运算符重载、友元函数等关键知识点,同时结合单例模式、工厂模式、观察者模式、策略模式等常用设计模式的 C++ 实现,帮助开发者写出结构清晰、易于维护的面向对象代码。

364

2026.04.09

Java 面向对象与核心编程机制
Java 面向对象与核心编程机制

系统讲解 Java 面向对象编程的核心知识体系,涵盖类的定义与封装、构造方法与 this/super 关键字、继承与方法重写、多态与向上向下转型、抽象类与接口的区别与设计原则、异常处理机制(try-catch-finally / 自定义异常)、泛型的类型参数与通配符、集合框架(List/Set/Map)的使用与遍历方式,帮助开发者全面掌握 Java 程序设计的核心机制与面向对象思维。

243

2026.04.17

java多态详细介绍
java多态详细介绍

本专题整合了java多态相关内容,阅读专题下面的文章了解更多详细内容。

375

2025.11.27

登录token无效
登录token无效

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

14666

2023.09.14

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

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

1725

2023.09.14

Uvicorn 报错与问题解决教程
Uvicorn 报错与问题解决教程

本专题汇总了Uvicorn服务器常见问题与报错解决的教程合集,涵盖启动失败、端口占用、模块导入错误、事件循环冲突及热重载失效等典型故障的排查思路。同时整理了多进程与Worker配置、SSL/HTTPS证书报错、跨域与代理配置等实战解决方案,助你快速定位并解决Uvicorn运行中的各类问题。

0

2026.11.02

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C++ Core Guidelines
C++ Core Guidelines

共0课时 | 0人学习

C++ Reference
C++ Reference

共0课时 | 0人学习

C++ 官方标准说明
C++ 官方标准说明

共0课时 | 0人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn