如何在AST中合理保留注释?Parsec解析器与代码格式化的困惑
处理AST中注释的优化方案
方案一:分离注释与核心AST,用位置关联映射
别把注释硬塞到AST节点的参数里,单独维护一张注释-节点关联表就行:
- 解析时记录每个注释的起止位置(行号、列号),以及它对应的AST节点位置(比如是在for循环关键字前、初始化表达式后,还是条件块末尾这类具体位置)
- 核心AST只保留纯逻辑结构,注释全靠这张表和AST节点绑定
- 做格式化的时候,根据表中的关联信息把注释插回对应位置就行
举个实际例子:解析// 开始循环\nfor (int i=0; /* 循环条件 */ i<10; i++) { ... }时,把// 开始循环标记为ForLoop节点的「前置注释」,把/* 循环条件 */标记为ForLoop节点的「条件区内部注释」,后续格式化时直接按标记位置输出。
方案二:给AST节点加通用注解容器
如果不想完全分离,给每个AST节点加一个通用的annotations字段(比如键值对结构),代替给每个注释位置加单独参数:
- 先定义一套位置枚举,比如
PreKeyword、PostInit、PreCondition、PostUpdate这些,对应for循环里的各个可放注释的位置 - 解析时把对应位置的注释按枚举类型存入节点的
annotations里 - 格式化时,根据枚举值把注释放到正确的位置
这种方式不会让AST节点参数爆炸,所有注释统一存在一个容器里,以后新增注释位置也只需要加枚举值,不用改AST结构。
方案三:用复合节点包裹注释与核心逻辑
把注释和相邻的核心代码节点包装成一个复合节点,比如定义AnnotatedNode类型:
- 包含
coreNode(纯逻辑的AST节点)和comments(该节点周围的注释列表,每个注释带位置标记,比如「前置」「后置」「内部某区域」) - 解析时遇到注释,就把它和前后的核心节点组合成
AnnotatedNode - 格式化时遍历这个复合节点,先输出对应位置的注释,再输出核心逻辑内容
这种方式能保持核心AST的纯净,外层节点专门管注释,逻辑也清晰。
基于Parsec的实现小技巧
在Parsec里可以单独写一个注释解析器,然后在解析各个AST节点时穿插调用:
- 比如解析for循环时,先调用注释解析器收集前置注释,再解析
for关键字,接着收集初始化部分的前后注释,再解析条件表达式,以此类推 - 把收集到的注释按位置分类,再用上面的方案存储,不用硬加到AST节点的参数里
内容的提问来源于stack exchange,提问作者Soeren
相关产品推荐
相关产品推荐

