The MABWA Project

The goal of the MABWA Project is to produce an implementation of PyFL that is much faster than the current lazy interpreter, which repeatedly decodes the expression tree. The current interpreter produces Basic PyFL, with all the advanced features (like while loops) implemented by translation. Our strategy is to translate Basic PyFL into the machine language for a FORTH-like stack-based abstract machine.


The MABWA Machine [+]

The MABWA machine has a conventional FORTH-like design, with a reverse polish instruction language. To add 2 and 3 you push 2 then 3 on the implicit value stack, then execute the add instruction that pops the top two elements of the stack, adds them, then pushes the result on the stack.


Code Blocks [+]

The 'commands' begin and end delimit code blocks, sequences of instructions that will be manipulated but not immediately executed. The MABWA machine pushes these two blocks onto the stack when it encounters them. They become the top two elements of the stack.


The MABWA assembler [+]

The next stage is to assemble the MABWA code into machine language. The result is still text, but at a lower level and more concise. For example, addition is denoted by +, and load becomes three instructions.


Evaluation of Variables[+]

The pseudo-instruction " causes the name of the variable (a string) to be pushed on the stack without being examined (as an instruction). Then the instruction $ looks up the definition of the variable - a code block (not shown) which is then executed.


Function Calls [-]

Environments come into play during evaluation of function calls. There are two environments, the environment in which the function was called and that in which it was defined. The body of the function is evaluated in the defining environment but the actuals are evaluated in the calling environment.

The inventors of LISP, the first functional language, got this wrong - they evaluated everything in the calling environment. The result has a name - "dynamic binding" - but is just wrong. It's not the lambda calculus. This is now well understood and modern LISPs, like Scheme, have the correct "static" binding.

Function calls are evaluated using closures, a closure being code block together with an environment. To evalute a closure we run the code block in the given environment.

A function is represented as a closure of a lambda expression. A function closure needs actual parameters to be evaluated. Given them, we form a frame in which each bound variable of the lambda expression is equated to a closure consisting of the corresponding actual parameter (a code block) and the calling environment. This frame is added on to the front of the defining environment d, giving environment d'. Then the result of the function application is the result of running the body of the lambda expression in d'.


  We plan to write a test interpreter in Python to check out the logic. But for speed, the ultimate goal, we'll use Apple's Swift.