-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlecture12.lhs
96 lines (65 loc) · 1.91 KB
/
lecture12.lhs
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
85
86
87
88
89
90
91
92
93
94
95
96
> module Lecture12 where
> import Text.Yoda
> import Data.Char
Let's start with a left-recursive grammar:
expr = term | expr "+" term
term = fact | term "*" fact
fact = numb | "(" expr ")"
numb = "0" | "1" | "2"
We must remove the left recursion by applying Paull's modified
algorithm:
expr = term expr'
expr' = "+" term expr'
| epsilon
term = fact term'
term' = "*" fact term' | epsilon
fact = numb | "(" expr ")"
numb = "0" | "1" | "2"
The other rules remain the same.
We now make datatypes that correspond to these rules.
Each nonterminal corresponds to a new datatype. The alternations
correspond to constructors for that type.
> data Expr = ExprTerm Term Expr'
> deriving Show
> expr :: Parser Expr
> expr = ExprTerm <$> term <*> expr'
expr' = "+" term expr'
| epsilon
> data Expr' = Expr'Add Term Expr'
> | Expr'Emp
> deriving Show
> expr' :: Parser Expr'
> expr' = Expr'Add <$ char '+' <*> term <*> expr'
> <|> Expr'Emp <$ unit
term = fact term'
> data Term = TermFact Fact Term'
> deriving Show
> term :: Parser Term
> term = TermFact <$> fact <*> term'
term' = "*" fact term'
| epsilon
> data Term' = Term'Mul Fact Term'
> | Term'Emp
> deriving Show
> term' :: Parser Term'
> term' = Term'Mul <$ char '*' <*> fact <*> term'
> <|> Term'Emp <$ unit
fact = numb
| "(" expr ")"
> data Fact = FactNumb Int
> | FactPar Expr
> deriving Show
> fact = FactNumb <$> numb
> <|> FactPar <$ char '(' <*> expr <* char ')'
numb = "0" | "1" | "2"
> numb :: Parser Int
> numb = read <$> digits
> digit :: Parser Char
> digit = satisfy isDigit
> digits :: Parser String
> digits = cull (some digit)
Now we can test this with statements such as:
parse (expr) "(3+2)*45"
It is possible to remove spurious results by applying `eof` at the
end:
parse (expr <* eof) "(3+2)*45"