2017-10-14 10 views
3

私は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任意のの文字を解析する

答えて

2

は私のために検索します。したがって、あなたのレクサーのために予約されたキーワードは認識されません。魔法のように

Right (Form "foo" ["arg1","arg2","arg2"] [Form "bar" ["arg1"] []]) 
+0

作品:

type Args = [String] 

と:私は次のような結果を得るため、これらの変更により

argsP :: S.Parser [String] argsP = P.manyTill identifier (P.try (P.lookAhead dot)) genericStatementP :: S.Parser String genericStatementP = identifier 

私はあなたが定義しなければならないと思います!どうもありがとう! – jules

関連する問題