File: Example.hs

package info (click to toggle)
haskell-uulib 0.9.15-2
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 332 kB
  • sloc: haskell: 2,751; makefile: 8
file content (84 lines) | stat: -rw-r--r-- 2,154 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
module Main where

-- import the the library functions from uulib
import UU.Parsing
import UU.Scanner

-- import our custom made Alex-scanner
import Scanner


-- Some boilerplate code to use the parser
-- Give `parsetokens' your parser and a list of tokens, returned by the `scanTokens'
-- function exported by the Scanner module, then you get either a list of error
-- messages in case of a parse error, or the parse tree.
type TokenParser a = Parser Token a

parseTokens :: TokenParser a -> [Token] -> Either [String] a
parseTokens p tks
  = if null msgs
    then final `seq` Right v
    else Left (map show msgs)
  where
    steps = parse p tks
    msgs  = getMsgs steps
    (Pair v final) = evalSteps steps


-- define a parse tree
data Expr
  = Identifier String
  | Integer Int
  | String String
  | Plus Expr Expr
  | Times Expr Expr
  | Let String  -- variable
        Expr    --   = expr
        Expr    -- body
  deriving Show


-- write a parser for it
-- Note: * make sure that the parser is not left recursive
--           (to the left is never a pExpr, or always a terminal first)
--       * make sure that the parser is not ambiguous
--           (by introducing priority levels for the operators)


-- Term -> let var = Expr in Expr
pExpr :: TokenParser Expr
pExpr
  =   (\_ x _ e _ b -> Let x e b) <$> pKey "let" <*> pVarid <*> pKey "=" <*> pExpr <*> pKey "in" <*> pExpr
  <|> pMult

-- Expr -> Factor | Factor * Expr
pMult :: TokenParser Expr
pMult
  =   pFactor 
  <|> (\l _ r -> Times l r) <$> pFactor <*> pKey "*" <*> pExpr

-- Factor -> Term | Term * Factor
pFactor :: TokenParser Expr
pFactor
  =   pTerm
  <|> (\l _ r -> Plus l r) <$> pTerm <*> pKey "+" <*> pFactor

-- Term -> var
-- Term -> String
-- Term -> Int
-- Term -> (Expr)
pTerm :: TokenParser Expr
pTerm
  =   Identifier <$> pVarid
  <|> (Integer . read) <$> pInteger16
  <|> (String  . read) <$> pString
  <|> (\_ e _ -> e) <$> pKey "(" <*> pExpr <*> pKey ")"


-- test it
main :: IO ()
main
  = let res = parseTokens pExpr (tokenize "nofile" "let x = 3 in x+x")
    in case res of
         Left errs -> mapM_ putStrLn errs
         Right tree -> putStrLn $ show tree