| 1 | data Op = Op String Prec Fixity deriving Eq |
|---|
| 2 | data Fixity = Leftfix | Rightfix | Nonfix deriving Eq |
|---|
| 3 | data Exp = Var Var | OpApp Exp Op Exp deriving Eq |
|---|
| 4 | type Prec = Int |
|---|
| 5 | type Var = String |
|---|
| 6 | |
|---|
| 7 | data Tok = TVar Var | TOp Op |
|---|
| 8 | |
|---|
| 9 | parse :: [Tok] -> Exp |
|---|
| 10 | parse (TVar x : rest) = fst (parse1 (Var x) (-1) Nonfix rest) |
|---|
| 11 | |
|---|
| 12 | parse1 :: Exp -> Int -> Fixity -> [Tok] -> (Exp, [Tok]) |
|---|
| 13 | parse1 e p f [] = (e, []) |
|---|
| 14 | parse1 e p f inp@(TOp op@(Op _ p' f') : TVar x : rest) |
|---|
| 15 | | p' == p && (f /= f' || f == Nonfix) |
|---|
| 16 | = error "ambiguous infix expression" |
|---|
| 17 | | p' < p || p' == p && (f == Leftfix || f' == Nonfix) |
|---|
| 18 | = (e, inp) |
|---|
| 19 | | otherwise |
|---|
| 20 | = let (r,rest') = parse1 (Var x) p' f' rest in |
|---|
| 21 | parse1 (OpApp e op r) p f rest' |
|---|
| 22 | |
|---|
| 23 | -- Printing |
|---|
| 24 | |
|---|
| 25 | instance Show Exp where |
|---|
| 26 | showsPrec _ (Var x) = showString x |
|---|
| 27 | showsPrec p e@(OpApp l (Op op _ _) r) = |
|---|
| 28 | showParen (p > 0) $ showsPrec 9 l . showString op . showsPrec 9 r |
|---|
| 29 | |
|---|
| 30 | -- Testing |
|---|
| 31 | |
|---|
| 32 | plus = TOp (Op "+" 6 Leftfix) |
|---|
| 33 | times = TOp (Op "*" 7 Leftfix) |
|---|
| 34 | divide = TOp (Op "/" 7 Leftfix) |
|---|
| 35 | gt = TOp (Op ">" 4 Nonfix) |
|---|
| 36 | ex = TOp (Op "^" 8 Rightfix) |
|---|
| 37 | |
|---|
| 38 | lookupop '+' = plus |
|---|
| 39 | lookupop '*' = times |
|---|
| 40 | lookupop '/' = divide |
|---|
| 41 | lookupop '>' = gt |
|---|
| 42 | lookupop '^' = ex |
|---|
| 43 | |
|---|
| 44 | fromstr [x] = [TVar [x]] |
|---|
| 45 | fromstr (x:y:z) = TVar [x] : lookupop y : fromstr z |
|---|
| 46 | |
|---|
| 47 | test1 = fromstr "a+b+c" |
|---|
| 48 | test2 = fromstr "a+b+c*d" |
|---|
| 49 | test3 = fromstr "a/b/c" |
|---|
| 50 | test4 = fromstr "a/b+c" |
|---|
| 51 | test5 = fromstr "a/b*c" |
|---|
| 52 | test6 = fromstr "1^2^3+4" |
|---|
| 53 | test7 = fromstr "a/1^2^3" |
|---|
| 54 | test8 = fromstr "a*b/c" |
|---|