import Control.Monad
import Text.ParserCombinators.Parsec hiding (spaces)
import System.Environment
+import Numeric
data LispVal = Atom String
| List [LispVal]
| Number Integer
| String String
| Bool Bool
+ deriving Show
symbol :: Parser Char
symbol = oneOf "!#$%&|*+-/:<=>?@^_~"
spaces = skipMany space
parseString :: Parser LispVal
-parseString = do
- char '"'
- x <- many (noneOf "\"")
- char '"'
- return $ String x
+parseString = do char '"'
+ x <- many innerChar
+ char '"'
+ return $ String x
+ where innerChar = noneOf ['\\', '\"'] <|> escapeChar
+ escapeChar = do char '\\'
+ c <- oneOf ['\"', '\\', 'n', 'r', 't', 'f']
+ return $ case c of
+ '\"' -> '\"'
+ '\\' -> '\\'
+ 'n' -> '\n'
+ 'r' -> '\r'
+ 't' -> '\t'
+ 'f' -> '\f'
parseAtom :: Parser LispVal
parseAtom = do
_ -> Atom atom
parseNumber :: Parser LispVal
-parseNumber = liftM (Number . read) $ many1 digit
+parseNumber = do toNum <- radix
+ ds <- many1 digit
+ let ((a,_):_) = toNum ds
+ return $ Number a
+ where radix = do r <- try (char '#' >> oneOf "bodx") <|> return 'd'
+ return $ case r of
+ 'd' -> readDec
+ 'x' -> readHex
+ 'o' -> readOct
+ 'b' -> readInt 2 (\x -> elem x "01") (read . (:[]))
+
+parseExpr :: Parser LispVal
+parseExpr = parseString
+ <|> parseNumber
+ <|> parseAtom
readExpr :: String -> String
-readExpr input = case parse (spaces >> symbol) "lisp" input of
+readExpr input = case parse parseExpr "lisp" input of
Left err -> "No match: " ++ show err
- Right val -> "Found value"
+ Right val -> "Found value: " ++ show val
main :: IO ()
main = do
args <- getLine
putStrLn (readExpr args)
+ main