1

我正在尝试为资源 API 创建一个简单的脚本。我有一个资源API,主要以结构化的方式创建游戏资源。我想要的是处理这个 API,而不是每次我想要一个资源时都创建 c++ 程序。所以我们(我和我来自 uni 的导师)决定创建一个简单的脚本来创建/编辑资源文件,而无需每次都编译。还有一些其他不相关的因素,我需要命令行界面而不是 GUI 程序。

无论如何,这是脚本示例:

<path>.<command> -<options>
/Graphics[3].add "blabla.png"

这种脚本语言不是我设计的,API 的所有者设计的。'.' 之前的部分 你可以猜到'.'之后的路径和部分。是实际命令和一些选项、标志等。作为第一步,我尝试创建左侧部分的语法,因为我认为我可以在搜索有关词法分析器和解析器的信息时使用它。问题是我在解析和编程语言方面缺乏经验,我不确定它是否正确。这是左侧的更多示例和语法。

dir -> '/' | '/' path
path -> object '/' path | object
object -> number | string '[' number ']'

如果这个语法可能是一团糟,我不知道。有 5 种不同的可能性,它们是:

String
"String"
Number
String[Number]
"String"[Number]

它必须以'/'符号开头,如果它是唯一的符号,我会接受它作为根。

现在我的问题是如何在词法上分析这个脚本?有什么特别的方法吗?我的词法分析器应该做什么和不应该做什么(我读过一些词法分析器也做了句法分析)。您认为语法等在技术上是否合适?我应该使用哪种解析方法(递归下降、LL 等)?我正在努力使它在技术上适合工作。它不是商业的,所以我有时间,因此我可以更好地学习词法分析和解析。我不想使用解析器库。

4

1 回答 1

3

我的词法分析器应该做什么和不做什么?

它应该:

  • 识别令牌
  • 忽略可忽略的空格和注释(如果有这样的东西)
  • 可选地,跟踪源位置以产生有意义的错误消息。

它不应该尝试解析输入,尽管使用这种简单的语言会非常诱人。

据我所知,您有以下标记:

  • 标点符号:/, ., 线性空白, 换行
  • 数字
  • 不带引号的字符串(通常称为“atoms”或“ids”)
  • 带引号的字符串(可能与不带引号的字符串相同的标记类型)

我不确定语法-options是什么,但这可能包括更多可能性。

选择返回linear-white-space(即,仅由制表符和空格组成的序列)作为标记有点值得怀疑;它使语法相当复杂,特别是因为可能存在空白可以忽略的地方,例如一行的开头和结尾。但我有直觉,您不想在路径内允许空格,并且您计划在命令名称及其参数之间要求它。也就是说,您要禁止:

/left /right[3] .whimper "hello, world"
/left/right[3].whimper"hello, world"

但也许我错了。也许你很乐意接受两者。那会更简单,因为如果您同时接受两者,那么您可以完全忽略线性空白。

顺便说一句,经验表明,使用换行符分隔命令可能会很尴尬。迟早您需要将命令分成两行,以避免购买额外的显示器来查看整行。将 a 作为要继续的行的最后一个字符的约定(由 bash 和 C 预处理器等使用)是\可能的,但可能会导致烦人的错误(例如在\继续这条线)。


从这里开始是 100% 的个人意见,免费提供。所以,看它的价值吧。

我正在努力使它在技术上适合工作。它不是商业的,所以我有时间,因此我可以更好地学习词法分析和解析。我不想使用解析器库。

在我看来,这里有一个矛盾。或者也许是两个矛盾。

技术上合适的工作将使用标准工具;至少是一个词法生成器,可能还有一个解析器生成器。它会这样做,因为如果使用得当,提供给工具的词汇和语法描述准确地记录了实际语言,并且工具保证所需的语言是实际识别的语言。编写临时代码,甚至是简单的词法识别器和递归下降解析器,尽管它可以很优雅,但自文档化、可维护性较差,并且提供的正确性保证较少。因此,最佳实践是“使用标准工具”。

其次,我不同意你的导师(如果我正确理解他们的建议,基于你的评论)编写临时词法分析器和解析器有助于理解词法和解析理论。事实上,它可能会适得其反。自下而上的解析在理论上和实践上都非常优雅,几乎不可能手写,也完全不可能阅读。因此,许多程序员更喜欢使用递归下降或 Pratt 解析器,因为他们理解代码。然而,这样的解析器不如自底向上解析器(特别是 GLR 或 Earley 解析器,它们是完全通用的)强大,并且它们的使用会导致不必要的语法妥协。

您无需编写正则表达式库即可理解正则表达式。这些库抽象出笨拙的实现细节(其中有很多,而且它们真的很笨拙),让您专注于创建和使用正则表达式的本质。

同样,你不需要编写编译器来理解如何用 C 编程。你对 C 有很好的基础之后,你可以通过理解它如何翻译成机器代码来提高你的理解(也许),但是除非您计划从事编译器编写工作,否则了解晦涩的优化算法的细节不会使您成为更好的程序员。或者,至少,他们不是你议程上的第一个。

同样,一旦你真正理解了正则表达式,你可能会发现编写一个库很有趣。或者不是——你可能会发现它非常令人沮丧,并在几个月的努力工作后放弃。无论哪种方式,您都会更加欣赏现有的库。但首先要学会使用现有的库。

解析器生成器也是如此。如果您想学习如何将编程语言的想法翻译成精确且可实现的东西,请学习如何使用解析器生成器。只有在你掌握了解析的理论之后,你才应该考虑专注于低级实现。

于 2013-07-11T16:37:48.123 回答