2016-05-30 4 views
0

私はそれをしようと理解して、私はfoo (x) = 1を解析することができますが、私はfoo x = 1強制的にすべてのオプションをバックトラックできますか?

parseExpr "foo x = 1" 
Left (line 1, column 10): 
unexpected end of input 
expecting digit, "," or "=" 

を解析することはできません。このパーサ

module SimpleParser where 
import Text.Parsec.String (Parser) 
import Text.Parsec.Language (emptyDef) 
import Text.Parsec 
import qualified Text.Parsec.Token as Tok 
import Text.Parsec.Char 
import Prelude 

lexer :: Tok.TokenParser() 
lexer = Tok.makeTokenParser style 
    where 
    style = emptyDef { 
       Tok.identLetter = alphaNum 
      } 

parens :: Parser a -> Parser a 
parens = Tok.parens lexer 

commaSep :: Parser a -> Parser [a] 
commaSep = Tok.commaSep1 lexer 

commaSep1 :: Parser a -> Parser [a] 
commaSep1 = Tok.commaSep1 lexer 


identifier :: Parser String 
identifier = Tok.identifier lexer 

reservedOp :: String -> Parser() 
reservedOp = Tok.reservedOp lexer 

data Expr = IntLit Int | Ident String | Label String Expr | Func String Expr Expr | ExprList [Expr] deriving (Eq, Ord, Show) 


integer :: Parser Integer 
integer = Tok.integer lexer 

litInt :: Parser Expr 
litInt = do 
    n <- integer 
    return $ IntLit (fromInteger n) 

ident :: Parser Expr 
ident = Ident <$> identifier 

paramLabelItem = litInt <|> paramLabel 

paramLabel :: Parser Expr 
paramLabel = do 
    lbl <- try (identifier <* reservedOp "=") 
    body <- paramLabelItem 
    return $ Label lbl body 

paramItem :: Parser Expr 
paramItem = parens paramRecord <|> litInt <|> try paramLabel <|> ident 

paramRecord :: Parser Expr 
paramRecord = ExprList <$> commaSep1 paramItem 

func :: Parser Expr 
func = do 
    name <- identifier 
    params <- paramRecord 
    reservedOp "=" 
    body <- paramRecord 
    return $ (Func name params body) 


parseExpr :: String -> Either ParseError Expr 
parseExpr s = parse func "" s 

を書かれている関数宣言

foo x = 1 
Func "foo" (Ident "x") = 1 

foo (x = 1) = 1 
Func "foo" (Label "x" 1) = 1 

foo x = y = 1 
Func "foo" (Ident "x") = (Label "y" 1) 

ために、この構文を解析する必要がありますこのコードをFunc "foo" (Label "x" 1)のように解析して失敗します。しかし、なぜそれがそれを解析しようとすることはできませんなぜ失敗した後Func "foo" (Ident "x") = 1

それを行う方法はありますか?また、私は私がfoo x = 1を解析することができますが、私はここでfoo (x = 1) = 2

parseExpr "foo (x = 1) = 2" 
Left (line 1, column 8): 
unexpected "=" 
expecting "," or ")" 

答えて

1

を解析することはできません。この場合、identparamLabel

paramItem = parens paramRecord <|> litInt <|> try paramLabel <|> ident 
paramItem = parens paramRecord <|> litInt <|> try ident <|> paramLabel 

を交換しようとしてい

は(私はParsecのは、作品をバックトラックを理解する方法で、動作しません):

In:

(try a <|> try b <|> c) 

aが失敗した場合、bが試されます、そしてbがその後失敗した場合cが試行されます。

しかし、中:aが成功してd失敗した場合

(try a <|> try b <|> c) >> d 

、Parsecのはは戻ってbをしようとしません。 aが成功すると、Parsecは全体の選択肢を解析して考慮し、dに移動します。それはbまたはcを試みることは決してありません。これは、同じ理由でいずれかの動作しません

aまたはb成功すると

(try (try a <|> try b <|> c)) >> d 

を、全体の選択は成功し、その外側tryは成功します。その後、解析はdに進みます。

ソリューションは、選択範囲内にdを配布することです:aが成功してd失敗した場合

try (a >> d) <|> try (b >> d) <|> (c >> d) 

は今、b >> dが試行されます。

関連する問題