微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

相似结构的保姆匹配

如何解决相似结构的保姆匹配

我正在尝试为 minecraft 函数语法创建一个 tree-sitter

语言的结构如下所示:

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
    )),selector_object: $ => choice(
      seq(
        "{",repeat(
          seq(
            $.selector_score,")
          )
        ),"}"
      ),seq(
        "{",repeat(
          seq(
            $.selector_nbt,"}"
      )
    ),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,")
        )
      ),"}"
    ),nbt_array: $ => seq(
      "[",repeat(
        seq(
          $.nbt_object_value,"]"
    ),nbt_object_key: $ => choice(
      $.string,$.identifier
    ),nbt_object_value: $ => choice(
      $.string,$.nbt_number,$.nbt
    ),nbt_number: $ => seq(
      $.number,field("nbt_number_suffix",optional(choice("l","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,14])
        (selector_value [0,15] - [0,28]
          (selector_object [0,28]
            (ERROR [0,16] - [0,27]
              (nbt_object_key [0,23]
                (identifier [0,23]))))))))
tests/test.mcfunction  0 ms    (ERROR [0,27])

预期:应该是ERROR而不是selector_score,并且应该有score_keyscore_value

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

我做错了什么?

解决方法

我通过使用两个冲突键的 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,

如果无法重写上述正则表达式以使其不存在冲突,那么您可能需要此处描述的解决方法:#1287 (reply in thread)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。