CptS355 – Assignment 5 Static Scoping PostScript Interpreter (SSPS) solution

$25.00

Original Work ?
Category: You will Instantly receive a download link for .ZIP solution file upon Payment

Description

5/5 - (2 votes)

Project Description
You will be modifying your SPS interpreter (Assignment 4 – Simple Post Script Interpreter) to handle a
slightly different language which we will call Scoped Simple PostScript – SSPS. SSPS has no dict,
begin or end operations. Instead, each time a postscript function is called a new dictionary is
automatically pushed on the dictionary stack.
Compared to your SPS interpreter function, the SPSS interpreter will take an addition argument whose
value will be either the string “static” or the string “dynamic”, to indicate whether it should behave
using static scope rules or dynamic scope rules. For example:
# This is the recursive function to interpret a given code array.
# code is a code array; scope is a string (either “static” or “dynamic”)
def interpretSPS(code,scope):
pass
# add an argument to interpret to specify the scoping rule that will be
# applied
# s is a string; scope is a string (either “static” or “dynamic”)
def interpreter(s,scope):
interpretSPS(parse(tokenize(s)),scope)
Since if, ifelse,repeat, and forall operators also call interpretSPS (to execute their
code arrays), you should also add the “scope” argument to these operator implementations.
To interpret code using static scoping rules call interpreter(s,’static’) and to interpret code
“s” using dynamic scoping rules call interpreter(s,’dynamic’).
• Each time a postscript function is about to be called push a new dictionary and when a
postscript function is about to return pop the dictionary.
• To implement static scope rules you need a static chain which is the set of dictionaries visited by
following the static links (also called the access links) we discussed in class. You already have a
stack of dictionaries, you don’t need to have explicit dynamic links. The dynamic chain is implicit
in the order of the dictionaries in the list. To search for a declaration you search from the top of
the stack.
• How can you implement the static chain? I suggest making the stack be a stack of tuples
(instead of just a stack of dictionaries) where each tuple contains an integer index and a
dictionary. The integer index represents the static link that tells you the position in the list of the
(dictionary, static-link-index) tuple for the parent scope.
• Where do static-link values come from? As we saw in class, at the point when a function is
called, the static link in the new stack entry needs to be set to point to the stack entry where the
function’s definition was found. (Note that with the stack being a list, this “pointer” is just an
index in the list.) So when calling a postscript function you create a new dictionary automatically
and what you push on the dictionary stack is a pair : (index-of-definition’s stack entry,
dictionary).
 Hint: In an effective implementation this should all take only a handful of lines of new
code but it is tricky to get all the pieces right. My advice is think more, write less for this
part of the project.
 As discussed in class, variable lookups using static scope rules proceed by looking in the
current dictionary at the top of the dictionary stack and then following the static-link
fields to other dictionaries (instead of just looking at the dictionaries in order).
 Note: In Assignment 3, you already implemented the lookup function using
static scoping rule, where you search the dictionaries following the index links in
the tuples (i.e., following the static links).
• Using dynamic scope rules, the SPSS interpreter will behave very much like SPS except that it
won’t support dict, begin or end operations in programs (indeed, there will be no
implementation of these operations in SSPS).
 I suggest you to use the same dictstack for both static and dynamic scope
implementations.
 When the scoping rule is dynamic, the lookup should just look at the dictionaries on the
dictstack starting from top (ignoring the static links).
Additional Notes:
You should not have two separate interpret functions for the static and dynamic scoping
implementations. Please include the scoping rule as an argument as suggested above and
customize the interpretation if static scoping is specified.
For each test input we will test your code for static and dynamic scoping as follows (assume
“input1” is the SPS code that we will interpret):
interpreter(input1, “static”)
interpreter(input1, “dynamic”)
– As explained before, your interpreter should store 2-tuples in dictstack where first
value in the tuple is the dictionary and second value is the static link index.
– A new tuple will be pushed onto the dictstack whenever a function call is made.
– “Static link index” is the index of the dictionary (in the dictstack) where the
function is defined. I will discuss the algorithm for finding this in class.
– Change your lookup function for static scoping. If the scoping rule is dynamic,
perform lookup by searching the activation record (tuples) top to down. If it is static, use
static links for the search.
– When a function call returns, remember to pop the tuple for that function call from the
dictstack.
– Change your stack operator implementation as explained below.
Output of the Interpreter
Whenever the stack operation is executed, the contents of the operand and dictionary stacks are
printed. (Remember that stack only printed the contents of the operand stack in Assignment-4)
 Print a line containing “==============” to separate the stack from what has come before.
 Print the operand stack one value per line; print the top-of-stack element first.
 Print a line containing “==============” to separate the stack from the dictionary stack.
 Print the contents of the dictionary stack, beginning with the top-of-stack dictionary one name
and value per line with a line containing {—- m—- n —-} before each dictionary.
m is the index that will identify the dictionary printed (dictionary index) and n is the index that
represents the static link for the dictionary printed (in the case that static scoping is being used).
Please see below for an example.
 Print a line containing “==============” to separate the dictionary stack from any subsequent
output.
Remember please the difference between a dictionary and a dictionary entry.
What if my SPS interpreter didn’t work correctly?
You will need to fix it so it works. You can visit with the TA or me for help.
How can I tell if my static scoping code is working correctly?
You will have to create some test cases for which you can predict the correct answers. Below are couple
examples for initial tests. Please create additional tests (at least 3) to test your interpreter.
When we grade your assignment, we will compare the outputs of your interpreter prints.
/x 4 def
/g { x stack } def
/f { /x 7 def g } def
f
The above SPS code will leave 7 on the stack using dynamic scoping and 4 using static scoping. The
output from the stack operator in function g would look like this when using static scoping:
==============
4
==============
—-2—-0—-
—-1—-0—-
/x 7
—-0—-0—-
/x 4
/g [‘x’, ‘stack’]
/f [‘/x’, 7, ‘def’, ‘g’]
==============
And using dynamic scoping, the output from the stack operator will look like the following:
==============
7
==============
—-2—-0—-
—-1—-0—-
/x 7
—-0—-0—-
/x 4
/g [‘x’, ‘stack’]
/f [‘/x’, 7, ‘def’, ‘g’]
==============
For the values of m and n you may use anything you like as along as it is possible to tell where the static
links point. For printing code array values, I suggest using [ ] around the values in the array.
Additional Test Cases:
2)
testinput2 = “””
/x 4 def
[1 1 1] 1 [2 3] putinterval /arr exch def
/g { x stack } def
/f { 0 arr {7 mul add} forall /x exch def g } def
f
“””
Expected Output
Using static scoping
Static
==============
4
==============
—-2—-0—-
—-1—-0—-
/x 42
—-0—-0—-
/x 4
/arr [1, 2, 3]
/g {‘codearray’: [‘x’, ‘stack’]}
/f {‘codearray’: [0, ‘arr’, {‘codearray’: [7, ‘mul’, ‘add’]}, ‘forall’,
‘/x’, ‘exch’, ‘def’, ‘g’]}
==============
Using dynamic scoping
Dynamic
==============
42
==============
—-2—-0—-
—-1—-0—-
/x 42
—-0—-0—-
/x 4
/arr [1, 2, 3]
/g {‘codearray’: [‘x’, ‘stack’]}
/f {‘codearray’: [0, ‘arr’, {‘codearray’: [7, ‘mul’, ‘add’]}, ‘forall’,
‘/x’, ‘exch’, ‘def’, ‘g’]}
==============
3)
testinput3 = “””
/m 50 def
/n 100 def
/egg1 {/m 25 def n} def
/chic
{ /n 1 def
/egg2 { n stack} def
m n
egg1
egg2
} def
n
chic
“””
Expected Output
Using static scoping
Static
==============
1
100
1
50
100
==============
—-2—-1—-
—-1—-0—-
/n 1
/egg2 {‘codearray’: [‘n’, ‘stack’]}
—-0—-0—-
/m 50
/n 100
/egg1 {‘codearray’: [‘/m’, 25, ‘def’, ‘n’]}
/chic {‘codearray’: [‘/n’, 1, ‘def’, ‘/egg2’, {‘codearray’: [‘n’,
‘stack’]}, ‘def’, ‘m’, ‘n’, ‘egg1’, ‘egg2’]}
==============
Using dynamic scoping
Dynamic
==============
1
1
1
50
100
==============
—-2—-1—-
—-1—-0—-
/n 1
/egg2 {‘codearray’: [‘n’, ‘stack’]}
—-0—-0—-
/m 50
/n 100
/egg1 {‘codearray’: [‘/m’, 25, ‘def’, ‘n’]}
/chic {‘codearray’: [‘/n’, 1, ‘def’, ‘/egg2’, {‘codearray’: [‘n’,
‘stack’]}, ‘def’, ‘m’, ‘n’, ‘egg1’, ‘egg2’]}
==============
4)
testinput4 = “””
/x 10 def
/A { x } def
/C { /x 40 def A stack } def
/B { /x 30 def /A { x } def C } def
B
“””
Expected Output
Using static scoping
Static
==============
10
==============
—-2—-0—-
/x 40
—-1—-0—-
/x 30
/A {‘codearray’: [‘x’]}
—-0—-0—-
/x 10
/A {‘codearray’: [‘x’]}
/C {‘codearray’: [‘/x’, 40, ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, 30, ‘def’, ‘/A’, {‘codearray’: [‘x’]}, ‘def’, ‘C’]}
==============
Using dynamic scoping
Dynamic
==============
40
==============
—-2—-0—-
/x 40
—-1—-0—-
/x 30
/A {‘codearray’: [‘x’]}
—-0—-0—-
/x 10
/A {‘codearray’: [‘x’]}
/C {‘codearray’: [‘/x’, 40, ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, 30, ‘def’, ‘/A’, {‘codearray’: [‘x’]}, ‘def’, ‘C’]}
==============
5)
testinput5 = “””
/x 10 def
/n 5 def
/A { 0 n {x add} repeat} def
/C { /n 3 def /x 40 def A stack } def
/B { /x 30 def /A { x } def C } def
B
“””
Expected Output
Using static scoping
Static
==============
50
==============
—-2—-0—-
/n 3
/x 40
—-1—-0—-
/x 30
/A {‘codearray’: [‘x’]}
—-0—-0—-
/x 10
/n 5
/A {‘codearray’: [0, ‘n’, {‘codearray’: [‘x’, ‘add’]}, ‘repeat’]}
/C {‘codearray’: [‘/n’, 3, ‘def’, ‘/x’, 40, ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, 30, ‘def’, ‘/A’, {‘codearray’: [‘x’]}, ‘def’, ‘C’]}
==============
Using dynamic scoping
Dynamic
==============
40
==============
—-2—-0—-
/n 3
/x 40
—-1—-0—-
/x 30
/A {‘codearray’: [‘x’]}
—-0—-0—-
/x 10
/n 5
/A {‘codearray’: [0, ‘n’, {‘codearray’: [‘x’, ‘add’]}, ‘repeat’]}
/C {‘codearray’: [‘/n’, 3, ‘def’, ‘/x’, 40, ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, 30, ‘def’, ‘/A’, {‘codearray’: [‘x’]}, ‘def’, ‘C’]}
==============
6)
testinput6 = “””
/out true def
/xand { true eq {pop false} {true eq { false } { true } ifelse} ifelse dup /x
exch def stack} def
/myput { out dup /x exch def xand } def
/f { /out false def myput } def
false f
“””
Expected Output
Using static scoping
Static
==============
False
==============
—-3—-0—-
/x False
—-2—-0—-
/x True
—-1—-0—-
/out False
—-0—-0—-
/out True
/xand {‘codearray’: [True, ‘eq’, {‘codearray’: [‘pop’, False]},
{‘codearray’: [True, ‘eq’, {‘codearray’: [False]}, {‘codearray’: [True]},
‘ifelse’]}, ‘ifelse’, ‘dup’, ‘/x’, ‘exch’, ‘def’, ‘stack’]}
/myput {‘codearray’: [‘out’, ‘dup’, ‘/x’, ‘exch’, ‘def’, ‘xand’]}
/f {‘codearray’: [‘/out’, False, ‘def’, ‘myput’]}
==============
Using dynamic scoping
Dynamic
==============
True
==============
—-3—-0—-
/x True
—-2—-0—-
/x False
—-1—-0—-
/out False
—-0—-0—-
/out True
/xand {‘codearray’: [True, ‘eq’, {‘codearray’: [‘pop’, False]},
{‘codearray’: [True, ‘eq’, {‘codearray’: [False]}, {‘codearray’: [True]},
‘ifelse’]}, ‘ifelse’, ‘dup’, ‘/x’, ‘exch’, ‘def’, ‘stack’]}
/myput {‘codearray’: [‘out’, ‘dup’, ‘/x’, ‘exch’, ‘def’, ‘xand’]}
/f {‘codearray’: [‘/out’, False, ‘def’, ‘myput’]}
==============
7)
testinput7 = “””
/x [1 2 3 4] def
/A { x length } def
/C { /x [10 20 30 40 50 60] def A stack } def
/B { /x [6 7 8 9] def /A { x 0 get} def C } def
B
“””
Expected Output
Using static scoping
Static
==============
4
==============
—-2—-0—-
/x [10, 20, 30, 40, 50, 60]
—-1—-0—-
/x [6, 7, 8, 9]
/A {‘codearray’: [‘x’, 0, ‘get’]}
—-0—-0—-
/x [1, 2, 3, 4]
/A {‘codearray’: [‘x’, ‘length’]}
/C {‘codearray’: [‘/x’, [10, 20, 30, 40, 50, 60], ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, [6, 7, 8, 9], ‘def’, ‘/A’, {‘codearray’: [‘x’, 0,
‘get’]}, ‘def’, ‘C’]}
==============
Using dynamic scoping
Dynamic
==============
10
==============
—-2—-0—-
/x [10, 20, 30, 40, 50, 60]
—-1—-0—-
/x [6, 7, 8, 9]
/A {‘codearray’: [‘x’, 0, ‘get’]}
—-0—-0—-
/x [1, 2, 3, 4]
/A {‘codearray’: [‘x’, ‘length’]}
/C {‘codearray’: [‘/x’, [10, 20, 30, 40, 50, 60], ‘def’, ‘A’, ‘stack’]}
/B {‘codearray’: [‘/x’, [6, 7, 8, 9], ‘def’, ‘/A’, {‘codearray’: [‘x’, 0,
‘get’]}, ‘def’, ‘C’]}
==============
8)
testinput8 = “””
[0 1 2 3 4 5 6 7 8 9 10] 3 4 getinterval /x exch def
/a 10 def
/A { x length } def
/C { /x [a 2 mul a 3 mul dup a 4 mul] def A a x stack } def
/B { /x [6 7 8 9] def /A { x 0 get} def /a 5 def C } def
B
“””
Expected Output
Using static scoping
Static
==============
[20, 30, 30, 40]
10
4
==============
—-2—-0—-
/x [20, 30, 30, 40]
—-1—-0—-
/x [6, 7, 8, 9]
/A {‘codearray’: [‘x’, 0, ‘get’]}
/a 5
—-0—-0—-
/x [3, 4, 5, 6]
/a 10
/A {‘codearray’: [‘x’, ‘length’]}
/C {‘codearray’: [‘/x’, [‘a’, 2, ‘mul’, ‘a’, 3, ‘mul’, ‘dup’, ‘a’, 4,
‘mul’], ‘def’, ‘A’, ‘a’, ‘x’, ‘stack’]}
/B {‘codearray’: [‘/x’, [6, 7, 8, 9], ‘def’, ‘/A’, {‘codearray’: [‘x’, 0,
‘get’]}, ‘def’, ‘/a’, 5, ‘def’, ‘C’]}
==============
Using dynamic scoping
Dynamic
==============
[10, 15, 15, 20]
5
10
==============
—-2—-0—-
/x [10, 15, 15, 20]
—-1—-0—-
/x [6, 7, 8, 9]
/A {‘codearray’: [‘x’, 0, ‘get’]}
/a 5
—-0—-0—-
/x [3, 4, 5, 6]
/a 10
/A {‘codearray’: [‘x’, ‘length’]}
/C {‘codearray’: [‘/x’, [‘a’, 2, ‘mul’, ‘a’, 3, ‘mul’, ‘dup’, ‘a’, 4,
‘mul’], ‘def’, ‘A’, ‘a’, ‘x’, ‘stack’]}
/B {‘codearray’: [‘/x’, [6, 7, 8, 9], ‘def’, ‘/A’, {‘codearray’: [‘x’, 0,
‘get’]}, ‘def’, ‘/a’, 5, ‘def’, ‘C’]}
==============