Parsing Rust编译器如何标记'&燃气轮机';vs'&燃气轮机&燃气轮机';非专利药?

Parsing Rust编译器如何标记'&燃气轮机';vs'&燃气轮机&燃气轮机';非专利药?,parsing,compilation,rust,tokenize,lexical-analysis,Parsing,Compilation,Rust,Tokenize,Lexical Analysis,我已经编写了许多简单的标记器和递归下降解析器,因此我熟悉它们如何工作的基本概念。但当我偶然发现以下锈迹代码时,我感到惊讶: Option<Option<i32>> 选项 我们知道Rust有一个>移位运算符,所以我认为一个简单的标记器会在这里输出一个>标记,解析器会将其视为一个错误(因为它需要两个标记) 但是很明显,Rust编译器理解这种情况并正确地处理它。这是怎么回事 标记器是否保持某种状态,不知何故知道它需要关闭一个角括号 解析器是否检查>>并将其拆分为两个令牌,

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

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

但是很明显,Rust编译器理解这种情况并正确地处理它。这是怎么回事

  • 标记器是否保持某种状态,不知何故知道它需要关闭一个角括号
  • 解析器是否检查
    >>
    并将其拆分为两个令牌,然后将其推回到令牌流中
  • 或者完全是别的什么

    • 事实上,有一个问题非常详细地描述了其中的一些内容:

      事实上,Rust令牌管道(tokenizer+lexer)是一个相对简单的具有前瞻性的递归下降解析器(顺便说一句,这解释了当您编写错误代码时会出现大量语法错误。例如,忘记关闭括号,解析器将卡在该块中,抱怨该块的限制). 每个令牌都被摄取,状态在令牌之间保持,另外一个令牌被窥视以进行前瞻

      当Rust遇到某件事情时,它应该为其打开一个单独的状态(例如您的示例),该状态将保持在能够精确处理该问题的状态。由于该语言的构思非常简洁,所以在引用和引用调用之外没有真正的歧义(比如
      *variable.call()
      -你是说
      (*variable.call()
      还是
      *(variable.call())
      ?Rust让你明确地指定了这一点)

      当涉及到像您所描述的那样的类型定义时,没有歧义,因为移位运算符不能定义在该空间中。turbofish操作符也是如此-前面的
      表示下一个类型


      因此,答案是“其他东西”——严格的词法规则和有状态解析器。

      词法分析器不是独立于解析器的,因此它有一点上下文。此外,关于您的精确问题,只能在精确的位置找到锈蚀类型:

      • 在函数签名中:显然,不能与运算符混淆

      • 符号之后:再次不能有任何歧义,因为冒号表示将写入类型:

        让x:Vec=some_iterator.collect();
        
      • 在turbofish操作符中:

        让x=some_迭代器。collect::();
        
        该符号的存在只是为了避免产生歧义

      • 在特质依赖类型中:

        impl trait Foo for Bar{
        依赖类型=Vec;
        }
        
        type
        关键字清楚地表明将有一个类型


      如您所见,Rust团队已经仔细设计了语法,以便语法中不存在歧义。

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

      图书馆比较 毛茸茸的泡菜 这是我编写的解析器,因此我最熟悉这些概念

      标记器是一个简单的逐字节解析器,它贪婪地使用标记

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

      标记化和解析都是使用板条箱实现的

      Syn Syn是另一个解析库。在这里,他们使用了一个相关的想法:每个标记是,每个字符一个。也就是说,结构有一个
      Span:[Span;2]
      字段

      鲁斯特 似乎编译器允许。在解析过程中:

      附加点 空白处还有一条皱纹。解析器应等效地解析这两种类型:

      Option<Option<i32>>
      Option < Option < i32 > >
      
      a >>= 1
      a >> = 1
      

      这种符号的存在只是为了避免产生歧义——有人说要去除涡鱼;这会如何改变你的答案?这并不能真正回答问题。许多传统的解析器都有一个完全独立于语言语义的标记化步骤,不知道是解析类型还是表达式来生成正确的标记。这似乎就是OP所讨论的标记器解析器管道。@mcarton真的有任何编程语言的lexer完全独立于解析器吗?一点背景知识通常是必要的。@Shepmaster真的吗?虽然我确实看到有人抱怨turbofish的语法,但我从未看到过一个严肃的建议来删除它。我不知道如何才能做到这一点,而不引起它所防止的许多头痛。@FrenchBoiethios可能不再有很多现代语言是纯粹的这种语言了。不。但这仍然是课程中的一种常见方法,词法分析和解析并不局限于编程语言。
      a >>= 1
      a >> = 1