2

我有一个语法正确的 Lua 5.1 源代码的文件。

我在该文件中有一个位置(行和字符偏移)。

我需要获取function()包含该位置的最内层主体的右括号的字节偏移量(或找出该位置属于文件的主要块)。

IE:

本地函数 foo()
                    ^ 结果
  打印(“酒吧”)
           ^ 输入
结尾
本地 foo = 函数()
                      ^ 结果
  打印(“酒吧”)
           ^ 输入
结尾
本地 foo = 函数()
  返回函数()
                   ^ 结果
    打印(“酒吧”)
             ^ 输入
  结尾
结尾

...等等。

我该如何稳健地做到这一点?

4

1 回答 1

0

编辑:我原来的答案没有考虑到“最里面”的要求。我已经考虑到了这一点

为了使事情“健壮”,有一些考虑因素。

首先,跳过字符串和注释内容很重要,以避免在以下情况下出现错误输出:

foo = function()
    print(" function() ")
    -- function()
    print("bar")
            ^ input
end

考虑到 Lua 的嵌套字符串和注释语法,这可能有点困难。例如,考虑输入以嵌套字符串或注释开头的情况:

foo = function()
    print([[
        bar = function()
            print("baz")
                    ^ input
        end
    ]])
end

因此,如果您想要一个完全健壮的系统,那么在到达函数参数列表的末尾之前只向后解析是不可接受的,因为您可能没有向后解析足够远的距离以达到 a [[,这会使您的匹配无效。因此有必要将整个文件解析到您的位置(除非您在这些奇怪的情况下可以接受不正确的匹配。如果这是一个编辑器插件,这些“不正确”的结果实际上可能是可取的,因为它们可以让您使用相同的插件编辑以字符串文字形式存储在其他 lua 代码中的 lua 代码)。

因为您尝试匹配的特定语法没有任何“嵌套”,所以不需要成熟的解析器。但是,您将需要维护一个堆栈来跟踪范围。考虑到这一点,您需要做的就是从头开始逐个字符地浏览源文件,应用以下逻辑:

  1. 每次遇到"or'时,忽略直到结尾的字符"or '。小心处理像\"\\
  2. 每次--遇到 a 时,忽略注释的结束换行符之前的字符。请注意,仅当注释不是多行注释时才这样做。
  3. 每次遇到多行字符串开始符号(例如[[,[=[等),或遇到多行注释符号(例如--[[or--[=[等​​)时,忽略这些字符,直到右方括号之间有适当数量的匹配等号.
  4. 当遇到单词边界时,检查它后面的字符是否可以开始一个以 a 结尾的块end(例如,、、、、等。不要包括)。如果是这样,则将位置推送到范围堆栈上。在这种情况下,“单词边界”是任何不能用作 lua 标识符的字符(这是为了防止在类似的情况下匹配)。文件的开头也被认为是一个单词边界。ifwhileforfunctionrepeatabcfunction()
  5. 如果遇到单词边界并且后面跟着end,则弹出堆栈的顶部元素。如果堆栈没有元素,则抱怨语法错误。

当您最终向前迈出并到达您的“输入”位置时,从堆栈中弹出元素,直到找到一个function范围。从该位置前进到下一个),忽略)注释中的 '(如果它跨越多行或包含内联注释,理论上可以在参数列表中找到--[[ ]])。那个位置就是你的结果。

这应该处理所有情况,包括function使用语法糖的情况,例如

function foo()
    print("bar")
end

你没有在你的例子中包括,但我想你仍然想匹配。

于 2014-12-07T02:24:45.957 回答