2016-07-29 4 views
1

私はLPegベースのパーサーを書いています。構文解析エラーがnil, errmsgを返すようにするにはどうすればよいですか?LPegで解析エラーを通知するにはどうすればよいですか?

私はerror()を使用することができますが、私が知る限り、通常のエラーを生成するのはnil, errmsgではありません。

コードがpretty longですが、関連する部分はこれです:

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を返すようにしたいです。

+0

あなたは何を達成しようとしていますか?それは最小の例ですか?あなたは '戻る'を試みましたか? – Jakuje

+0

'error()'は 'nil、errmsg'の代わりにエラーを生成します。バックスラッシュエスケープでエラーが発生した場合、 'Line:match()'と 'Data:match()'を使って 'nil、errmsg'を返します。 – SoniEx2

+0

@Jakuje実際には、無効なエスケープがあるときには 'Line:match()'だけで 'nil、errmsg'を返します。 – SoniEx2

答えて

0

LPeg自体には、エラー報告に役立つ特別な機能はありません。あなたの問題への迅速な修正がprotected call (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の整数です(通常のPEG障害には0が使用されます)。スローラベルがある場合

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

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

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

+0

LPegでない場合はまだLPegですか?私は、LPegLabelを標準のLPegを内蔵したものだけで使うことはできないと確信しています。 – SoniEx2

+0

@ SoniEx2 LPegLabelはLPegではありませんが、ドロップインの代替として使用できます。私の答えの最初の部分( 'pcall'を使って)は標準的なLuaなので、LPegでそれを使うことができます。 – undecidabot

+0

LuvitにLPegLabelをバンドルさせてください。私はこの回答の2番目の部分を使うかもしれません。 (普通のLPegにボルトで接続するためにLPegLabelを書き直すことはできませんか?) – SoniEx2

関連する問題