【问题标题】:Are parsing expression grammars suited to parsing the shell command language?解析表达式语法是否适合解析 shell 命令语言?
【发布时间】:2015-03-09 02:58:56
【问题描述】:

POSIX shell 命令语言不容易解析,主要是因为词法分析和解析之间的紧密耦合。

但是,解析表达式语法 (PEG) 通常无需扫描仪。通过结合词法和解析,我似乎可以避免这些问题。我使用的语言 (Rust) 有一个维护良好的 PEG 库。但是,我知道使用这个库可能会遇到三个困难:

  • Shell 必须能够逐行解析,而不是读取超出行尾的字符。
  • 别名是纯粹的词法,在某些情况下可能会导致一个标记被其他标记的任何序列替换
  • Shell 保留字仅在某些情况下被识别

鉴于这些要求,PEG 是否适合解析 shell 命令语言,还是手写递归下降解析器更适合?

【问题讨论】:

  • FWIW,bash 使用了一个相当简单的野牛生成的解析器,并结合了一个极其复杂的手写词法分析器。我不知道 PEG 的效果如何,但如果你试一试,请告诉我们。
  • 三个原因:它是 GPL,而我的 shell 在 MIT/Apache 2 下,它在 C 中,而我的 shell 在 Rust 中,我不会从中学到任何东西。
  • 是的。 PEG 解析器进行扫描。语法语言比正则表达式更强大,更简洁方便。我已经将几个 ANTLR 语法翻译成 Grako (PEG),词汇部分也很容易翻译。不过,PEG 的效率将低于基于状态机的词法分析器。
  • @Apalala 我不仅仅指词法分析;我的意思也是解析。
  • 这个问题可能比 Stack Overflow 更适合程序员 Stack Exchange。作为一个 SO 问题,它似乎太宽泛,而且民意调查太多。 YMMV。

标签: shell parsing rust parser-generator peg


【解决方案1】:

是的,可以使用 PEG,而且您注意到的任何问题都不应该是问题。 特别是:

1) 逐行解析:大多数 PEG 工具不会有任何内置的空白跳过。包括换行符在内的所有空格都必须由您明确处理,这意味着您可以以任何您喜欢的方式处理换行符。

2) 您不应该使用来自 PEG 的解析树作为您的 AST。相反,您应该下降解析树并构建 AST。对于别名,在解析完成并构建 AST 之后,您可以检测别名并为别名插入适当的扩展。

3) 保留字不保留,除非您保留它们。也就是说,如果您的上下文中可能出现保留字或其他字母数字符号,则必须首先明确检查保留字,然后检查任意字母数字符号,因为一旦 PEG 确定它有匹配项,则不会返回-追踪。在不允许保留字的任何地方,只要不检查它,您的通用字母数字符号规则就会成功。

【讨论】:

  • 我有点离题,但我将“别名”一词读作“无参数宏”。谁说宏扩展必须在您提供的语法中形成一个短语?如果没有,您不能只是“替换树”。 (坦率地说,当词法分析器遇到它们时,只需扩展它们就可以轻松处理它们)。
  • @Ira:传统的 shell 别名基本上是文本替换 - 调用中的任何后续文本都被解析为扩展的一部分。因此,尽管您所说的对于其他语言或更高级的 shell 中的别名可能是正确的,但文本替换几乎总是正确的。此外:正如我已经说过的,AST 不是解析树。你做任何替换创建正确的别名语义。
  • “几乎总是?”给定字符串“ if (pqr abc”,其中 pqr 是“a>b)”的别名,你如何解析字符串然后稍后替换别名?
  • 你不能,贝壳也不能。几乎总是,我的意思是“在大多数情况下别名是合法的”。您的示例在我使用的任何外壳中都不合法。我说“大多数”是因为我不确定; OP应该检查。无论如何,我已经结束了争论,因为这与所提出的问题无关。
  • shell 别名不是宏、无参数或其他,因此您的论点不适用。只有在命令有效的情况下才会检测和扩展 Shell 别名。但是,我可能在建议一个简单的 AST 替换方面走得太远了,所以我在上面概括了我的答案。感谢您指出可能存在的误解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多