【问题标题】:Is it a Lexer's Job to Parse Numbers and Strings?解析数字和字符串是 Lexer 的工作吗?
【发布时间】:2011-09-13 06:58:01
【问题描述】:

解析数字和字符串是词法分析器的工作吗?

考虑到我在询问 lexer 是否应该 parse 输入这一事实,这听起来可能会也可能不会愚蠢。但是,我不确定这实际上是词法分析器的工作还是解析器的工作,因为为了正确地进行词法分析,词法分析器首先需要解析字符串/数字,所以它会如果解析器这样做,似乎代码会被复制。

这确实是词法分析器的工作吗?或者词法分析器是否应该简单地将123.456 之类的字符串分解为字符串123.456,然后让解析器找出其余的?使用字符串做到这一点不会那么简单......

【问题讨论】:

  • 这是用于 Lex / YACC 之类的吗?
  • @Grady:有点……不是真的。 xD 我正在尝试手工制作自己的词法分析器(希望是解析器),但我不知道哪个应该做什么来解析数字和字符串。我没有使用任何外部工具,如 Lex/YACC,所以在这方面,没有。
  • 很有趣,但仍不清楚。您的意思是词法分析器的工作是识别解析器的 type 数字,而不是识别令牌?在这种情况下,正如您所说,您有一种循环引用(它如何在知道类型之前知道要解析的格式)。我认为这就是为什么 C#(例如)允许浮点数(F 和 D)上的后缀来消除词法分析器的双精度浮点数的歧义。我的猜测是,当词法分析器完成时,应该没有关于标记的问题,但可能有一些关于类型的问题。必须精心设计文字格式以实现这一点。
  • @harpo:不,我指的不是类型。 (或者我是吗?我想我对你所说的“类型”感到困惑。)我只是指这样一个事实,一个词法分析器能够说“这里是一个字符串文字”,它需要处理所有的转义码和一切。但如果它所做的只是返回输入的一部分,那么解析器将不得不再次做同样的事情——这就是重复,不是吗?
  • 您的意思是它必须通过识别转义序列不会终止字符串,而是它的一部分来“处理”转义序列;并且通过将这个“字面意思”交给解析器,然后解析器的工作就是对它们进行编码。或者,词法分析器可以执行编码并向解析器提供“就绪”字符串。后者对我来说更合适,对于字符串,但对于似乎暗示词法分析器正在将输入 converting 输入为解析器准备好的数字的数字,这似乎超出了范围。只是在这里大声思考。

标签: parsing lexer tokenize


【解决方案1】:

简单的答案是“是”。

在摘要中,您根本不需要词法分析器。您可以简单地编写一个使用单个字符作为标记的语法(实际上这正是 SGLR 解析器所做的,但这是另一天的故事)。

您需要词法分析器,因为使用字符作为原始元素构建的解析器不如将输入流分解为“令牌”的解析器高效,其中令牌是您正在解析的语言的原始元素(空格、关键字、标识符、数字,运算符,字符串,cmets,...)。 [如果您不关心效率,您可以跳过此答案的其余部分并阅读有关 SGLR 解析器的内容]。

好的词法分析器通常采用一组表示语言元素的正则表达式,并将它们编译成一个高效的有限状态机,该机器可以将输入流快速分割成这样的语言元素。 (如果您不想使用词法分析器生成器,对于简单的语言,您可以自己编写 FSA)。这种编译的 FSA 每个输入字符只执行几十条机器指令(从输入缓冲区获取字符,将字符切换到新状态,确定令牌是否完整,如果不再次执行),因此可以非常快。

此类词法分析器的输出通常是表示语言元素的代码(如果解析器无论如何都会忽略它,则没有空格)和一些位置信息(从文件 foo 开始,第 17 行第 3 列)以启用错误报告。

你可以停在那里并拥有有用的词法分析器。执行转换步骤通常很有用,该步骤将字符串转换为该令牌的等效本机机器值,无论是在收集字符时还是在令牌完成时,因为仍然知道涉及的特定字符令牌。这用于将目标语言中的数字(不同基数的)转换为其本地二进制等价物,将包含转义序列的文字字符串转换为构成字符串的实际字符,甚至获取标识符名称并在哈希表中查找它们以便轻松确定相同的标识符。解析器通常对这些转换后的值不感兴趣,但是解析之外的步骤(语义分析、检查优化、代码生成)无论如何都需要转换后的值,因此您最好在发现它们时进行转换。 (您可以延迟此转换,直到需要它们的二进制值,但实际上您几乎总是需要该值,因此延迟转换并不会带来太多好处)。

【讨论】:

  • 感谢您的详细回答,这真的很有帮助,+1。不过,有一个问题:您提到了One can stop there and have useful lexers。如果我停在那里,这意味着解析器将不得不处理文字 again (以找出转义码,解析数字等),对吗?因此它会涉及代码/工作的重复?
  • 解析器不需要;它只对抽象标记感兴趣,而不对它们的实际值感兴趣。 之后的步骤解析器会感兴趣,并且必须按照您所说的再次处理文字。重新发现和使用你已经知道的信息总是比在你知道的时候利用这些信息更昂贵。
  • 理想的词法分析器会执行值转换,因为它会看到可能是词素一部分的字符。如果您手动编写词法分析器,您将很容易看到这个机会(当您处理数字时,很容易将累加器乘以 10 并添加值)。在实践中,这有点混乱,但如果你付出了混乱的代价,你会得到非常快速的词法分析器,可以随时转换。
  • 您的最后一段根本无法与交叉编译器一起使用。转换为目标格式是代码生成的功能,而不是输入扫描。 1979 年,弗兰克·德·雷默 (Frank de Remer) 详细教导了我这一点。
  • @EJP:所以代码生成读取包含输入语言符号的字符串字符,然后然后决定做什么?这怎么算优势?您的交叉编译器如何在不知道源语言文字意思的情况下生成与目标语言兼容的文字?即使您认为这是交叉编译器决定如何表示转换后的值,拥有一个规范的机器值也很好,所以这肯定不会受到伤害。我们构建许多交叉编译器的经验是这种技术非常方便。
【解决方案2】:

我假设您想将“123.456”视为一个整体值,在这种情况下,您会将其全部传递给解析器,除非您需要以某种方式对其进行编码,例如

struct DecimalRep{
    double mantissa,
    double exponent 

}

但我想这完全取决于解析器的期望。

【讨论】:

  • 所以它实际上应该以更合适的内部格式将数据传递给解析器,而不仅仅是作为常规字符串?
  • 听起来这取决于你;)我会把它当作一个单一的令牌。
  • 另外,如果它们要分开和独立,你不会想为它创建一个特殊的数据类型。
  • @Mehrdad:您希望将文字值转换为易于编译器其余部分操作的表示形式。如果您有浮点文字,则应将其转换(如果没有精度损失)为 IEEE 格式的浮点数;那么如果编译器必须添加两个文字(例如,常量折叠),它可以使用内置于 CPU 中的本机 IEEE 浮点来完成。对于字符串/整数值也是如此。 (如果你把所有这些东西都保留为原始字符序列,你可能会通过不进行转换来节省 [可能不会] 一些时间,然后你会得到凌乱的编译器胆量。
  • @IraBaxter:是的,6 年后,我非常了解这些 :) 谢谢!
【解决方案3】:

词法分析器本质上是从输入中识别 TOKEN。在这种情况下,词法分析器可能会将数字“匹配”为浮点数 TOKEN。解析器本质上是处理标记并进行语法分析

【讨论】:

  • @Sai:是的,标记化是有道理的(因此我将标签添加到我的问题中:P)但我不确定“匹配”和“处理”之间的区别是什么。例如。那么"Hello\n World" 应该被词法分析器转换成什么?
  • 您可以将词法分析器视为一个预处理器,它有助于使解析器轻松解析。通常,词法分析器将“Hello”识别为 WORD,\n 识别为 NEWLINE,World 识别为 WORD
  • @Mehrdad -- 抱歉没有正确阅读。我没有意识到这是一个字符串文字(即使它很清楚)。对于那个很抱歉。这通常应该被解释为字符串文字。
  • 明确地说,传统字符串文字被大多数词法分析器提取为单个标记。 "Hello\World" 将生成一个 STRINGLITERAL 条目,其二进制值是 H、e、l、...\n、W、o、...d 的字符代码。 (更多...)
  • ... 根据语言的不同,字符串文字可能不是传统的,因此不是传统的词法。我们的 DMS 词法 PHP 前端双引号将“字符串文字”作为一系列不同类型的字符串文字片段。这是因为 PHP 中的此类字符串文字实际上是连接一堆字符串值的隐式表达式,其中一些确实是文字字符串片段,其中一些是 PHP 允许在文字字符串“中间”的插值变量或其他运算符.这个词法分析器仍在做正确的事:提取语言元素。
猜你喜欢
  • 1970-01-01
  • 2012-01-24
  • 2019-02-26
  • 2016-11-03
  • 1970-01-01
  • 2010-10-18
  • 1970-01-01
  • 1970-01-01
  • 2020-06-21
相关资源
最近更新 更多