Skip to content

Instantly share code, notes, and snippets.

@Pan-Maciek
Created April 15, 2017 15:09
Show Gist options
  • Save Pan-Maciek/c42a0924f37b779d9545e73fdff40b3f to your computer and use it in GitHub Desktop.
Save Pan-Maciek/c42a0924f37b779d9545e73fdff40b3f to your computer and use it in GitHub Desktop.
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