恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

仓颉编程语言 AST 解析实战:基于 std.ast 的 parseDecl 与 parseProgram 用法详解

  • 首页
  • 资讯中心
  • /
  • 仓颉编程语言 AST 解析实战:基于 std.ast 的 parseDecl 与 parseProgram 用法详解

相关资讯

AnyPS5非官方方案:跨设备访问PS5的串流、文件管理与远程控制技术解析 2026/10/14 7:03:19
OpenCV实战:信用卡数字识别与模板匹配全流程解析 2026/10/14 7:03:19
MySQL离线手机号码归属地数据库:导入、查询与避坑指南 2026/10/14 7:03:19

最新资讯

Python五子棋项目实战:从tkinter界面到AI人机对战算法解析
PS5 DualSense手柄Linux驱动原理与高级特性支持
计算机组成原理期末复习指南:从PPT到Cache与流水线实战
Hyperframes超帧结构解析:视频编码中的高效压缩与弱网传输实践
Hive分隔符原理与实战:避免数据错位的底层解析指南
Vue3商城前端工程化实践:从脚手架到上线的完整链路

今日推荐

IBM Verify Identity Access 修复 22 个漏洞:两个 9.8 严重 RCE 无需认证
小区物业管理系统
小型超市仓库管理系统

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

仓颉编程语言 AST 解析实战:基于 std.ast 的 parseDecl 与 parseProgram 用法详解

发布时间:2026/10/14 7:03:19
仓颉编程语言 AST 解析实战:基于 std.ast 的 parseDecl 与 parseProgram 用法详解 编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/cangjie_runtime点击查看免费下载std.ast是仓颉标准库中面向编译器前端与宏开发的语法解析包它将仓颉源码的词法单元Tokens解析为抽象语法树AST节点对象为宏展开、代码生成和静态分析提供结构化数据。本文以stdlib/doc/libs/std/ast/ast_samples/parse.md为核心骨架完整演示parseDecl、parseProgram两个核心入口的用法与输出并结合仓库源码parse_decl.cj、parse_node.cj、ffi.cj深入讲解整套解析函数家族、Tokens词法单元体系及底层实现原理帮助读者掌握把仓颉源码解析为可编程操作 AST 的完整技术方案。一、std.ast 包与 AST 解析概览1.1 包的功能定位按照 ast 包总览文档 的说明std.ast主要包含两部分能力语法解析器提供cangjieLex、parseDecl、parseExpr、parsePattern、parseProgram、parseType等语法解析函数可将仓颉源码的词法单元Tokens解析为抽象语法树节点对象语法树节点以Node为父类派生出Decl声明、Expr表达式、Pattern模式、TypeNode类型四大体系覆盖类定义、函数定义、变量声明、控制流、字面量、匹配模式等全部仓颉语法结构。平台限制对于 iOS 平台运行的场景本包仅支持在 iOS 12 及以上系统运行见 ast_package_overview.md。1.2 两大核心数据结构Token 与 Tokens在进入解析函数之前需要先理解两个基础类型Token词法单元结构体包含三个公开只读字段见 token.cj 源码kind: TokenKind—— 词法种类如CLASS、IDENTIFIER、INT32、ASSIGN等value: String—— 词法单元对应的源码文本pos: Position—— 位置信息Position包含文件 ID、行号和列号详见 Position。Tokens对Token序列进行封装的类型实现了ToString、IterableToken、ToBytes接口见 tokens.cj支持下标访问、迭代遍历并可通过toBytes()序列化为字节流传给底层解析器。从源码结构看TokenKind枚举token_kind.cj覆盖了仓颉编译器内部全部词法结构包括符号DOT、COMMA、ASSIGN等、关键字CLASS、FUNC、VAR等、基本类型INT8INT64、FLOAT32等以及字面量、换行、结束符等。解析结果dump()输出中的kind字段即来源于此枚举。1.3 解析在宏机制中的角色std.ast解析函数最常见的应用场景是宏展开宏定义以Tokens接收输入通过解析函数将输入源码转化为 AST 节点进行校验、改写后再通过toTokens()转回Tokens输出。需要注意仓颉宏展开后的代码不允许出现包的声明和包导入语句详见 parseProgram 函数文档。二、前置步骤从源码字符串到词法单元 Tokens所有解析函数的输入都是Tokens因此第一步是把源码变成词法单元。std.ast提供两种方式。2.1 cangjieLex对字符串做词法分析cangjieLex(String) 将字符串转换为Tokens类型其单参版本等价于cangjieLex(code, true)import std.ast.* main(): Unit { // 用 cangjieLex 将输入字符串转化为 Tokens let tokens cangjieLex(let x 10) // 输出得到的 Tokens println(tokens.size: ${tokens.size}) println(tokens.toString(): ${tokens.toString()}) }运行结果tokens.size: 4 tokens.toString(): let x 10双参版本 cangjieLex(String, Bool) 的第二个参数truncated控制是否删减解析后Tokens末尾的Token(END)结束符import std.ast.* main(): Unit { // 用 cangjieLex 将输入字符串转化为 Tokens let tokens cangjieLex(let x 10, false) // 输出得到的 Tokens // 末尾相较于传入 true 得到的 Tokens 多了一个 Token(END) println(tokens.size: ${tokens.size}) println(tokens.toString(): ${tokens.toString()}) }运行结果tokens.size: 5 tokens.toString(): let x 10即truncated传false时保留结束符size多出 1 个而toString()输出不受影响。从 ffi.cj 的cangjieLex实现可以看到该函数通过CJ_AST_Lex调用仓颉编译器的词法分析器底层对应 ast_api.cpp 中的LexWithError内部使用Lexer进行切词并对TokenKind.END做删减处理当输入的code无法被正确解析为Tokens时抛出IllegalArgumentException申请内存失败时抛出IllegalMemoryException。2.2 quote源码片段的“准字面量”写法在宏与 ast 示例代码中更常用的是quote(...)表达式它把括号内的仓颉源码片段直接构造为Tokens避免手写字符串转义。例如let input: Tokens quote( class Data { var a: Int32 init(a_: Int32) { a a_ } } )quote本质上是编译期将源码文本词法化为Tokens的语法糖解析示例与宏定义中的Tokens输入几乎都通过它构造。2.3 compareTokens比较两个 Tokens 是否一致compareTokens(Tokens, Tokens) 用于比较两个Tokens内容是否一致只要内容相同忽略换行符、结束符和位置信息即返回trueimport std.ast.* main(): Unit { // 创建 Tokens let tokens0 quote(let x 10) let tokens1 quote(let x 10) let tokens2 quote(let x 20) println(compareTokens(tokens0, tokens1): ${compareTokens(tokens0, tokens1)}) println(compareTokens(tokens0, tokens2): ${compareTokens(tokens0, tokens2)}) }运行结果compareTokens(tokens0, tokens1): true compareTokens(tokens0, tokens2): false三、parseDecl将源码解析为单个声明节点Decl3.1 完整示例parseDecl(Tokens, String) 用于解析一组词法单元获取一个Decl类型的节点。下面有一个类Dataclass Data { var a: Int32 init(a_: Int32) { a a_ } }利用解析函数将上述代码解析为一个Decl对象import std.ast.* main() { let input: Tokens quote( class Data { var a: Int32 init(a_: Int32) { a a_ } } ) let decl parseDecl(input) // 获取一个 Decl 声明节点 var classDecl match (decl as ClassDecl) { // decl 的具体类型为 ClassDecl, 将其进行类型转化。 case Some(v) v case None throw Exception() } classDecl.dump() }运行结果ClassDecl { -keyword: Token { value: class kind: CLASS pos: 5: 9 } -identifier: Token { value: Data kind: IDENTIFIER pos: 5: 15 } -body: Body { -decls: 0, VarDecl { -keyword: Token { value: var kind: VAR pos: 6: 13 } -identifier: Token { value: a kind: IDENTIFIER pos: 6: 17 } -declType: PrimitiveType { -keyword: Token { value: Int32 kind: INT32 pos: 6: 20 } } } -decls: 1, FuncDecl { -keyword: Token { value: init kind: INIT pos: 7: 13 } -identifier: Token { value: init kind: IDENTIFIER pos: 7: 13 } -funcParams: 0, FuncParam { -identifier: Token { value: a_ kind: IDENTIFIER pos: 7: 18 } -colon: Token { value: : kind: COLON pos: 7: 20 } -paramType: PrimitiveType { -keyword: Token { value: Int32 kind: INT32 pos: 7: 22 } } } -block: Block { -nodes: 0, AssignExpr { -leftExpr: RefExpr { -identifier: Token { value: a kind: IDENTIFIER pos: 8: 17 } } -assign: Token { value: kind: ASSIGN pos: 8: 19 } -rightExpr: RefExpr { -identifier: Token { value: a_ kind: IDENTIFIER pos: 8: 21 } } } } } } }3.2 示例要点解读parseDecl(input)的返回类型是Decl但Decl是所有声明节点的父类运行期实际承载的具体类型可能是ClassDecl、FuncDecl、VarDecl、MacroDecl等。示例通过decl as ClassDecl配合match进行类型转化Some(v)分支拿到真实的ClassDecl对象None分支抛出异常。这与 operate.md 中的用法一致。dump()是每个 AST 节点内置的打印方法输出为缩进树形结构完整呈现节点的嵌套关系与每个Token的value、kind、pos行号:列号。ClassDecl的-body是Body节点其decls下标 0 为VarDeclvar a: Int32下标 1 为FuncDeclinit构造函数构造函数块内是AssignExpra a_左右操作数分别是引用a与a_的RefExpr。注意示例输出中的pos如5: 9、8: 21是相对quote源码片段起点的行列位置列号从 1 开始。3.3 astKind 参数与支持范围parseDecl的第二个参数astKind!: String 用于指定解析特定节点类型有效值为PrimaryCtorDecl和PropMemberDeclPrimaryCtorDecl解析主构造函数。例如quote(Point(var x: Int32, var y: Int32) {})配合astKind: PrimaryCtorDecl可得到PrimaryCtorDecl节点如果不设置astKind则会因为没有func关键字而无法解析。PropMemberDecl解析prop声明的 getter 和 setter 函数解析结果为FuncDecl类型。例如import std.ast.* main() { let getter quote( get() { _val } ) let setter quote( set(v) { _val v }) let getterDecl parseDecl(getter, astKind: PropMemberDecl) let setterDecl parseDecl(setter, astKind: PropMemberDecl) println((getterDecl as FuncDecl).getOrThrow().block.toTokens()) println((setterDecl as FuncDecl).getOrThrow().block.toTokens()) }运行结果{ _val } { _val v }注意parseDecl不支持解析FuncParam类型详见 ast_package_funcs.md。3.4 源码实现从 parse_decl.cj 可以看到parseDecl的实现逻辑根据astKind分发到不同的底层 C 接口 ——CJ_AST_ParsePrimaryConstructor、CJ_AST_ParsePropMemberDecl或默认的CJ_AST_ParseDecl解析结果以 flatbuffer 格式返回再通过generateDeclAST依据astKind字符串如class_decl、func_decl、var_decl等逐一构造对应的仓颉 AST 节点并调用addPositionInfo回填位置信息。解析失败统一抛出ParseASTException(Failed to parse decl.)。DECL_LISTparse_node.cj列出了所有受支持的声明节点种类包括main_decl、func_decl、macro_decl、class_decl、interface_decl、enum_decl、struct_decl、type_alias_decl、primary_ctor_decl、var_decl、prop_decl、extend_decl、func_param、var_with_pattern_decl、macro_expand_decl。四、parseProgram将整个仓颉源文件解析为 Program 节点4.1 完整示例parseProgram(Tokens) 用于解析单个仓颉文件的源码获取一个Program类型的节点。待解析仓颉源码文件test_macro_define.cj的内容如下/** * 此 cj 文件作为输入参数用于测试 parseProgram() **/ macro package m internal import std.ast.* internal import base as mybase public macro M(input: Tokens) { return input }利用parseProgram函数将上述代码解析为一个Program节点对象internal import std.ast.* internal import std.fs.* internal import std.io.* main() { let path: String ./test_macro_define.cj let file: File File(path, Read) let reader: StringReaderFile StringReader(file) let code: String reader.readToEnd() // 读取源码文件内容为字符串 let tokens: Tokens cangjieLex(code) let fileNode parseProgram(tokens) // 解析为 Program 节点 fileNode.dump() return 0 }运行结果Program { -packageHeader: PackageHeader { -keywordM: Token { value: macro kind: MACRO } -keywordP: Token { value: package kind: PACKAGE } -packageIdentifier: Token { value: m kind: IDENTIFIER } } -importLists: 0, ImportList { -modifier: Token { value: internal kind: INTERNAL } -keywordI: Token { value: import kind: IMPORT } -importKind: All prefixPath: 0: Token { value: std kind: IDENTIFIER } prefixPath: 1: Token { value: ast kind: IDENTIFIER } -identifier: Token { value: * kind: MUL } } -importLists: 1, ImportList { -modifier: Token { value: internal kind: INTERNAL } -keywordI: Token { value: import kind: IMPORT } -importKind: Alias -identifier: Token { value: base kind: IDENTIFIER } -importAlias 0: Token { value: as kind: AS } -importAlias 1: Token { value: mybase kind: IDENTIFIER } } -decls: 0, MacroDecl { -modifiers: 0, Modifier { -keyword: Token { value: public kind: PUBLIC } } -keyword: Token { value: macro kind: MACRO } -identifier: Token { value: M kind: IDENTIFIER } -funcParams: 0, FuncParam { -identifier: Token { value: input kind: IDENTIFIER } -colon: Token { value: : kind: COLON } -paramType: RefType { -identifier: Token { value: Tokens kind: IDENTIFIER } } } -block: Block { -nodes: 0, ReturnExpr { -keyword: Token { value: return kind: RETURN } -expr: RefExpr { -identifier: Token { value: input kind: IDENTIFIER } } } } } }4.2 示例要点解读与parseDecl不同parseProgram处理的是完整源文件输入既可以来自quote字面量也可以像本例这样先通过std.fs的File、std.io的StringReader读取磁盘文件内容再经cangjieLex词法化得到Tokens最后交给parseProgram。Program节点的三个核心属性从上到下依次是packageHeader: PackageHeader—— 包声明示例中是macro package m宏包因此包含MACRO、PACKAGE两个关键字 TokenimportLists: ArrayListImportList—— 导入语句列表示例中第一条是全量导入internal import std.ast.*importKind: All通配符*的 kind 为MUL第二条是别名导入internal import base as mybaseimportKind: AliasimportAlias记录as与mybasedecls—— 顶层声明示例中是MacroDeclpublic macro M(input: Tokens)其函数体为ReturnExpr返回RefExpr(input)。4.3 使用限制注意仓颉宏展开后的代码不允许出现包的声明和包导入语句。使用parseProgram时若输入的源码中包含包声明或包导入语句输出的Program节点中也会包含它们分别记录在packageHeader和importLists属性中因此不能在宏函数中直接将这样的Program节点返回为Tokens详见 ast_package_funcs.md。4.4 源码实现从 parse_node.cj 可以看到parseProgram调用底层 C 接口CJ_AST_ParseTopLevel对应 ast_api.cpp 中ParseKind::PROGRAM分支内部执行Parser::ParseTopLevel()随后通过createProgram(node.GetRootAsFile())构造Program节点。此外Program、PackageHeader、ImportList等节点类型都提供了以Tokens直接构造的init(inputs: Tokens)便捷构造器内部复用parseProgram见 nodes.cj例如从Tokens单独提取包声明或导入列表。五、解析函数家族总览除parseDecl、parseProgram外std.ast还提供面向表达式、模式、类型的解析函数以及配套的Fragment增量解析变体。全部函数签名与功能如下详见 ast_package_funcs.md函数签名功能parseDeclparseDecl(input: Tokens, astKind!: String ): Decl解析一组词法单元获取一个Decl节点parseDeclFragmentparseDeclFragment(input: Tokens, startFrom!: Int64 0): (Decl, Int64)解析一个Decl节点及继续解析的索引parseExprparseExpr(input: Tokens): Expr解析一组词法单元获取一个Expr节点parseExprFragmentparseExprFragment(input: Tokens, startFrom!: Int64 0): (Expr, Int64)解析一个Expr节点及继续解析的索引parsePatternparsePattern(input: Tokens): Pattern解析一组词法单元获取一个Pattern节点parsePatternFragmentparsePatternFragment(input: Tokens, startFrom!: Int64 0): (Pattern, Int64)解析一个Pattern节点及继续解析的索引parseProgramparseProgram(input: Tokens): Program解析单个仓颉文件的源码获取一个Program节点parseTypeparseType(input: Tokens): TypeNode解析一组词法单元获取一个TypeNode节点parseTypeFragmentparseTypeFragment(input: Tokens, startFrom!: Int64 0): (TypeNode, Int64)解析一个TypeNode节点及继续解析的索引所有非Fragment解析函数在输入Tokens无法构造对应节点时抛出 ParseASTException异常中包含报错提示信息。5.1 Fragment 变体批量解析与增量位置Fragment系列返回(节点, Int64)二元组第二项是“继续解析的位置索引”非常适合在同一段Tokens中连续解析多个语法片段。例如 parseDeclFragment 解析两个连续函数import std.ast.* main() { let tokens quote( func f0(x: Int64) { return x 1 } func f1(x: Int64) { return x 2 } ) let (funcDecl0, mid) parseDeclFragment(tokens) // 从第一个 FuncDecl 后继续 let (funcDecl1, _) parseDeclFragment(tokens, startFrom: mid) // 输出两次 parse 的结果 println(funcDecl0.toTokens(): ${funcDecl0.toTokens()}) println(funcDecl1.toTokens(): ${funcDecl1.toTokens()}) }运行结果funcDecl0.toTokens(): func f0(x: Int64) { return x 1 } funcDecl1.toTokens(): func f1(x: Int64) { return x 2 }其底层实现parse_decl.cj 的parseDeclFragment通过parseFragment调用CJ_AST_ParseDecl由 C 侧将已消耗的 token 数量写入sizeRef最终返回(astNode, count)其中count tokenCounter startFrom即为下一次解析的起始位置。类似地parseExprFragment 可解析quote(a b, c d)中的两个表达式跳过逗号parsePatternFragment 可从quote(case A(a) println(a))中startFrom: 1的位置解析出EnumPattern节点A(a)并将mid定位到 5。注意parseDeclFragment不支持解析FuncParam、PropDecl、PrimaryCtorDecl类型见 ast_package_funcs.md。5.2 表达式、模式与类型解析parseExpr将quote(a b)解析为BinaryExprtoTokens()可无损还原为a bimport std.ast.* main() { let expr parseExpr(quote(a b)) // 输出 parse 的结果 println(expr is BinaryExpr: ${expr is BinaryExpr}) println(expr.toTokens(): ${expr.toTokens()}) }运行结果expr is BinaryExpr: true expr.toTokens(): a bparsePattern将quote((A(a), B(b)))解析为TuplePatternimport std.ast.* main() { let pattern parsePattern(quote((A(a), B(b)))) // 输出 parse 的结果 println(pattern is TuplePattern: ${pattern is TuplePattern}) println(pattern.toTokens(): ${pattern.toTokens()}) }运行结果pattern is TuplePattern: true pattern.toTokens(): (A(a), B(b))parseType将quote(MyClass)解析为RefTypeimport std.ast.* main() { let refType parseType(quote(MyClass)) // 输出 parse 的结果 println(refType is RefType: ${refType is RefType}) println(refType.toTokens(): ${refType.toTokens()}) }运行结果refType is RefType: true refType.toTokens(): MyClass从 parse_node.cj 的EXPR_LIST、TYPE_LIST、PATTERN_LIST可以看出表达式体系覆盖binary_expr、call_expr、match_expr、lambda_expr、quote_expr等 40 余种类型体系覆盖ref_type、qualified_type、option_type、func_type、tuple_type、this_type等 10 种模式体系覆盖var_pattern、const_pattern、tuple_pattern、enum_pattern、wildcard_pattern等 9 种。六、解析结果的使用打印、遍历与修改拿到 AST 节点之后通常有三类后续操作对应仓库中的三个配套示例文档。6.1 dump快速查看节点结构由于节点种类丰富、不同节点属性各异std.ast为每个 AST 节点实现了dump函数方便实时查看语法树节点的整体结构见 dump.mdimport std.ast.* main() { let input quote(var demo: Int64 1) // 假设当前代码所在行数为4 let varDecl parseDecl(input) varDecl.dump() }运行结果VarDecl { -keyword: Token { value: var kind: VAR pos: 4: 23 } -identifier: Token { value: demo kind: IDENTIFIER pos: 4: 27 } -declType: PrimitiveType { -keyword: Token { value: Int64 kind: INT64 pos: 4: 33 } } -assign: Token { value: kind: ASSIGN pos: 4: 39 } -expr: LitConstExpr { -literal: Token { value: 1 kind: INTEGER_LITERAL pos: 4: 41 } } }这也是本文第三、四节示例中classDecl.dump()、fileNode.dump()所依赖的机制先解析、后 dump即可直观核对 AST 结构是否符合预期。6.2 增删改查直接修改 AST获取ClassDecl节点后可以对其执行增、删、改、查等操作见 operate.mdimport std.ast.* main() { let input: Tokens quote( class Data { var a: Int32 init(a_: Int32) { a a_ } } ) let decl parseDecl(input) // 获取一个 Decl 声明节点 var classDecl match (decl as ClassDecl) { // decl 的具体类型为 ClassDecl, 将其进行类型转化。 case Some(v) v case None throw Exception() } var identifier classDecl.identifier // 为该节点增加一个成员函数用于获取a的值 var funcdecl FuncDecl(quote(func getValue() {a})) classDecl.body.decls.add(funcdecl) println(Identifier value is ${identifier.value}) println(ClassDecl body size is ${classDecl.body.decls.size}) 0 }运行结果Identifier value is Data ClassDecl body size is 3可见ClassDecl.body.decls是可直接add的声明列表向其中追加一个由quote构造的FuncDecl后类体声明数由 2 变为 3。这是宏改写代码的典型手法解析 → 修改节点 →toTokens()输出新代码。6.3 traverse自定义访问函数遍历 AST继承抽象类 Visitor 并重写visit函数可定制遍历 AST 的行为见 traverse.md。下面的访问器专门收集“未初始化”的变量声明节点import std.ast.* class MyVisitor : Visitor { public var uninitializedVars Tokens() // 存储变量词法单元 public override func visit(varDecl: VarDecl) { try { varDecl.expr } catch (e: ASTException) { uninitializedVars.append(varDecl.identifier) } breakTraverse() // 不会继续遍历 varDecl 的子节点 return } } main(): Int64 { let input quote( var a : Int64 ) let varDecl parseDecl(input) let visitor MyVisitor() // MyVisitor中定义了对 varDecl 节点的处理 varDecl.traverse(visitor) // 实现对 varDecl 节点的处理 println(Uninitialized VarDecl size is ${visitor.uninitializedVars.size}) 0 }运行结果Uninitialized VarDecl size is 1七、底层实现原理从仓颉层到编译器前端从源码结构看std.ast的解析能力由三层协作完成仓颉 API 层ffi.cj通过foreign声明对外调用 C 接口包括CJ_AST_ParseExpr、CJ_AST_ParseDecl、CJ_AST_ParsePattern、CJ_AST_ParseType、CJ_AST_ParseTopLevel、CJ_AST_Lex等。仓颉侧先将Tokens通过toBytes()序列化为字节缓冲tokensBytes经unsafePointerCastFromUint8Array拷贝为 C 指针传给 C解析结果以 flatbuffer 二进制格式返回再由genASTFormatNode读取为ASTFormat_Node供上层构造 AST 对象。parseFragment额外通过sizeRef输出已解析的 token 数量实现增量解析。C 桥接层ast_api.cpp复用仓颉编译器前端的Parser、Lexer、DiagnosticEngine、SourceManager等组件。ParseWithError根据ParseKindEXPR、DECL、PROGRAM、PATTERN分别调用Parser::ParseExprLibast()、Parser::ParseDecl(scopeKind)、Parser::ParseTopLevel()、Parser::ParsePattern()并把解析诊断信息汇总返回LexWithError则用Lexer::GetTokens()完成词法分析。AST 构造层parse_decl.cj、parse_node.cj 等根据 flatbuffer 节点中的astKind字符串分发到createClassDecl、createFuncDecl、createVarDecl、createMacroDecl、createProgram等工厂函数逐层还原Token、Body、Block、FuncParam、类型节点与表达式节点并回填Position位置信息。例如generateDeclAST中的case class_decl createClassDecl(...)分支即对应parseDecl示例中ClassDecl节点的构造。八、常见问题与注意事项宏展开代码不允许包声明/导入parseProgram解析出的Program若包含packageHeader或importLists不能在宏函数中直接将其作为Tokens返回否则会违反宏展开后的代码约束见 ast_package_funcs.md。parseDecl的适用范围默认不解析FuncParamparseDeclFragment则进一步排除FuncParam、PropDecl、PrimaryCtorDecl。需要解析主构造函数或 prop 的 getter/setter 时务必通过astKind指定PrimaryCtorDecl/PropMemberDecl。节点类型转化parseDecl的静态返回类型是Decl访问具体成员前需用asmatch或is判断实际类型如ClassDecl、FuncDecl、VarDecl避免对父类直接访问子类专属属性。异常处理解析失败抛出ParseASTExceptioncangjieLex词法失败抛出IllegalArgumentException内存申请失败抛出IllegalMemoryException节点访问越界或缺失属性可能抛出ASTException。位置信息语义Token.pos中的行号与列号是相对输入Tokens源码片段的行列位置quote构造的片段与磁盘文件读取的片段起始行列不同dump输出中的pos应结合输入来源理解。配套的报错能力宏中还可以使用 diagReport 输出与原生编译器格式一致的自定义错误/警告示例见 report.md该接口仅在宏展开阶段有效嵌套宏场景下还可使用assertParentContext、getChildMessages、setItem等Macro With Context函数示例见 context.md。九、小结本文以parse.md的两个核心示例为主线完整覆盖了parseDecl与parseProgram的调用方式、dump输出结构、astKind参数语义与使用限制并扩展到cangjieLex词法入口、quote字面量、compareTokens比较函数以及parseExpr、parsePattern、parseType与各自Fragment增量变体构成的完整解析函数家族。结合 parse_decl.cj、parse_node.cj、ffi.cj、ast_api.cpp 等源码可以清晰看到“词法分析 → flatbuffer 序列化 → AST 节点构造”的完整链路。掌握这套解析 API即可在宏定义中实现源码校验、代码改写与代码生成或在工具链中构建基于仓颉语法树的静态分析能力。赞分享编程语言语言运行时标准库垃圾回收并发编程【免费下载链接】cangjie_runtime仓颉编程语言运行时与标准库。项目地址https://gitcode.com/Cangjie/cangjie_runtime点击查看免费下载相关推荐仓颉源码 AST 解析实战使用 std.ast 将仓颉代码解析为语法树对象仓颉源码 AST 解析实战使用 std.ast 将仓颉代码解析为语法树对象 本指南以仓颉标准库 std.ast 包为核心讲解如何将一段仓颉源码解析为抽象语法文档知识库教程OpenHarmony仓颉 std.ast 语法树 Block 块节点详解结构组成、属性语义与 AST 编程实战仓颉 std.ast 语法树 Block 块节点详解结构组成、属性语义与 AST 编程实战 Block 是仓颉标准库 std.ast 语法树节点体系中表示块人工智能AI 技能文档开发工具仓颉语言 std.ast 包 AST 节点类全解析语法树类型体系与宏编程实践指南仓颉语言 std.ast 包 AST 节点类全解析语法树类型体系与宏编程实践指南 导读 仓颉编程语言的标准库 std.ast 包提供了源码语法解析器与完整的文档知识库教程OpenHarmony上一篇KMS智能激活工具完整指南5分钟永久解决Windows和Office激活问题下一篇GitHub下载加速终极指南3步告别龟速访问提升10倍效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号