1

我正在尝试为 Minecraft 函数语法创建一个树保姆

该语言的结构如下所示:

command @e[key=value] other args

在上面的示例中,我对第二个参数(目标选择器)中的值有疑问。这个值可以是很多东西,比如字符串、数字、布尔值和两个类似的对象结构(NBT 和记分牌对象)。

以下是每个示例:

NBT

{key:value}

记分牌对象

{key=number} // where number is: N, ..N, N.., or N..N

我的语法文件包含以下代码:

// unrelated code removed

module.exports = grammar({
  name: "mcfunction",
  rules: {
    root: $ => repeat(
      choice(
        $.command
      )
    ),
    command: $ => prec.right(seq(
      field("command_name", $.identifier),
      repeat(
        choice(
          $.selector
        )
      ),
      "\n"
    )),
    identifier: $ => /[A-Za-z][\w-]+/,
    number: $ => prec(1, /-?\d+(\.\d+)?/),
    boolean: $ => choice(
      "true",
      "false"
    ),
    string: $ => seq(
      "\"",
      repeat(
        choice(
          $._escape_sequence,
          /[^"]/
        )
      ),
      "\""
    ),
    _escape_sequence: $ => seq("\\", "\""),
    selector: $ => seq(
      token(
        seq(
          "@",
          choice(
            "p", "a", "e", "s", "r"
          )
        )
      ),
      optional(
        seq(
          token.immediate("["),
          optional(
            repeat(
              seq(
                $.selector_option,
                optional(",")
              )
            )
          ),
          "]"
        )
      ),
    ),
    selector_option: $ => seq(
      $.selector_key,
      "=",
      $.selector_value
    ),
    selector_key: $ => /[a-z_-]+/,
    selector_value: $ => choice(
      $.item,
      $.path,
      $.selector_key,
      $.selector_number,
      $.number,
      $.boolean,
      $.selector_object
    ),
    selector_number: $ => prec.right(1, choice(
      seq(
        "..",
        $.number
      ),
      seq(
        $.number,
        "..",
        $.number
      ),
      seq(
        $.number,
        ".."
      ),
      $.number
    )),
    selector_object: $ => choice(
      seq(
        "{",
        repeat(
          seq(
            $.selector_score,
            optional(",")
          )
        ),
        "}"
      ),
      seq(
        "{",
        repeat(
          seq(
            $.selector_nbt,
            optional(",")
          )
        ),
        "}"
      )
    ),
    selector_nbt: $ => seq(
      $.nbt_object_key,
      ":",
      $.nbt_object_value
    ),
    selector_score: $ => seq(
      field("selector_score_key", $.selector_key),
      "=",
      field("selector_score_value", $.selector_number)
    ),
    _namespace: $ => /[a-z_-]+:/,
    item: $ => seq(
      $._namespace,
      $.selector_key
    ),
    path: $ => seq(
      choice($.item, /[a-z_]+/),
      repeat1(
        token("/", /[a-z_]/)
      )
    ),
    nbt: $ => choice(
      $.nbt_array,
      $.nbt_object
    ),
    nbt_object: $ => seq(
      "{",
      repeat(
        seq(
          $.nbt_object_key,
          ":",
          $.nbt_object_value,
          optional(",")
        )
      ),
      "}"
    ),
    nbt_array: $ => seq(
      "[",
      repeat(
        seq(
          $.nbt_object_value,
          optional(",")
        )
      ),
      "]"
    ),
    nbt_object_key: $ => choice(
      $.string,
      $.number,
      $.identifier
    ),
    nbt_object_value: $ => choice(
      $.string,
      $.nbt_number,
      $.boolean,
      $.nbt
    ),
    nbt_number: $ => seq(
      $.number,
      field("nbt_number_suffix", optional(choice("l","s","d","f","b")))
    )
  }
});

但是,如果我编译和解析test @e[scores={example=1..}],我会得到:

(root [0, 0] - [6, 0]
  (command [0, 0] - [1, 0]
    command_name: (identifier [0, 0] - [0, 4])
    (selector [0, 5] - [0, 29]
      (selector_option [0, 8] - [0, 28]
        (selector_key [0, 8] - [0, 14])
        (selector_value [0, 15] - [0, 28]
          (selector_object [0, 15] - [0, 28]
            (ERROR [0, 16] - [0, 27]
              (nbt_object_key [0, 16] - [0, 23]
                (identifier [0, 16] - [0, 23]))))))))
tests/test.mcfunction  0 ms    (ERROR [0, 16] - [0, 27])

预期:而不是ERROR,它应该是selector_score,并且应该有一个score_keyand score_value

selector_nbt如果我从中删除序列,则不会发生这种情况selector_object。但是,如果在使用 nbt 数据的命令上运行解析(使用两个序列或仅使用selector_nbt),则不会出现错误。

我究竟做错了什么?

4

1 回答 1

0

我通过使用choice两个冲突键中的一个解决了这个问题,如下所示:

choice(
  alias($.key_1, $.key_2),
  $.key_2
)

GitHub 上的 ahlinc回答:

selector_key您可以通过为终端分配词法分析器优先级来修复上述语法的错误,identifier例如:

selector_key: $ => token(prec(1, /[a-z_-]+/)),

但是您需要注意,您使用的正则表达式会发生冲突:

identifier: $ => /[A-Za-z][\w-]+/,
selector_key: $ => token(prec(1, /[a-z_-]+/)),

如果无法重写上述正则表达式以使其中没有冲突,那么您可能需要此处描述的解决方法:#1287(在线程中回复)

于 2021-08-02T20:09:48.957 回答