Как обрабатывать ошибки при разборе в F # - PullRequest
9 голосов
/ 09 марта 2011

Я использую утилиты fslex / fsyacc для своих F # Lexer и Parser. Если вводимый текст имеет неверный синтаксис, необходимо знать место, где это происходит.

Можно определить неправильную лексему (токен) в Lexer и выдать исключение, если использовался неправильный символ или слово:

rule token = parse
          ...      
  | integer   { INT (Int32.Parse(lexeme lexbuf)) }
  | "*="      { failwith "Incorrect symbol" }
  | eof       { EOF }

Вопрос больше относится к Parser (fsyacc) - если входной текст имеет правильные токены и был успешно токенизирован Lexer, но при синтаксическом анализе произошла ошибка (например, неправильный порядок токенов или какой-то отсутствующий токен в правиле)

Я знаю, если поймать исключение, это даст позицию (строку и столбец), где синтаксический анализ не удался:

try
   Parser.start Lexer.token lexbuf
with e ->
   let pos = lexbuf.EndPos
   let line = pos.Line
   let column = pos.Column
   let message = e.Message  // "parse error"
    ... 

Но возможно ли (если да - как это сделать?) Определить также класс AST, для которого не удалось выполнить синтаксический анализ .

Например, можно ли написать что-то похожее на следующее в моем файле parser.fsy:

Expression1: 
   | INT         { Int $1 }
     ...
   | _           { failwith "Error with parsing in Expression1"}

1 Ответ

9 голосов
/ 09 марта 2011

Простое пропускание "_" должно привести к конфликту сдвига / уменьшения. Для небольшого набора токенов вы можете перечислить их все. Для большого набора токенов это более проблематично.

Компилятор F # делает нечто подобное, определяя префиксы более ранних правил и устанавливает состояние ошибки:

atomicPattern:
  ...
  | LPAREN parenPatternBody RPAREN 
      {  let m = (lhs(parseState)) in SynPat.Paren($2 m,m) } 
  | LPAREN parenPatternBody recover 
      { reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnmatchedParen()); $2 (rhs2 parseState 1 2) }
  | LPAREN error RPAREN 
      { (* silent recovery *) SynPat.Wild (lhs(parseState)) }
  | LPAREN recover 
      {  reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnmatchedParen()); SynPat.Wild (lhs(parseState))}  

recover: 
   | error { true }  
   | EOF { false }

Вы можете увидеть весь файл в хранилище .

Более подробную информацию об обработке ошибок в ocamlyacc / fsyacc можно найти в руководстве OCaml (Часть III & rarr; Генераторы синтаксического анализатора и синтаксического анализатора & rarr; Обработка ошибок).

...