They both share a common prototype so we can split that out into a
separate definition. We also want to be able to parse top level
expressions, so we add constructor for that in AST.
Hopefully now you can see the beauty of monadic parsing:
Function <$> readPrec <*> readPrec
import Text.Read
import Text.ParserCombinators.ReadP hiding ((+++), choice)
import Text.Read
import Text.ParserCombinators.ReadP hiding ((+++), choice)
]
where parseNum = Num <$> readPrec
parseVar = Var <$> lift (munch1 isAlpha)
]
where parseNum = Num <$> readPrec
parseVar = Var <$> lift (munch1 isAlpha)
- -- use 'prec 1' and 'step' so that parsing 'a'
- -- can only go one step deep, to prevent ininfite
- -- recursion
parseBinOp s prc op = prec prc $ do
a <- step readPrec
lift $ do
parseBinOp s prc op = prec prc $ do
a <- step readPrec
lift $ do
b <- readPrec
return (BinOp op a b)
b <- readPrec
return (BinOp op a b)
+data Prototype = Prototype String [String]
+ deriving Show
+
+instance Read Prototype where
+ readPrec = lift $ do
+ name <- munch1 isAlpha
+ params <- between (char '(') (char ')') $
+ sepBy (munch1 isAlpha) skipSpaces
+ return (Prototype name params)
+
+data AST = Function Prototype Expr
+ | Extern Prototype
+ | TopLevelExpr Expr
+ deriving Show
+
+instance Read AST where
+ readPrec = parseFunction +++ parseExtern +++ parseTopLevel
+ where parseFunction = do
+ lift $ string "def" >> skipSpaces
+ Function <$> readPrec <*> readPrec
+ parseExtern = do
+ lift $ string "extern" >> skipSpaces
+ Extern <$> readPrec
+ parseTopLevel = TopLevelExpr <$> readPrec