- The fun way
ghci Main.hs letsGo
- The other way
ghci Main.hs emulate "your Fun code"
- The hard way (*see at the bottom of the ReadMe)
We made four adjustments to the F syntax:
-
We decided to interchange the semicolons between multiple
Local Definitions
with commas because we wanted semicolons to be used exclusively between multipleDefinitions
(for better readability). -
According to the script the precedence of the negation should be lower than the precedence of an addition. This would lead to
-5 + 2
being evaluated as-7
. We wanted our syntax to be more intuitive so we changed the precedences to let-5 + 2
be evaluated as-3
. -
As opposed to the script we allow inputs of the form
A-B-C
andA/B/C
by implementing a left associativity for-
and/
. -
We also implemented exponential expressions. Only integers are allowed as exponents.
The Main module is the interface for our entire implementation. It imports all of the modules below. You can either call the modules' functions directly or call letsGo
for a fun and interactive experience of Fun!
Each module provides a function
and a showFunction
. When other modules want to continue processing the result of a different module they always call function
, never showFunction
. The only purpose of showFunction
is to create a nice, more comprehensive output of an intermediate result.
-
takes a
String
(your Fun program) as input, splits it up intoTokens
and returns them in a list.
-
takes a
String
(your Fun program) as input, callstokenize
on it and converts the list ofTokens
into an AST (abstract syntax tree) withExpressions
as nodes and leaves. -
creates an output that is easier to comprehend than the output of
parse
. It lists allDefinitions
with their arguments and represents the AST structure of the function body with parentheses.For example
showParse "main = cool 1; cool x = 10*x;"
creates the following output:Definition main [] (Function (Variable "cool") (Val 1)) Definition cool ["x"] (Mult (Val 10) (Variable "x"))
-
takes a
String
(your Fun program) as input, callsparse
on it and converts the AST into a list ofInstructions
. This list is appended toinitCode
which contains theInstructions
that call themain
function, ensure the termination of the code and enable the emulation of unary, binary and ifExpressions
.compile
also initializesHeap
,Global
,PC
andStack
:pc = 0 code = initCode ++ [Instruction] stack = [] heap = [DEF name arity codeAddress] global = [(name, heapAddress)]
Heap
is initialized withDEF
cells which consist of the name, arity and code address of each function. TheGlobal
environment contains the function names and correspondingHeap
addresses of thoseDEF
cells.These five sets of data are returned as a
State
:State pc code stack heap global
-
provides a better visualization of the initial
State
. It only showsInstructions
,Heap
andGlobal
.
-
takes a
String
(your Fun program) as input, callscompile
on it and uses theState
as input forrun
which emulates theInstructions
step by step and changesPC
,Stack
andHeap
accordingly. It is a recursive function which overwrites the oldState
after eachInstruction
is processed. The finalState
contains the result of the emulation and is returned toemulate
which unpacks the result and returns it. -
visualizes
emulate
by showing each state of the emulation process. In order to do that, it needs to know how theState
looked after eachInstruction
but run doesn't provide this information. So it callsshowRun
which doesn't overwrite the oldState
, but rather appends each newState
to a list in a recursive manner.
- letsGo function
- monadic error handling
- console output of
showFunctions
- associativity of
-
and/
- exponential functions
- it works
- it's Fun!
*3. The hard way
-- myProgram.hs
import Tokenizer
import Parser
import Compiler
import Emulator
import Datatypes
example = showTokenize "your Fun code"
ghci myProgram.hs
example