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

小数で

module Main where

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

lexer  :: TokenParser ()
lexer   = makeTokenParser(haskellDef)

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


calc  = parseTest expr

expr  = expr1
expr1 = chainl1 expr2 addop
expr2 = chainl1 expr3 mulop
expr3 =     neg
        <|> chainr1 prim  powerop
prim  =     parens expr
        <|> try float
        <|> do { x <- integer; return (fromIntegral x) }


addop   =   do { symbol "+"; return (+) }
        <|> do { symbol "-"; return (-) }

mulop   =   do { symbol "*"; return (*)   }
        <|> do { symbol "/"; return (/) }

neg     =   do { symbol "-"; x <- expr3; return (-x) }

powerop =   do { symbol "^"; return (**) }

で、

*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"
0.0
*Main> calc "4 + 4.5 - (34/(8*3+-3))"
6.880952380952381
*Main> calc "-10/3"
-3.3333333333333335