|
|
CS 3721
Programming Languages
Fall 2013 |
Recitation 7. Assignments
|
Week 7: Oct 7 - 11
|
Submit following directions at:
submissions
and rules at:
rules.
Deadlines are:
- 2013-10-18 23:59:59 (that's Fri, 18 Oct 2013, 11:59:59 pm)
for full credit.
- No part-credit turn-in. (Because the mid-term exam is Mon, 21 Oct.)
|
Compiler for Assignments, and for I/O:
Study the pages:
- Recursive-Descent Parsing:
- Tiny® Language:
- MIPS Assembly Language:
Overview:
For this recitation you are to do the following:
- Write a program in Java or C
that will read a Tiny®
program as data and compile it, that is, output a MIPS assembly
program that will carry out the intent of the Tiny® program.
You will do this by adding code to your parser for Tiny®
That was written for Recitation 6: Tiny® Parser.
- Execute the MIPS program.
For this recitation we will also:
- restrict the compiler to a subset of Tiny®:
leaving off if-then-else and while statements, and leaving
off the operators ^, %, and @.
This subset of Tiny® is described by the portion
of the following grammar that is in red.
Grammar for Tiny®
language |
M −−−> L '$'
L −−−> S { S }
S −−−> I | W | A | P | C | G
I −−−> '[' E '?' L ':' L ']' | '[' E '?' L ']'
W −−−> '{' E '?' L '}'
A −−−> lower-case '=' E ';'
P −−−> '<' E ';'
C −−−> '<' ('B' | 'N' | 'T') ';'
G −−−> '>' lower-case ';'
E −−−> T {('+' | '-') T}
T −−−> U {('*' | '/' | '%' | '@') U}
U −−−> F '^' U | F
F −−−> '(' E ')' | ('+' | '-') F | lower-case | digit
|
The next table gives an overview of the features to be implemented.
Features
Implemented by this Recitation |
Name of Feature |
Grammar Rule |
Tiny Examples |
Assignment Statement
(Insert value into a variable) |
A −−−> lower-case '=' E ';' |
n = n + 1; a = 2*b/c-4; |
Output Expression
(Output value of an expression) |
P −−−> '<' E ';' |
< n; < (a+b)/2; |
Output Blank, Newline, or Tab
(B for ' ', N for '\n', T for '\t') |
C −−−> '<' ('B' | 'N' | 'T') ';' |
< B; < N; < T; |
Input Value (Insert value
from input into a variable) |
G −−−> '>' lower-case ';' |
> n; > a; > p; |
How is Memory Mapped:
We need to be clear about the use of memory at run time.
Recall the .data part of the MIPS code we will use:
MIPS
Memory Allocation |
.data
.align 3
M: .double 0.,1.,2.,3.,4.,5.,6.
.double 7.,8.,9. # constants
.space 208 # variables a to z
.space 1000 # 125 temporaries
Blank: .asciiz " "
NewL: .asciiz "\n"
Tab: .asciiz "\t"
|
We use M[i] to stand for i*8 bytes past the start of M.
Then the locations of digits, variables and temporaries are given
in the table:
Memory Allocation Table.
The names "Blank", "NewL", and "Tab" above are my own
arbitrary choice.
Returning Addresses:
As mentioned above, you should start with your Tiny Parser from
Recitation 6. Each function related to expressions will
be returning an address where the value of the corresponding
part of the program can be found at run time. Thus functions
E, T, U, and F will each return such an address.
In my own code I return the proper index of the M
"array", and then multiply by 8 before using it, but you
could instead return the actual address.
For example, in your code, whenever you have a call to E,
this call should return the address where the value of that
expression will be at run time. It doesn't matter whether that
call to E processes a digit, an identifier, or an
arbitrarily complex expression.
Consider what the function F should return in your code.
- If F handles a digit, say stored in a variable
ch, then F should return (ch-'0').
- If F handles a lower-case letter, stored in ch,
then F should return (ch-'a'+10).
- If F handles an expression (in parens) by calling
E, the F should return whatever E returns.
How To Get Started.
I would start with your parser from Recitation 5.
Then initially I would make only a few changes:
- Change F so that it returns the proper integer
for a lower-case letter and the proper one for a digit.
- Change U, T, E so that they
pass the value coming to them from below on up by returning it.
- Add code to A so that it completely handles an assignment.
A first decides which number belongs
to the variable on the left side. Save this number inside A.
Then get the number returned from a call to E.
Multiply this by 8 to get byte offset of the expression from
the start of M.
Finally generate (print) two MIPS
instructions, the first to load the number at the locations
returned by E into a register, and second to store
this number into the location given by the identifier at
the right side of the assignment. So
start with the input: f = 7;$, which should be a legal
input to your parse. With the changes above, your program
should output the two MIPS instructions at the far left.
Then with the same program, try the second input.
For the third input below, you must add to the function
E so that when there is an addition, it will produce two loads,
add, and a store instruction. These three inputs below are
for your own debugging.
Sample Input: |
Input: f = 7; $
Should produce output:
# M[15] = M[7]
l.d $f2, 56($s1)
s.d $f2, 120($s1)
|
| |
Sample Input: |
Input: f = 7; g = f; $
Should produce output:
# M[15] = M[7]
l.d $f2, 56($s1)
s.d $f2, 120($s1)
# M[16] = M[15]
l.d $f2, 120($s1)
s.d $f2, 128($s1)
|
| |
Sample Input: |
Input: g = f + 8 ; $
Should produce output:
# M[36] = M[15] + M[8]
l.d $f2, 120($s1)
l.d $f4, 64($s1)
add.d $f6, $f2, $f4
s.d $f6, 288($s1)
# M[16] = M[36]
l.d $f2, 288($s1)
s.d $f2, 128($s1)
|
|
- Here are sample programs that you should compile from Tiny to MIPS
assembly code. You then should execute the MIPS code.
For these you need to implement the two types of output
In order to successfully execute
these using spim, you must
add the stuff at the beginning and end of the complete sample
programs. Of course all four programs work with doubles,
but the doubles in Sample Input 1 are all exact integers.
Sample Input 0: |
a = 8 * 2;
b = 7 * a;
c = b + 1;
d = a / c;
e = 3 + d;
< e;
< N;
$
|
| |
Sample Input 1: |
f = 3*7;
g = f + (9 + 4);
h = f + g;
< h; < B;
a = f*f + g*g;
b = g*h + f*g;
c = g*g + h*h;
< c; < B;
f = a*a + b*b;
g = b*c + a*b;
h = c*c + b*b;
< h; < N;
a = f*f + g*g;
b = g*h + f*g;
c = g*g + h*h;
< c; < N; $
|
Output: |
55 4181 24157817
806515533049393
Fibonacci Nums:
F10 F19 F37 F73
|
| |
Sample Input 2: |
< 3+1/(7+1/(5*3+1/(1+
1/((4*(9*8+1))+1/(1+
1/(1+1/(1+1/(2+1/(1+
1/(3+1/(1+1/(2*7+1/(2+
1) ))))))))))));$
|
| |
Sample Input 3: |
p = 3 + (1/7);
> r;
v = (4/3)*p*r*r*r;
< p; < N;
< r; < N;
< v; < N;
$
|
Run of Program: |
% spim r3.s
3.5
3.14285714285714279
3.5
179.666666666666657
|
|
What you should submit:
- Give the complete Java or C source code for your compiler program.
- For each of the four sample program in turn, include:
- The original Tiny program.
- The complete MIPS code that results from compiling that Tiny program,
for Sample Inputs 0 and 3 only. (My MIPS code for
Sample Inputs 1 and 2 are 240 and 180 lines long respectively.)
- The output resulting from running that particular MIPS program
using spim.
Revision date: 2013-10-11.
(Use ISO 8601,
an International Standard.)
|