私はhaskellのParsecでAbap言語の断片を解析しようとしています。 Abapのステートメントはドットで区切られています。関数定義の構文は次のとおりです。Parsecを使用して命令的言語を構文解析する不自然な動作
FORM <name> <arguments>.
<statements>.
ENDFORM.
最小限の例として使用します。 ここでは、対応する型をhaskellとパーサに書き込む試みを行っています。 GenStatement
-Constructorは、上記の関数定義を除く他のすべてのステートメント用です。
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
パーサを次の入力でテストすると、異常な動作が発生します。
Right (GenStatement "form foo arg1 arg2 arg2" [GenStatement "form bar arg1" [GenStatement "endform" [GenStatement "endform" []]]])
で
-- 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."
結果は、最初のBrachは常に失敗し、唯一の第二の一般的な分岐が成功しているようです。しかし、(一般的な文の解析)は、第2の分岐は、突然のフォームを解析するコメントされている場合は成功します
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" []])
を取得しますか?最初のブランチが成功したようですが、なぜ最初のブランチがうまくいかないのですか?何が欠けていますか?
事前に感謝します。ドットが(あなたがP.anyChar
を使用している)が表示されるまで、あなたのパーサgenericStatementP
が任意のの文字を解析する
作品:
と:私は次のような結果を得るため、これらの変更により
を
私はあなたが定義しなければならないと思います!どうもありがとう! – jules