mirror of
https://github.com/osmarks/random-stuff
synced 2024-12-26 18:10:34 +00:00
101 lines
3.0 KiB
Forth
Executable File
101 lines
3.0 KiB
Forth
Executable File
open System
|
|
open System.Numerics
|
|
|
|
type Stack = StackContents of Complex list
|
|
|
|
let splitPart (what:char) index (stringIn:string) = stringIn.Split(what).[index]
|
|
let spliti = splitPart 'i'
|
|
let firstInSpliti = spliti 0
|
|
let secondInSpliti = spliti 1
|
|
let isDoubleAsString text = System.Double.TryParse text |> fst
|
|
let doubleFromString text = System.Double.TryParse text |> snd
|
|
let isImaginaryAsString (text:string) =
|
|
match text.Contains("i") with
|
|
| false -> false
|
|
| true ->
|
|
let normalPart = firstInSpliti text
|
|
isDoubleAsString normalPart
|
|
let imaginaryFromString text =
|
|
let imaginaryPart = doubleFromString (firstInSpliti text)
|
|
Complex(0.0, imaginaryPart)
|
|
|
|
let showStack (StackContents contents) =
|
|
printfn "%A" contents // Print unpacked StackContents with formatting string
|
|
StackContents (contents) // Repack the StackContents
|
|
|
|
let push value (StackContents contents) =
|
|
StackContents (value::contents)
|
|
|
|
let pop (StackContents contents) =
|
|
match contents with
|
|
| top::rest -> // Separate top from rest
|
|
(top, StackContents rest) // Stack contents must be the StackContents type.
|
|
| [] -> // Check for stack underflow
|
|
failwith "Stack underflow"
|
|
|
|
let binary func stack =
|
|
let x, newStack = pop stack
|
|
let y, newestStack = pop newStack
|
|
let z = func y x // This is deliberately swapped, because we are working on a stack
|
|
push z newestStack
|
|
|
|
let unary func stack =
|
|
let x, newStack = pop stack
|
|
push (func x) stack
|
|
|
|
let dup stack =
|
|
let x, _ = pop stack // Drop the new stack, we want to duplicate "x"
|
|
push x stack
|
|
|
|
let swap stack =
|
|
let x, newStack = pop stack
|
|
let y, newerStack = pop newStack
|
|
push y (push x newerStack)
|
|
|
|
let drop stack =
|
|
let _, newStack = pop stack // Pop one off the top and ignore it
|
|
newStack
|
|
|
|
let numberInput value stack = push value stack
|
|
|
|
let add = binary (+)
|
|
let multiply = binary (*)
|
|
let subtract = binary (-)
|
|
let divide = binary (/)
|
|
let negate = unary (fun x -> -(x))
|
|
let square = unary (fun x -> x * x)
|
|
let cube = dup >> dup >> multiply >> multiply
|
|
let exponent = binary ( ** )
|
|
|
|
let show stack =
|
|
let value, _ = pop(stack)
|
|
printfn "%A" value
|
|
stack // We're going to keep the same stack as before.
|
|
|
|
let empty = StackContents []
|
|
|
|
let splitString (text:string) = text.Split ' '
|
|
|
|
let processTokenString stack token =
|
|
match token with
|
|
| "*" -> stack |> multiply
|
|
| "+" -> stack |> add
|
|
| "/" -> stack |> divide
|
|
| "+-" -> stack |> negate
|
|
| "sqr" -> stack |> square
|
|
| "cub" -> stack |> cube
|
|
| "**" | "^" -> stack |> exponent
|
|
| _ when isDoubleAsString token ->
|
|
let doubleInString = doubleFromString token
|
|
numberInput (Complex(doubleInString, 0.0)) stack
|
|
| _ when isImaginaryAsString token ->
|
|
let imaginaryInString = imaginaryFromString token
|
|
numberInput imaginaryInString stack
|
|
| _ -> showStack stack // For easier debugging.
|
|
|
|
Console.Write("Please enter your expression here: ")
|
|
let userExpression = Console.ReadLine()
|
|
let splitExpression = splitString userExpression
|
|
|
|
let resultantStack = List.fold processTokenString (empty) (Array.toList splitExpression) |> showStack
|