如果DSL 需要嵌入 Rust 代码中(如内联汇编或 SQL 语句),您应该使用过程宏。
相反,如果 DSL 代码是要解释的单独文件,则可以使用解析包,例如 Nom 或 Pest。
也可以使用声明性宏。
这段代码是带有整个 html/css 语言,并且它是完全类型安全的,并且带有声明性宏。
对于语义分析器,请使用egg和egglog。
它们是自定义数据结构,用于以非破坏性方式表示编译器重写规则。
传统的编译器优化器的工作方式是与输入的模式相匹配,并对其进行破坏性的改写,但这意味着改写的顺序非常重要。
例如,如果你在改写(x * a) / a = x之前应用改写x * 2 = x << 2,你就会失去更好的优化机会,因为(x * 2) / 2会被改写成(x << 2) / 2,这不会被第二个规则所匹配。
egg代替了对等价词组的跟踪,并以一种紧凑的方式存储它们。你可以得到一个单一的节点,它指向所有已知的计算表达式,然后你可以相当有效地与之进行模式匹配,并且可以进行应用分析和成本函数,为你的程序非常有效地搜索广泛的可能形式。
还有直接使用基于纯文本的逐字符进行扫描,其中涉及了分词器,有一些超级简单且可读的东西,如下所示:
fn scan_rust_line_comment(&mut self) -> ScannerResult<'text, &'text str> { |
其中KEYWORDS是["as", "break", ...].
总结
宏用于在编译期间创建 Rust 代码。
好的宏应该尽可能坚持 Rust 代码。
您可以将 syn 用于过程宏。
用于创建用于其他目的的扫描器和解析器的工具包括:
- logos (基于结构的扫描仪生成器)
- pest(PEG 解析器生成器)
- nom(解析器组合器库)
- lalrpop(用于构建 LR(1) 解析器的解析器生成器)
- rowan(管理 CST 的库)