表驱动的词法分析需要多少缓冲



我正在Rust中编写一个POSIX shell实现。这带来了一些相当尴尬的要求:

  • 输入必须逐行读取。如果输入来自不可查找的源,则意味着必须一次读取一个字节的输入
  • 反斜线换行,如果不加引号,则表示换行。它不是一个令牌分隔符,理想情况下应该在词法分析之前进行处理

如果lexer一次读取一个字符,并允许规则设置lexer的字符源可以查询的内部状态,则可以很容易地处理这两个要求(Rust不允许在全局变量中填充状态的C解决方案)。我现在的lexer就是这么做的。然而,这是398行高度重复的代码,包括一些(不充分的)测试。此代码请求自动生成。

自动生成的lexer通常使用基于有限自动机的表驱动设计。我对此不是很熟悉,我想知道前瞻性是这个设计固有的还是通常不使用。如果通常不使用前瞻性,那么我可能可以修改现有的lexer生成器来做我想做的事情;否则,我可能会被手工编写的代码卡住。

这可能是一个过于宽泛的问题,或者生成的答案包含了太多意见,这不是SO问题的好属性。这在很大程度上是一个问题的组合,询问现有lexer生成器算法的实现、有限自动机的编程、shell语言的词法要求和Rust程序的特性,以及可能更多的主题。

首先,让我们讨论一下工具生成的lexer的功能问题。让我们考虑一下最常用的flex,GNU lexer生成器。答案是;它可以为你构建一个lexer,让你随心所欲。它足够灵活,包含足够多的不同功能来完成这些工作(其他类似工具也是如此)。它会简单明了吗?不一定。该工具使您能够使用内置的读取和有限状态自动机,但您可以提供自己的输入例程,编写自己的状态机,甚至可以处理自写代码中的困难部分(在C或C++中)。在手册、教程网站、教程视频、课本和SO上的问题中,有很多关于如何实现这一点的例子。

当flex在C或C++中生成代码时,这对您在Rust中编码有什么帮助?我们需要一个基于Rust的lexer。一次可以做文献搜索,看看有什么可用的。维基百科擅长列表,并且有可用的解析器和lexer生成器工具列表。然而,这些都不会生成Rust。然而,Rust中有这样的工具:

  • RustLex:Rust的词法分析器生成器
  • RACC-Rust另一个编译器编译器

由于这两项都是正在进行的实验性工作,你需要自己对它们进行评估。

另一种选择是制作自己版本的开源工具(如flex)来使用Rust。这可以通过两种方式实现:

  1. 您可以对flex的输出进行后处理,将C代码转换为Rust代码,然后进行编译
  2. 您可以修改该工具的代码以生成Rust,而不是C。(它不需要用Rust本身编写,就可以实现您的愿望。)

这些方法已经做了好几次,以便能够针对其他新语言。因此,有一大堆用于各种语言的编译器生成器工具。

下一个问题是手写lexer代码的大小和性质。在任何语言中,都有标准化和公认的有限状态自动机编程方法。有经验的程序员应该知道模式:

while ( NOT <<EOF>> ) {
  switch ( next_symbol() ) {
     case state_symbol[1]: 
              ....
             break;
      case state_symbol[2]:
              ....
              break;
       default:
             error(diagnostic);
  }
}

甚至可以在功能上作为:

action[state_symbol[next_symbol()]];

可以手工编写一个非常紧凑和高效的常规语言解析FSA来进行词法分析,但这是语言和算法方面的经验问题。

你提出的宽泛而不精确的问题得到了宽泛而不准确的答案:是的,一切皆有可能,它不依赖于缓冲和回溯。

最新更新