0

我正在玩树顶游戏,但我无法使用简单的语法来生成我期望的 AST。

我的规则是

1:LINE 可以由一个或多个 PIPED COMMAND 组成,用 ; 分隔 2:一个 PIPED COMMAND 是一个或多个由 | 分隔的 COMMAND 3:一个命令是一个或多个由空格分隔的标识符

我期待这样的树

hello | abc | def ; abc | test ; cats ;

生成这样的树

Line
  PipedCommand
    Command
      Identifier hello
    Command 
      Identifier abc
    Command 
      Identifier def
  PipedCommand
    Command 
      Identifier abc
    Command 
      Identifier test
  PipedCommand
    Command 
      Identifier cats

但是,即使只是正确返回管道命令,我也无法得到它,如果我指定超过 2 个,结果就会混乱

> test | abc
[Command+Command0 offset=0, "test " (identifier):
  Identifier+Identifier0 offset=0, "test",
 Command+Command0 offset=6, " abc" (identifier):
  Identifier+Identifier0 offset=7, "abc"]
> test | abc | def
[Command+Command0 offset=0, "test " (identifier):
  Identifier+Identifier0 offset=0, "test"]
> 

语法目前看起来像:

grammar Line
  rule commands
    (command space? '|' commands space?) <Commands> / command
  end

  rule command
    space? identifier space? <Command>
  end

  rule identifier
    [a-zA-Z] [a-zA-Z0-9_]* <Identifier>
  end

  rule space
    [\s]+
  end
end

希望有人可以提供一点帮助!

谢谢

4

1 回答 1

1

您的解析器适用于这两个示例,我刚刚对其进行了测试。尝试删除这些类,然后在 irb 中运行 LineParser.new.parse('some | test'),你会看到解析树。

在您的测试程序或语法节点模块中有一些有趣的东西。也许您正在向解析器输入一个意想不到的字符?对于您显示的第二个示例输出,对命令的递归调用一定会失败,因此它会返回第二个选项。如果是这样,您还必须将 consume_all_input 选项设置为 false,否则会失败。

但是,因为它是递归的,所以它不会在您的命令 (PipedCommand) 下为您提供平面命令数组。您将获得一个包含第一个命令和另一个命令的命令,其中将包含命令的其他两个实例。

如果您不想要嵌套的 AST,则应该使用迭代而不是递归。这可能看起来像

rule commands
  head:command tail:( '|' command )*
  {
    def ast
      [head] + tail.elements.map(&:command)
    end
  }
end

如果这不能帮助您解决问题,请发布运行示例所需的所有文件,我们会为您找到错误。

于 2015-02-21T10:10:49.437 回答