20次发布

0.4.5 2024年8月17日
0.4.2 2024年6月30日
0.4.1 2024年3月26日
0.3.3 2023年12月12日
0.3.1 2023年11月24日

#52 in 编程语言

Download history 2036/week @ 2024-06-22 5359/week @ 2024-06-29 1143/week @ 2024-07-06 1131/week @ 2024-07-13 1167/week @ 2024-07-20 1273/week @ 2024-07-27 1371/week @ 2024-08-03 1256/week @ 2024-08-10 1413/week @ 2024-08-17

5,436次每月下载

MIT许可证

190KB
3.5K SLoC

License: MIT Lints Tests Crates.io version codecov

mrLSD/semantic-analyzer-rs

语义分析器是一个开源的编程语言语义分析器,易于构建具有扩展性的高效编译器。

🌀 库的用途和解决的问题

创建一种编程语言的编译器是一个涉及多个关键阶段的过程。最常见的是

▶️ 词法分析(Lexer):这一阶段涉及将输入字符流分解成一系列令牌。令牌是编程语言的原子元素,如标识符、关键字、运算符等。

▶️ 语法分析(Parsing):在这一阶段,前一阶段获得的令牌根据编程语言的语法规则进行分组。这个过程的结果是一个抽象语法树(AST),它表示代码的层次结构。

语义分析:这一阶段涉及检查代码的语义正确性。这可以包括类型检查、变量作用域验证等。

▶️ 中间代码优化:在这一阶段,编译器试图改进中间表示形式以使其更高效。这可以包括死代码消除、表达式简化等。

▶️ 代码生成:这是最终的阶段,编译器将优化的中间表示形式(IR)转换为特定于目标架构的机器代码。

此库表示语义分析阶段。

🌻 特性

名称绑定和作用域检查:分析器验证所有变量、常量、函数在使用前都进行了声明,并且它们的使用在其作用域内。它还检查名称冲突,即同一作用域内的变量、常量、函数、类型具有相同的名称。

检查函数调用:分析器验证函数是否以正确的参数数量调用,并且参数的类型与函数期望的类型匹配。

作用域规则:检查变量、函数、常量、类型是否在其作用域内使用,并且在其可见作用域内可用。

类型检查:分析器检查操作是否在兼容的类型上对表达式、函数、常量、绑定进行。对于表达式中的操作。它是验证表达式类型与其在上下文中的使用是否一致的过程。

流控制检查:分析器检查控制流语句(if-else、循环、返回、break、continue)是否正确使用。支持条件表达式和条件表达式正确性检查。

构建符号表:在分析中使用符号表作为语义分析器使用的用于跟踪源代码中符号(变量、函数、常量)的数据结构。符号表中的每个条目都包含符号的名称、类型、与块状态相关的范围以及其他相关信息。

泛型表达式值:根据编译器要求,能够扩展AST(抽象语法树)的自定义表达式。并在《语义堆栈上下文》中实现这些自定义表达式的自定义指令。

🌳 语义状态树

语义分析器执行和通过阶段的输出结果是:语义状态树

这可以用于中间代码生成,进一步进行语义树优化、代码检查、后端代码生成(如LLVM)以针对目标机器。

🌲 语义状态树的结构

  • 块状态及其相关的块状态子分支。这是作用域的基本实体:变量、块(函数、if、循环)。特别是对表达式来说很有意义。这允许你细粒度地分离可见作用域及其可见限制。特别是 - 所有子元素都可以访问父元素。然而,父元素不能访问子元素,这有效地限制了可见作用域和实体使用。

    • 变量状态:块状态实体,包含当前状态下变量的属性,如:名称、类型、可变性、分配、重新分配。

    • 内部变量状态:块状态实体,包含内部变量名称。对于中间表示和代码生成后端(如LLVM)很有用。其中,阴影名称变量应具有不同的内部名称。这意味着内部变量始终是唯一的。

    • 标签状态:块状态实体,包含关于控制流标签的所有信息。

  • 全局状态:包含常量、声明函数和类型的全局状态。

  • 状态实体:包含

    • 全局状态
    • 错误结果
    • 语义树结果

所有这些源数据,都可以用于中间表示,用于后续优化和编译器代码生成。

🧺 编程语言的子集

分析器的输入参数是预定义的AST(抽象语法树)。作为一个构建AST的库,以及唯一的依赖项nom_locate——允许获取有关源代码的所有必要信息,以进行进一步的语义分析和生成相关且信息丰富的错误消息。目前决定AST是一个固定结构,因为它是定义编程语言词法表示的基本元素。

另一方面,它允许你实现与语法树匹配的任何编程语言子集。这也意味着从AST可以生成满足语义分析初始要求的词法表示子集。作为词法分析和源代码解析的库,建议使用:nom是一个解析器组合库

AST显示的是图灵完备的编程语言,并包含实现此功能所需的所有必要元素。

🔋 🔌 可扩展性

由于 AST 是预定义的,但在实际情况下,根据编译器的特定需求扩展功能可能是必要的,因此增加了 AST 可扩展性和为 语义栈上下文 生成的一组额外的 指令 功能。

  • 🚨 遗传表达式值:根据编译器要求,扩展自定义 z 表达式的能力。在 语义栈上下文 中实现这些自定义表达式自定义指令的能力。

🛋️ 例子

  • 🔎 有一个独立项目的示例实现 💾 Toy Codegen。该项目使用 SemanticStack 结果并将它们转换为 代码生成 逻辑,这清楚地显示了使用 semantic-analyzer-rs SemanticStackContext 结果的可能性。使用 LLVM 作为后端,inkwell 作为 LLVM 代码生成的库,并编译成可执行程序。数据源是 AST 结构本身。

📶 功能

可用的 rust 库功能

  • codec - 💮 启用与 Serde 的序列化和反序列化。这在形成 AST、Codegen、SemanticState 的序列化表示过程中特别方便。另一个重要细节是,任何实现 Serde 的库都可以作为序列化 codec 使用。例如格式:jsontomlyamlbinary 以及许多其他可以使用 serde 库的格式。应用 codec 功能的主要实体包括
    • AST ↪️ AST 数据源可以用序列化源表示。这对于设计并测试 Codegen、AST 数据传输管道特别有用,也可以用作 AST 数据生成源 - 任何可以生成序列化 AST 数据的编程语言。
    • State ↪️ SematniсState 可以以序列化数据的形式获得。这在存储代码生成前的状态、后分析、优化等方面特别方便 - 这将允许处理已经分析的数据。
    • SemanticStack ↪️ 包含一组用于 Codegen 的指令。以序列化形式表示可能方便用于以下情况:仅基于由语义分析器生成的代码生成器指令进行代码生成,而无需重复语义分析。序列化表示的 SemanticStack - 为使用任何第三方代码生成器和任何编程语言实现的编译器打开了广泛的可能性。

MIT LICENSE

依赖项

~1–1.3MB
~25K SLoC