2016-07-29 8 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() 

내가 잘못된 탈출있을 때 nil, errmsg을 반환 Line:match(...)를 원한다.

+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을 번들로 제공하고이 답변의 두 번째 부분을 사용할 수 있습니다. (LPegLabel을 일반 LPeg에 볼트로 다시 쓸 수는 없습니까?) – SoniEx2