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

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"] []])