symbolic mathematics engine in OCaml with differentiation, integration, simplification, and numerical methods
17

Configure Feed

Select the types of activity you want to include in your feed.

leibniz / lib / parser.ml
5.7 kB 223 lines
1open Lexer 2open Expr 3 4exception Parse_error of string * position 5 6type parse_state = { tokens : token_with_pos list; mutable pos : int } 7 8let token_name = function 9 | Num _ -> "number" 10 | Var _ -> "variable" 11 | Ident _ -> "identifier" 12 | Plus -> "'+'" 13 | Minus -> "'-'" 14 | Star -> "'*'" 15 | Slash -> "'/'" 16 | Caret -> "'^'" 17 | LParen -> "'('" 18 | RParen -> "')'" 19 | Comma -> "','" 20 | EOF -> "end of input" 21 22let peek state = 23 if state.pos < List.length state.tokens then 24 (List.nth state.tokens state.pos).token 25 else EOF 26 27let peek_pos state = 28 if state.pos < List.length state.tokens then 29 (List.nth state.tokens state.pos).start_pos 30 else 31 { line = 0; col = 0; offset = 0 } 32 33let advance state = 34 state.pos <- state.pos + 1 35 36let expect state tok = 37 if peek state = tok then advance state 38 else 39 let pos = peek_pos state in 40 raise (Parse_error ( 41 Printf.sprintf "expected %s but found %s at line %d, column %d" 42 (token_name tok) (token_name (peek state)) pos.line pos.col, 43 pos)) 44 45let rec parse_expr state = 46 parse_additive state 47 48and parse_additive state = 49 let left = ref (parse_multiplicative state) in 50 while peek state = Plus || peek state = Minus do 51 let op = peek state in 52 advance state; 53 let right = parse_multiplicative state in 54 left := if op = Plus then Add (!left, right) else Sub (!left, right) 55 done; 56 !left 57 58and parse_multiplicative state = 59 let left = ref (parse_power state) in 60 while peek state = Star || peek state = Slash do 61 let op = peek state in 62 advance state; 63 let right = parse_power state in 64 left := if op = Star then Mul (!left, right) else Div (!left, right) 65 done; 66 !left 67 68and parse_power state = 69 let left = parse_unary state in 70 if peek state = Caret then begin 71 advance state; 72 let right = parse_power state in 73 match left with 74 | Var "e" -> Exp right 75 | _ -> Pow (left, right) 76 end else left 77 78and parse_unary state = 79 match peek state with 80 | Minus -> 81 advance state; 82 Neg (parse_unary state) 83 | _ -> parse_primary state 84 85and parse_primary state = 86 match peek state with 87 | Num n -> 88 advance state; 89 Const n 90 | Var v -> 91 advance state; 92 (match v with 93 | "pi" | "π" -> SymConst Pi 94 | "e" -> SymConst E 95 | _ -> Var v) 96 | Ident "sin" -> 97 advance state; 98 expect state LParen; 99 let arg = parse_expr state in 100 expect state RParen; 101 Sin arg 102 | Ident "cos" -> 103 advance state; 104 expect state LParen; 105 let arg = parse_expr state in 106 expect state RParen; 107 Cos arg 108 | Ident "tan" -> 109 advance state; 110 expect state LParen; 111 let arg = parse_expr state in 112 expect state RParen; 113 Tan arg 114 | Ident "sinh" -> 115 advance state; 116 expect state LParen; 117 let arg = parse_expr state in 118 expect state RParen; 119 Sinh arg 120 | Ident "cosh" -> 121 advance state; 122 expect state LParen; 123 let arg = parse_expr state in 124 expect state RParen; 125 Cosh arg 126 | Ident "tanh" -> 127 advance state; 128 expect state LParen; 129 let arg = parse_expr state in 130 expect state RParen; 131 Tanh arg 132 | Ident "asin" | Ident "arcsin" -> 133 advance state; 134 expect state LParen; 135 let arg = parse_expr state in 136 expect state RParen; 137 Asin arg 138 | Ident "acos" | Ident "arccos" -> 139 advance state; 140 expect state LParen; 141 let arg = parse_expr state in 142 expect state RParen; 143 Acos arg 144 | Ident "atan" | Ident "arctan" -> 145 advance state; 146 expect state LParen; 147 let arg = parse_expr state in 148 expect state RParen; 149 Atan arg 150 | Ident "atan2" -> 151 advance state; 152 expect state LParen; 153 let arg1 = parse_expr state in 154 expect state Comma; 155 let arg2 = parse_expr state in 156 expect state RParen; 157 Atan2 (arg1, arg2) 158 | Ident "exp" -> 159 advance state; 160 expect state LParen; 161 let arg = parse_expr state in 162 expect state RParen; 163 Exp arg 164 | Ident "ln" | Ident "log" -> 165 advance state; 166 expect state LParen; 167 let arg1 = parse_expr state in 168 (match peek state with 169 | Comma -> 170 advance state; 171 let arg2 = parse_expr state in 172 expect state RParen; 173 Log (arg1, arg2) 174 | RParen -> 175 advance state; 176 Ln arg1 177 | _ -> 178 let pos = peek_pos state in 179 raise (Parse_error ( 180 Printf.sprintf "expected ',' or ')' in log function at line %d, column %d" 181 pos.line pos.col, 182 pos))) 183 | Ident "sqrt" -> 184 advance state; 185 expect state LParen; 186 let arg = parse_expr state in 187 expect state RParen; 188 Sqrt arg 189 | Ident "abs" -> 190 advance state; 191 expect state LParen; 192 let arg = parse_expr state in 193 expect state RParen; 194 Abs arg 195 | LParen -> 196 advance state; 197 let expr = parse_expr state in 198 expect state RParen; 199 expr 200 | _ -> 201 let pos = peek_pos state in 202 raise (Parse_error ( 203 Printf.sprintf "unexpected %s at line %d, column %d" 204 (token_name (peek state)) pos.line pos.col, 205 pos)) 206 207let parse str = 208 try 209 let tokens = tokenize str in 210 let state = { tokens; pos = 0 } in 211 let expr = parse_expr state in 212 if peek state = EOF then expr 213 else 214 let pos = peek_pos state in 215 raise (Parse_error ( 216 Printf.sprintf "unexpected tokens after expression at line %d, column %d" 217 pos.line pos.col, 218 pos)) 219 with 220 | Parse_error (msg, _) -> 221 failwith msg 222 | Failure msg -> 223 failwith msg