parsing - Rust 编译器如何标记泛型中的 '>' 与 '>>'?

标签 parsing compilation rust tokenize lexical-analysis

我编写过许多简单的分词器和递归下降解析器,因此我熟悉它们工作原理的基本概念。但是当我偶然发现以下 Rust 代码时,我感到很惊讶:

Option<Option<i32>>

我们知道 Rust 有一个 >> 移位运算符,所以我认为一个简单的分词器会在这里输出一个 >>> 标记,解析器会将其视为错误(因为它需要两个 > 标记)。

但显然 Rust 编译器了解情况并正确处理。这是怎么回事?

  • 分词器是否保持某种状态,以某种方式知道它需要关闭尖括号?
  • 解析器是否检查 >>> 并将其分成两个推回 token 流的 token ?
  • 还是完全不同?

最佳答案

您可以查看 Rust 解析库以了解它们如何处理它。

图书馆比较

泡菜泡菜

这是我编写的解析器,所以我最熟悉其中的概念。

tokenizer 是一个简单的逐字节解析器,贪婪地 consumes the characters >> to create a DoubleRightAngle token 。

标记化完成后,所有这些标记都将收集到一个向量中,然后进行第二次解析。在此过程中,解析位置是一个复杂的索引 allows being "split" .这允许解析器在需要时将 >> 分解为两个 >。特定的解析函数根据正在解析的内容查找一个 >> 或两个递归 >

标记化和解析都是使用 peresil 实现的 crate 。

同步

Syn 是另一个解析库。在这里,他们使用了一个相关的想法:每个标记都是 composed of multiple spans , 每个字符一个。即 Shr struct 有一个 spans: [Span; 2] 字段。

使用rust

编译器似乎允许 "gluing" multiple tokens into a bigger one .在解析过程中,>> can be "consumed" and replaced with a > :

token::BinOp(token::Shr) => {
    let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
    Some(self.bump_with(token::Gt, span))
}
token::BinOpEq(token::Shr) => {
    let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
    Some(self.bump_with(token::Ge, span))
}
token::Ge => {
    let span = self.token.span.with_lo(self.token.span.lo() + BytePos(1));
    Some(self.bump_with(token::Eq, span))
}

加分

空格周围还有一个额外的皱纹。解析器应该等效地解析这两种类型:

Option<Option<i32>>
Option < Option < i32 > >

但是,它不应该等效地解析这些表达式:

a >>= 1
a >> = 1

关于parsing - Rust 编译器如何标记泛型中的 '>' 与 '>>'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58065507/

相关文章:

java - 如何解析txt文件中的2列int

c++ - StarCluster错误中的C++程序编译

lua - 动态类型语言的编译器如何处理非局部变量的变化?

parsing - 如何从Haskell中的字符串解析UTCTime类型的时间值?

java - 解析 JSON 抛出异常

gcc - 无法配置 gcc - 找不到 mpfr

rust - 为什么 `&str` 实现函数(例如 `String` )的 `String::trim` 结果不像静态字符串文字?

Rust:条件特征继承

rust - 如何收集 panic !争论?

java - 出于教育目的在 Java 中实现 XML 解析器