What does it do
- keep track of deferred operations
- keep track of what environment to return to (after a function is done)
- keep track of the result of evaluating expressions
Control
- In the beginning, it will contain the whole program
- As the program runs, it stores what we still need to execute
Stash
- Any primitive values get put onto the stash
- The last value on the stash is what the program will output after it is done
- If there are no values on the stash at the end, will output
undefined
- If there are no values on the stash at the end, will output
How to evaluate a program
When encountering ? as the next item on control, first, remove the item, then:
Expression
e.g. 1 * 2 + 3 * 4 is the next item on control
- Decompose expression
- Remove
1 * 2 + 3 * 4from control - Push the operator
+onto the control - Push the arguments onto the control, from right to left (so that the leftmost operation will be evaluated first), so push
3 * 4, then1 * 2
- Remove
Value
e.g. true, 1, [1, 2, 3]
- Push value onto stash note: if the value is a compound value (function object, pair, array), then it will be created in the environment area, and pointed to by the item on the stash
Operator
e.g. >=, +, !
- Take the top n required values from the stash (e.g.
1and2) and apply the operator (for+,>=etc. it is 2 values, but for!it is 1 value) - Remove the top 2 values from the stash
- Push the result onto the stash (
3)
Sequence
e.g.
1 + 2;
3 * 4;
5 / 6;- Decompose sequence (
1+2;,3*4;,5/6;) - Push parts onto control from bottom up, with pop statements inbetween so push in this order:
5/6;,pop,3*4;,pop,1+2;- Push a
popright after every value-producing statement, apart from the first statement in the sequence. i.e.pops will be added so that the sequence results in the value of the last value-producing statement being pushed onto the stash
- Push a
Block
e.g.
{
const x = 1;
x + 1;
}- Find all declarations in the block (
const x = 1;) - Push an
envinstruction onto the control, which points to the current environment- Only if there are more statements that access names on the rest of the control (so the program block will not result in an
env)
- Only if there are more statements that access names on the rest of the control (so the program block will not result in an
- Create an environment frame that extends the current environment
- Add the declaration to the environment, so the frame will contain
x:= - Push the contents of the block onto the control, so
const x = 1; x + 1;(it is either a sequence or an expression)
env instruction
- Change the current environment to the environment that the
envinstruction is pointing to
While loop
e.g. while (i > 1) { i = i + 1; }
- Push the
whileinstruction onto the control (it contains the entire definition of the while loop) - Push the predicate (
i > 1) onto the control - Push
undefinedonto the control (this is because while loops are value producing, so if the contents of the loop are not run, the stash will contain undefined)
while instruction
- Check whether the value on the stash is true
- If true
- Push the predicate onto the control
- Push the body of the loop onto the control (as a block
{...}) - Push
poponto the control (this is to remove the previous result of executing the while loop)
- If false
- Do nothing (remember to remove the
whileinstruction from the control)
- Do nothing (remember to remove the
Conditional expression or statement
e.g. conditional expression x > 1 ? 1 + 2 : 3 + 4; or conditional statement if(x > 1) { 1 + 2; } else { 3 + 4; }
- Push
branchonto the control (thebranchinstruction will “store” both sides of the conditional expression (1+2and3+4)) - Push the predicate expression onto the control (
true) note:
- Both of these are value-producing, i.e. the result of evaluating their contents will be put onto the stash
- Both of these are considered one entry in a sequence, i.e. the entire
if ... else ...will be pushed onto the control when a sequence is evaluated
For loop
For 1101S, don’t need to know how for loops work
branch instruction
e.g. branch (that contains 1+2 : 3+4)
- Push the expression that corresponds with the top value on the stash onto the control as a block, so if the value on the stash is
true, then push{1+2;}onto the control - Remove the top value (or pop) from the stash
Assignment statement
e.g. const abc = 1 + 2;
- Push onto the conrol:
popthenasgn abc - Push onto the control the assignment expression (
1 + 2)
Name
e.g. abc
- Search for the name in the current environment
- Push the value found onto the stash
- If this value is a function, push the word
closure, which points to the function found - If this value is a pair or array, push the word
pair/array, which points to the pair or array
- If this value is a function, push the word
asgn instruction
e.g. asgn abc
- Search for the name in the current environment
abcin this case - Set the value of
abcto the top item on the stash
pop instruction
- Remove the top value (or pop) from the stash
Logical composition
e.g. x && y
- Push the corresponding conditional statement onto the control
x && y→x ? y : falsex || y→x ? true : y
Lambda expression
e.g. x => {1+1; return x * x;}
- Draw the function in the current environment (the two circles, with right circle pointing to the current environment)
- Push the function onto the stash (represented by the word
closure, which points to the function created in 1.)
Function statement
e.g. function sum(x, y) {return x + y;}
- Push a constant assignment onto the control (
const sum = (x,y) => ...)
Function call/application
e.g. sum(1,2 + 3);
- Push onto the control:
call n, where n is number of arguments, socall 2in this case - Push onto the control: the function argument expressions, from right to left, so
2 + 3then1(this corresponds to left to right evaluation) - Push the name of the function onto the control
call instruction
e.g. call 2
- Take
nitems from the stash, in this case 2. The topmost item will be the rightmost argument to the function - After taking
nitems from the stash, there should be aclosureon the stash. - If there are more statements that access names on the rest of the control, push an
envinstruction that points to the current environment- To tell whether we need an
envinstruction, just check if we need to return to the current environment after the function is done
- To tell whether we need an
- If the function is a compound function (not simple) (i.e. there is a return statement and there are statements apart from the return statement), push a
markinstruction onto the control - Evaluate this
closurewith the arguments from 1.- If there are arguments, extend the function’s environment with a frame that contains the arguments
- If the function is simple, push the contents of the function (the expression that the function returns) onto the control
- If it is compound (not simple), push the whole function body block onto the control
return statement
e.g. return 1 + 2;
- Remove the top value (or pop) from the control
- If the popped value is not a
markinstruction, push areturninstruction onto the control - If it is a
markinstruction, do not push anything onto the control, then push the expression onto the control (1+2) note: this is equivalent to popping from control until amarkis removed
- If the popped value is not a