Lexeme パーサ

  • 説明の順序とコードが出現する順序がごちゃごちゃで、再現させにくい…
  • digitToInt って何だ? Char.digitToInt にあった

まんま(完成品?)

module Main where

import Char
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Token( TokenParser, makeTokenParser, reservedNames, reservedOpNames )
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language( haskellStyle, haskellDef )

lexer :: TokenParser ()
lexer  = makeTokenParser 
         (haskellDef
         { reservedNames   = ["return","total"]
         , reservedOpNames = ["*","/","+","-"]
         })

whiteSpace = P.whiteSpace lexer
lexeme     = P.lexeme lexer
symbol     = P.symbol lexer
natural    = P.natural lexer
parens     = P.parens lexer
semi       = P.semi lexer
identifier = P.identifier lexer
reserved   = P.reserved lexer
reservedOp = P.reservedOp lexer

receipt :: Parser Bool
receipt = do{ ps <- many produkt
            ; p  <- total
            ; return (sum ps == p)
            }

produkt = do{ reserved "return"
            ; p <- price
            ; semi
            ; return (-p)
            }
      <|> do{ identifier
            ; p  <- price
            ; semi
            ; return p
            }
      <?> "produkt"

total   = do{ p <- price
            ; reserved "total"
            ; return p
            }

price   :: Parser Int   -- price in cents         
price   = lexeme (do{ ds1 <- many1 digit
                    ; char '.'
                    ; ds2 <- count 2 digit
                    ; return (convert 0 (ds1 ++ ds2))            
                    })
          <?> "price"
          where
            convert n []     = n
            convert n (d:ds) = convert (10*n + digitToInt d) ds

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

runLex :: Show a => Parser a -> String -> IO ()
runLex p input
        = run (do{ whiteSpace
                 ; x <- p
                 ; eof
                 ; return x
                 }) input

で、

*Main> runLex receipt "book 12.00; plant 2.55; 14.55 total"
True
*Main> runLex receipt "book 12.00; plant 2.55; 12.55 total"
False
*Main> runLex receipt "book 12.00; plant 2; 12.55 total"
parse error at (line 1, column 20):
unexpected ";"
expecting digit or "."
*Main> runLex receipt "book 12.00; return 2.00; plant 2.55; 12.55 total"
True
*Main> runLex receipt "book 12.00; reader 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; returns 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; total 2.00; plant 1.00; 15.00 total"
parse error at (line 1, column 13):
unexpected reserved word "total"
expecting produkt or price
*Main> runLex receipt "book 12.00; totals 2.00; return 1.00; 13.00 total"
True


まんま(produkt がちょっと違う、try 入り)

module Main where

import Char
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Token( TokenParser, makeTokenParser, reservedNames, reservedOpNames )
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language( haskellStyle, haskellDef )

lexer :: TokenParser ()
lexer  = makeTokenParser 
         (haskellDef
         { reservedNames   = ["return","total"]
         , reservedOpNames = ["*","/","+","-"]
         })

whiteSpace = P.whiteSpace lexer
lexeme     = P.lexeme lexer
symbol     = P.symbol lexer
natural    = P.natural lexer
parens     = P.parens lexer
semi       = P.semi lexer
identifier = P.identifier lexer
reserved   = P.reserved lexer
reservedOp = P.reservedOp lexer

receipt :: Parser Bool
receipt = do{ ps <- many produkt
            ; p  <- total
            ; return (sum ps == p)
            }

produkt = do{ try (symbol "return")
            ; p <- price
            ; semi
            ; return (-p)
            }
      <|> do{ identifier
            ; p  <- price
            ; semi
            ; return p
            }
      <?> "produkt"

total   = do{ p <- price
            ; reserved "total"
            ; return p
            }

price   :: Parser Int   -- price in cents         
price   = lexeme (do{ ds1 <- many1 digit
                    ; char '.'
                    ; ds2 <- count 2 digit
                    ; return (convert 0 (ds1 ++ ds2))            
                    })
          <?> "price"
          where
            convert n []     = n
            convert n (d:ds) = convert (10*n + digitToInt d) ds

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

runLex :: Show a => Parser a -> String -> IO ()
runLex p input
        = run (do{ whiteSpace
                 ; x <- p
                 ; eof
                 ; return x
                 }) input

で、

*Main> runLex receipt "book 12.00; plant 2.55; 14.55 total"
True
*Main> runLex receipt "book 12.00; plant 2.55; 12.55 total"
False
*Main> runLex receipt "book 12.00; plant 2; 12.55 total"
parse error at (line 1, column 20):
unexpected ";"
expecting digit or "."
*Main> runLex receipt "book 12.00; return 2.00; plant 2.55; 12.55 total"
True
*Main> runLex receipt "book 12.00; reader 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; returns 2.00; plant 1.00; 15.00 total"
parse error at (line 1, column 19):
unexpected "s"
expecting price
*Main> runLex receipt "book 12.00; total 2.00; plant 1.00; 15.00 total"
parse error at (line 1, column 13):
unexpected reserved word "total"
expecting produkt or price
*Main> runLex receipt "book 12.00; totals 2.00; return 1.00; 13.00 total"
True


まんま(lexer がちょっと違う、字句解析の時のまま)

module Main where

import Char
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Token( TokenParser, makeTokenParser, reservedOpNames )
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language( haskellStyle, haskellDef )

lexer :: TokenParser ()
lexer  = makeTokenParser 
         (haskellDef
         { reservedOpNames = ["*","/","+","-"]
         })

whiteSpace = P.whiteSpace lexer
lexeme     = P.lexeme lexer
symbol     = P.symbol lexer
natural    = P.natural lexer
parens     = P.parens lexer
semi       = P.semi lexer
identifier = P.identifier lexer
reserved   = P.reserved lexer
reservedOp = P.reservedOp lexer

receipt :: Parser Bool
receipt = do{ ps <- many produkt
            ; p  <- total
            ; return (sum ps == p)
            }

produkt = do{ reserved "return"
            ; p <- price
            ; semi
            ; return (-p)
            }
      <|> do{ identifier
            ; p  <- price
            ; semi
            ; return p
            }
      <?> "produkt"

total   = do{ p <- price
            ; reserved "total"
            ; return p
            }

price   :: Parser Int   -- price in cents         
price   = lexeme (do{ ds1 <- many1 digit
                    ; char '.'
                    ; ds2 <- count 2 digit
                    ; return (convert 0 (ds1 ++ ds2))            
                    })
          <?> "price"
          where
            convert n []     = n
            convert n (d:ds) = convert (10*n + digitToInt d) ds

run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x

runLex :: Show a => Parser a -> String -> IO ()
runLex p input
        = run (do{ whiteSpace
                 ; x <- p
                 ; eof
                 ; return x
                 }) input

で、

*Main> runLex receipt "book 12.00; plant 2.55; 14.55 total"
True
*Main> runLex receipt "book 12.00; plant 2.55; 12.55 total"
False
*Main> runLex receipt "book 12.00; plant 2; 12.55 total"
parse error at (line 1, column 20):
unexpected ";"
expecting digit or "."
*Main> runLex receipt "book 12.00; return 2.00; plant 2.55; 12.55 total"
True
*Main> runLex receipt "book 12.00; reader 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; returns 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; total 2.00; plant 1.00; 15.00 total"
True
*Main> runLex receipt "book 12.00; totals 2.00; return 1.00; 13.00 total"
True