-- calc3.y -*- mode: haskell -*- { module Main where import Data.Char (isSpace, isDigit, isAlpha, isAlphaNum) import Data.Maybe (fromMaybe) } %name calc %tokentype { Token } %error { parseError } %token let { TokenLet } in { TokenIn } int { TokenInt $$ } var { TokenVar $$ } '=' { TokenEq } '+' { TokenPlus } '-' { TokenMinus } '*' { TokenTimes } '/' { TokenDiv } '(' { TokenLP } ')' { TokenRP } %nonassoc in %left '+' '-' %left '*' '/' %left NEG %% Exp : let var '=' Exp in Exp { \env -> $6 (($2,$4 env) : env) } | Exp '+' Exp { \env -> $1 env + $3 env } | Exp '-' Exp { \env -> $1 env - $3 env } | Exp '*' Exp { \env -> $1 env * $3 env } | Exp '/' Exp { \env -> $1 env `div` $3 env } | '(' Exp ')' { $2 } | '-' Exp %prec NEG { \env -> - ($2 env) } | int { \env -> $1 } | var { \env -> fromMaybe 0 (lookup $1 env) } { parseError :: [Token] -> a parseError _ = error "Parse error" data Token = TokenLet | TokenIn | TokenInt Int | TokenVar String | TokenEq | TokenPlus | TokenMinus | TokenTimes | TokenDiv | TokenLP | TokenRP deriving (Show) lexer :: String -> [Token] lexer [] = [] lexer (c:cs) | isSpace c = lexer cs | isAlpha c = let (name,rest) = span isAlphaNum cs tok = case c:name of "let" -> TokenLet "in" -> TokenIn var -> TokenVar var in tok : lexer rest | isDigit c = let (num,rest) = span isDigit cs in TokenInt (read (c:num)) : lexer rest lexer ('=':cs) = TokenEq : lexer cs lexer ('+':cs) = TokenPlus : lexer cs lexer ('-':cs) = TokenMinus : lexer cs lexer ('*':cs) = TokenTimes : lexer cs lexer ('/':cs) = TokenDiv : lexer cs lexer ('(':cs) = TokenLP : lexer cs lexer (')':cs) = TokenRP : lexer cs main = do input <- getContents mapM_ print (map (($ []) . calc . lexer) (lines input)) }