2011-11-12 2 views
1

누군가가 다음 동작을 이해하도록 도와 줄 수 있습니다. parseAll (parseIf, "If bla blablaa")is expected이됩니다. 대신 나는 항상 string matching regex 'is\b' expected but 'b' found을 얻습니다. " If bla is blablaa" (맨 처음 공백에 주목하십시오)이 동일한 동작을하기 때문에 공백과 관련이 있다고 생각합니다. 나는 StandardTokenParsers로 시험해 보았고 모든 것이 잘 동작했다. 하지만 STP는 불행히도 정규 표현식을 지원하지 않습니다. 추가 질문 : 문자 시퀀스 대신 문자열 시퀀스를 사용하도록 RegexParser를 어떻게 변경해야합니까? 그러면 오류보고를 훨씬 쉽게 할 수 있습니다.RegexParser에 대한 사용자 지정 오류

lazy val parseIf = roleGiverIf ~ giverRole 

lazy val roleGiverIf = 
    kwIf ~> identifier | failure("""A rule must begin with if""") 
lazy val giverRole = 
    kwIs ~> identifier | failure("""is expected""") 

lazy val keyword = 
    kwIf | kwAnd | kwThen | kwOf | kwIs | kwFrom | kwTo 

lazy val identifier = 
    not(keyword) ~ roleEntityLiteral 
// ... 

def roleEntityLiteral: Parser[String] = 
    """([^"\p{Cntrl}\\]|\\[\\/bfnrt]|\\u[a-fA-F0-9]{4})\S*""".r 
def kwIf: Parser[String] = "If\\b".r 
def kwIs: Parser[String] = "is\\b".r 

// ... 

parseAll(parseIf, "If bla blablaa") match { 
    case Success(parseIf, _) => println(parseIf) 
    case Failure(msg, _) => println("Failure: " + msg) 
    case Error(msg, _) => println("Error: " + msg) 

답변

0

이 문제는 매우 이상합니다. |으로 전화를 걸고 양쪽에 오류가 발생하면 오류가 발생한 쪽 마지막으로이 선택되고 왼쪽면이 선호됩니다.

giverRole으로 직접 구문 분석하면 예상 한 결과가 생성됩니다. 실패 이전에 성공적인 일치를 추가하면,보고있는 결과가 생성됩니다.

이유는 다소 미묘합니다. 나는 모든 파서에 log 문을 뿌려서 만 발견했습니다. 이를 이해하려면 을 이해해야합니다. RegexParser은 공백을 건너 뛰는 방법입니다. 특히 의 공백은 accept에 스킵됩니다. failureaccept을 호출하지 않으므로 공백을 건너 뛰지 않습니다. 스킵으로

kwIs의 실패 failure의 실패 If 후 공간 이 일어나는 공간으로서, b에서 발생하지만. 여기 :

If bla blablaa 
^kwIs fails here 
^failure fails here 

따라서 kwIs의 오류 메시지는 앞서 언급 한 규칙보다 우선합니다.

파서가 공백을 무시하고 건너 뛰게함으로써이 문제를 해결할 수 있습니다. 이 패턴은 항상 일치해야합니다. 그렇지 않으면 더 혼란스러운 오류 메시지가 나타납니다. 여기에 내가 일을 생각하는 제안입니다 :

"\\b|$".r ~ failure("is expected") 

또 다른 해결책은 어떤 경우에 당신은 맞춤형 오류 메시지를 제공 할 수 동의를 암시 정규식을 사용하는 대신 acceptIf 또는 acceptMatch을 사용하는 것입니다.

+0

나는 정규식과 어휘 능력을 가진 파서를 작성했고, 당신이 제안한대로 acceptIf를 사용했다. 그러나 위의 예가 예상대로 작동하지 않는 것은 여전히 ​​이상합니다. 도움을 주셔서 감사합니다 – awertos

+0

@awertos 마침내 문제가 무엇인지 알아 냈습니다. 첫 번째 해결책은 내가 생각했던 것보다 더 적절했다. 나는 단지 공백이 아닌 문자를 사용하지 않고 오류를 적절한 위치에 표시하도록 변경했다. –

관련 문제