2

私は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

4

1 に答える 1

0

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"使用します。ここで、 は 1 ~ 255 の整数です (通常の PEG 障害には 0 が使用されます)。lpeg.T(L)L

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

スローされたラベルがある場合にLine:match(...)返されるようになりました (は残りの未処理の入力であり、その長さからエラー位置を計算するために使用できます)。これにより、ラベルに基づいて適切なエラー メッセージを出力できます。より複雑な文法の場合、エラー ラベルとメッセージをマッピングするためのより体系的な方法が必要になるでしょう。LPegLabel リポジトリの readme にあるドキュメントを確認して、その方法の例を確認してください。nil, label, suffixsuffix

LPegLabel を使用すると、文法でラベルをキャッチすることもできます (ラベル付きの選択を介して)。これは、エラー回復などの実装に役立ちます。ラベル付けされた失敗と例の詳細については、ドキュメントを確認してください。

于 2016-09-03T05:30:41.057 に答える