Rust编译器如何在泛型中标记'>'和'>>'?

Jos*_*ise 3 parsing compilation lexical-analysis tokenize rust

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

Option<Option<i32>>
Run Code Online (Sandbox Code Playgroud)

我们知道Rust具有>>移位运算符,因此我认为天真的令牌生成器会>>在此处输出令牌,解析器将其视为错误(因为它期望使用两个>令牌)。

但显然Rust编译器了解情况并正确处理。这里发生了什么?

  • 分词器是否保持某种状态,以某种方式知道需要关闭尖括号?
  • 解析器是否检查>>并将其分成两个令牌,然后将其推回到令牌流中?
  • 还是完全其他?

She*_*ter 5

您可以查看Rust解析库以了解其处理方式。

图书馆比较

模糊泡菜

这是我编写的解析器,因此我对这些概念最熟悉。

令牌生成器是一个简单的逐字节解析器,它贪婪地消耗字符>>来创建DoubleRightAngle令牌。

完成标记化后,所有这些标记都被收集到向量中,并进行第二次解析。在此过程中,解析位置是一个复杂的索引,允许被“拆分”。如果需要,这允许解析器将a分解>>为两个>。特定的解析函数根据要解析的内容寻找一>>两个递归>

令牌化和解析都使用peresil板条箱实现。

同步

Syn是另一个解析库。在这里,他们使用了一个相关的想法:每个令牌由多个span组成,每个span 代表一个字符。也就是说,该Shr结构具有一个spans: [Span; 2]字段。

Rustc

看来编译器允许将多个令牌“粘合”到更大的令牌中。在解析期间,>>可以被“消耗”并替换为>

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))
}
Run Code Online (Sandbox Code Playgroud)

附加点

空格周围还有其他皱纹。解析器应等效地解析这两种类型:

Option<Option<i32>>
Option < Option < i32 > >
Run Code Online (Sandbox Code Playgroud)

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

a >>= 1
a >> = 1
Run Code Online (Sandbox Code Playgroud)