如何用LPeg发出解析错误信号



我正在编写一个基于LPeg的解析器。如何使解析错误返回nil, errmsg

我知道我可以使用error(),但据我所知,这会产生一个正常的错误,而不是nil, errmsg

代码很长,但相关部分是:

local eof = lpeg.P(-1)
local nl = (lpeg.P "r")^-1 * lpeg.P "n" + lpeg.P "\n" + eof -- r for winblows compat
local nlnoeof = (lpeg.P "r")^-1 * lpeg.P "n" + lpeg.P "\n"
local ws = lpeg.S(" t")
local inlineComment = lpeg.P("`") * (1 - (lpeg.S("`") + nl * nl)) ^ 0 * lpeg.P("`")
local wsc = ws + inlineComment -- comments count as whitespace
local backslashEscaped
= lpeg.P("\ ") / " " -- escaped spaces
+ lpeg.P("\\") / "\" -- escaped escape character
+ lpeg.P("\#") / "#"
+ lpeg.P("\>") / ">"
+ lpeg.P("\`") / "`"
+ lpeg.P("\n") -- \n newlines count as backslash escaped
+ lpeg.P("\") * lpeg.P(function(_, i)
    error("Unknown backslash escape at position " .. i) -- this error() is what I wanna get rid of.
  end)
local Line = lpeg.C((wsc + (backslashEscaped + 1 - nl))^0) / function(x) return x end * nl * lpeg.Cp()

当存在无效转义时,我希望Line:match(...)返回nil, errmsg

LPeg本身没有提供特定的功能来帮助您报告错误。一个快速解决你的问题的方法是打一个受保护的电话(pcall)来匹配如下:

local function parse(text)
  local ok, result = pcall(function () return Line:match(text) end)
  if ok then
    return result
  else
    -- `result` will contain the error thrown. If it is a string
    -- Lua will add additional information to it (filename and line number).
    -- If you do not want this, throw a table instead like `{ msg = "error" }`
    -- and access the message using `result.msg`
    return nil, result
  end
end

然而,这也会捕获任何其他错误,这可能是您不想要的。更好的解决方案是使用LPegLabel。LPegLabel是LPeg的扩展,增加了对标记故障的支持。只需将require"lpeg"替换为require"lpeglabel",然后使用lpeg.T(L)来抛出标签,其中L是1-255之间的整数(0用于常规PEG故障)。

local unknown_escape = 1
local backslashEscaped = ... + lpeg.P("\") * lpeg.T(unknown_escape)

现在,如果抛出了一个标签,Line:match(...)将返回nil, label, suffixsuffix是剩余的未处理输入,您可以使用它来通过其长度计算错误位置)。这样,您就可以根据标签打印出相应的错误消息。对于更复杂的语法,您可能想要一种更系统的方法来映射错误标签和消息。请查看LPegLabel存储库的自述文件中的文档,查看如何做到这一点的示例。

LPegLabel还允许您顺便捕捉语法中的标签(通过标签选择);这对于实现诸如错误恢复之类的功能非常有用。有关标记故障和示例的更多信息,请查看文档。

相关内容

  • 没有找到相关文章

最新更新