2012-03-19 3 views
3

Для языков с ключевыми словами необходимо выполнить некоторые специальные обманки, чтобы, например, предотвратить «если» интерпретироваться как идентификатор, а «ifSomeVariableName» - стать ключевым словом «if», за которым следует идентификатор «SomeVariableName» в токене поток.Идентификаторы FParsec и ключевые слова

Для рекурсивного спуска и Lex/Yacc я просто применил подход (в соответствии с полезной инструкцией) для преобразования потока токенов между лексером и парсером.

Однако FParsec, похоже, не делает отдельного лексерского шага, поэтому мне интересно, как лучше всего справиться с этим. Говоря о, кажется, что Parsec Haskell поддерживает лексерский слой, но FParsec этого не делает?

ответ

4

Я думаю, эта проблема очень проста. Ответ заключается в том, что вам необходимо:

  1. Разберите полное слово ([a-z]+), только нижний регистр;
  2. Проверьте, принадлежит ли оно словарю; если да, верните keyword; в противном случае парсер отпадет;
  3. Parse identifier по отдельности;

E.g. (Только гипотетический код, не тестируются):

let keyWordSet = 
    System.Collections.Generic.HashSet<_>(
     [|"while"; "begin"; "end"; "do"; "if"; "then"; "else"; "print"|] 
    ) 
let pKeyword = 
    (many1Satisfy isLower .>> nonAlphaNumeric) // [a-z]+ 
    >>= (fun s -> if keyWordSet.Contains(s) then (preturn x) else fail "not a keyword") 

let pContent = 
    pLineComment <|> pOperator <|> pNumeral <|> pKeyword <|> pIdentifier 

Код выше будет анализировать ключевое слово или идентификатор дважды. Чтобы исправить это, вы также можете:

  1. Разберите все слово ([a-z][A-Z]+[a-z][A-Z][0-9]+), например. все буквенно-цифровое;
  2. Проверьте, если это ключевое слово или идентификатор (строчные и принадлежность к словарю) и либо
    1. Вернуться ключевое слово
    2. Вернуться идентификатор

P.S. Не забудьте сначала заказать «более дешевые» парсеры, если это не испортит логику.

+0

Мне нравится ваш второй процесс. Он в основном делает то же самое, что и лексерский постпроцессорный трюк, но просто встроен. В 20/20 задним числом это самый очевидный решение :). Спасибо – Hans

+0

Определение 'pKeyword' в приведенном выше ответе меня сбивает с толку.Мой вывод типа показывает, что это «Parser », который не является (IMHO), что вы хотите - вы хотите вернуть «Parser » или сбой, завернутый в тип «Reply», и я не вижу, как достичь что с помощью оператора '| >>'? – Sam

+0

@Sam, спасибо, что указали это. Я обновил правило охраны. В зависимости от специфики домена, также может потребоваться обернуть синтаксический анализатор (ы) в «попытку». Надеюсь это поможет. – bytebuster

0

Вы можете определить синтаксический анализатор для пробелов и проверить, соблюдается ли его ключевое слово или идентификатор. Например, некоторые общие пробельные анализатор будет выглядеть

пусть pWhiteSpace = pLineComment < |> pMultilineComment < |> pSpaces

это потребуется, по крайней мере один пробел

пусть ws1 = skipMany1 pWhiteSpace

то, если будет выглядеть

let pIf = pstring "if". >> ws1

+1

«if (« не будет соответствовать такому способу ». – Hans

Смежные вопросы