Странное поведение синтаксический анализ императивного языка с использованием Parsec
Я пытаюсь разобрать фрагмент языка Abap с помощью Parsec в haskell. Операторы в Abap разделены точками. Синтаксис определения функции:
FORM <name> <arguments>.
<statements>.
ENDFORM.
Я использую его в качестве минимального примера.
Вот моя попытка написать соответствующий тип в haskell и синтаксическом анализаторе. GenStatement-конструктор предназначен для всех других операторов, кроме определения функции, как описано выше.
module Main where
import Control.Applicative
import Data.Functor.Identity
import qualified Text.Parsec as P
import qualified Text.Parsec.String as S
import Text.Parsec.Language
import qualified Text.Parsec.Token as T
type Args = String
type Name = String
data AbapExpr -- ABAP Program
= Form Name Args [AbapExpr]
| GenStatement String [AbapExpr]
deriving (Show, Read)
lexer :: T.TokenParser ()
lexer = T.makeTokenParser style
where
caseSensitive = False
keys = ["form", "endform"]
style = emptyDef
{ T.reservedNames = keys
, T.identStart = P.alphaNum <|> P.char '_'
, T.identLetter = P.alphaNum <|> P.char '_'
}
dot :: S.Parser String
dot = T.dot lexer
reserved :: String -> S.Parser ()
reserved = T.reserved lexer
identifier :: S.Parser String
identifier = T.identifier lexer
argsP :: S.Parser String
argsP = P.manyTill P.anyChar (P.try (P.lookAhead dot))
genericStatementP :: S.Parser String
genericStatementP = P.manyTill P.anyChar (P.try dot)
abapExprP = P.try (P.between (reserved "form")
(reserved "endform" >> dot)
abapFormP)
<|> abapStmtP
where
abapFormP = Form <$> identifier <*> argsP <* dot <*> many abapExprP
abapStmtP = GenStatement <$> genericStatementP <*> many abapExprP
Тестирование синтаксического анализатора со следующими входными данными приводит к странному результату. поведение.
-- a wrapper for convenience
parse :: S.Parser a -> String -> Either P.ParseError a
parse = flip P.parse "Test"
testParse1 = parse abapExprP "form foo arg1 arg2 arg2. form bar arg1. endform. endform."
Приводит к
Right (GenStatement "form foo arg1 arg2 arg2" [GenStatement "form bar arg1" [GenStatement "endform" [GenStatement "endform" []]]])
Таким образом, кажется, что первый brach всегда терпит неудачу, и только вторая родовая ветвь успешна. Однако если вторая ветвь (синтаксический анализ общих операторов) комментируется, то синтаксический анализ форм внезапно завершается успешно:
abapExprP = P.try (P.between (reserved "form")
(reserved "endform" >> dot)
abapFormP)
-- <|> abapStmtP
where
abapFormP = Form <$> identifier <*> argsP <* dot <*> many abapExprP
-- abapStmtP = GenStatement <$> genericStatementP <*> many abapExprP
Теперь мы получаем
Right (Form "foo" "arg1 arg2 arg2" [Form "bar" "arg1" []])
Как это возможно? Кажется, что первая ветвь успешно работает, так почему же она не работает в первом примере - что я упускаю?
Заранее большое спасибо!
1 ответ:
Мне кажется, что ваш парсер
genericStatementPразбирает любой символ, пока не появится точка (вы используетеP.anyChar). Следовательно, он не распознает зарезервированные ключевые слова для вашего лексера.Я думаю, что вы должны определить:
type Args = [String]И:
argsP :: S.Parser [String] argsP = P.manyTill identifier (P.try (P.lookAhead dot)) genericStatementP :: S.Parser String genericStatementP = identifierС этими изменениями я получаю следующий результат:
Right (Form "foo" ["arg1","arg2","arg2"] [Form "bar" ["arg1"] []])