Странное поведение синтаксический анализ императивного языка с использованием 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"] []])