Created
April 15, 2017 15:09
-
-
Save Pan-Maciek/c42a0924f37b779d9545e73fdff40b3f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Eval | |
open System | |
type Operator = | |
| Add | |
| Subtract | |
| Multiply | |
| Divide | |
type token = | |
| Number of Double | |
| OpenBracket | |
| CloseBracket | |
| Operator of Operator | |
let tokenize i = | |
let rec tokenize s = | |
match s with | |
| [] -> [] | |
| ' ' :: tail -> tokenize tail | |
| '(' :: tail -> OpenBracket :: tokenize tail | |
| ')' :: tail -> CloseBracket :: tokenize tail | |
| '+' :: tail -> Operator Add :: tokenize tail | |
| '-' :: tail -> Operator Subtract :: tokenize tail | |
| '*' :: tail -> Operator Multiply :: tokenize tail | |
| '/' :: tail -> Operator Divide :: tokenize tail | |
| c :: tail when Char.IsDigit(c) || c = ',' || c = '.' -> | |
let rec doubleToValue s acc = | |
match s with | |
| c :: tail when Char.IsDigit(c) || c = ',' || c = '.' -> doubleToValue tail (c :: acc) | |
| _ -> | |
match acc with | |
| ',' :: _ -> (Number (Double.Parse (String.Concat (Seq.rev acc) + "0")), s) | |
| _ -> (Number (Double.Parse (String.Concat (Seq.rev acc))), s) | |
let (token, t) = doubleToValue tail [c] | |
token :: tokenize t | |
| n :: _ -> failwith ("Parse error - invalid character detected: " + n.ToString()) | |
tokenize (Seq.toList i) | |
let evalTokens input = | |
let eval a b op = | |
match op with | |
| Operator Add -> b + a | |
| Operator Subtract -> b - a | |
| Operator Multiply -> b * a | |
| Operator Divide -> b / a | |
| _ -> failwith "unexpected operator" | |
let pop (stack:'a list) = (stack.Head, stack.Tail.Head, stack.Tail.Tail) | |
let rec eval_rec input numstack (opstack:token list) = | |
match input with | |
| Number n :: tail -> eval_rec tail (n::numstack) opstack | |
| Operator o :: tail -> | |
if opstack.Length <> 0 && opstack.Head > (Operator o) then | |
let firstNum, secondNum, numstackRem = pop numstack | |
let e = eval firstNum secondNum opstack.Head | |
eval_rec tail (e::numstackRem) (Operator o::opstack.Tail) | |
else | |
eval_rec tail numstack (Operator o::opstack) | |
| OpenBracket :: tail -> eval_rec tail numstack (OpenBracket::opstack) | |
| CloseBracket :: tail -> | |
match opstack with | |
| Operator op :: opTail -> | |
let firstNum, secondNum, numstackRem = pop numstack | |
let e = eval firstNum secondNum (Operator op) | |
eval_rec input (e::numstackRem) opTail | |
| OpenBracket :: _ -> | |
eval_rec tail numstack opstack.Tail | |
| _ -> failwith "error parsing input" | |
| [] -> | |
match opstack with | |
| Operator op :: tail -> | |
let firstNum, secondNum, numstackRem = pop numstack | |
let e = eval firstNum secondNum (Operator op) | |
eval_rec [] (e::numstackRem) tail | |
| [] -> numstack.Head | |
| _ -> failwith "error parsing input" | |
eval_rec input [] [] | |
let eval input = evalTokens (tokenize input) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment