bison マニュアルの中間記法電卓

Parsec.Expr を使用

module Main where

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

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

symbol     = P.symbol     lexer
parens     = P.parens     lexer
integer    = P.integer    lexer
float      = P.float      lexer
reservedOp = P.reservedOp lexer


calc  = parseTest expr

expr  = expr1
expr1 = buildExpressionParser table prim
prim  =     parens expr
        <|> try float
        <|> do { x <- integer; return (fromIntegral x) }


table   = [[op    "^" (**)   AssocRight]
          ,[preop "-" negate]
          ,[op    "*" (*)    AssocLeft,  op "/" (/) AssocLeft]
          ,[op    "+" (+)    AssocLeft,  op "-" (-) AssocLeft]
          ]
        where
          op s f assoc
            = Infix  (do { reservedOp s; return f } <?> "operator") assoc
          preop s f
            = Prefix (do { reservedOp s; return f } <?> "operator")

で、

*Main> calc "1+2"
Loading package parsec-2.0 ... linking ... done.
3.0
*Main> calc "1-2"
-1.0
*Main> calc "2*3"
6.0
*Main> calc "10/3"
3.3333333333333335
*Main> calc "-56+2"
-54.0
*Main> calc "-2 ^ 2"
-4.0
*Main> calc "2^2^3"
256.0
*Main> calc "-(1+2*3)"
-7.0
*Main> calc "1+-1"
1.0
*Main> calc "1+ -1"
0.0

なぜか一部うまく動作しない