|
|
CS 3721
Programming Languages
Fall 2013 |
Recitation 8. Conditionals
|
Week 9: Oct 23 - 25
|
Submit following directions at:
submissions
and rules at:
rules.
Deadlines are:
- 2013-10-28 23:59:59
(that's Mon, 28 Oct 2013, 11:59:59 pm)
for full credit.
- 2013-11-01 23:59:59 (that's Fri,
1 Nov 2013, 11:59:59 pm)
for 75% credit.
|
Overview:
This recitation extends the previous one to translate
- while loops, using the { ? } syntax, and
- if-then-(optional)else, using the
[ ? : ] syntax.
The above two items are by far the most important parts of
this recitation. You should work on them first and then
work on the following lesser items:
- the remainder operator, using the percent
(%) symbol, and
- the truncated division operator, using the "at-sign"
(@) symbol, and
- the exponentiation operator, using the hat
(^) symbol., and
- the negation operator, using the unary minus
(-) symbol
You need to add extra code to
your parser to translate these additional constructs, keeping
all the earlier implemented parts still working.
You will now be using the full grammar from Recitation 6.
(Below the part in bold red type
is what needs to be implemented
for this recitation.)
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
|
Translation of Constructs:
One mainly has to decide how to
translate each construct into MIPS assembly language (in a way consistent
with the previous recitation).
- while statements:
W −−>
'{' E '?' L '}'
You've already been given a sample MIPS program with a while
implemented: MIPS: Euler Series.
Below I give the code for this MIPS program again
(dropping two output statements), with parts
related to the while statement highlighted in different colors:
The special code added for the while statement itself is
in red.
The code that evaluates the while condition, which is
generated by the call to E() inside the first part
of the while statement is in blue.
I changed
the MIPS comments to light green.
Tiny Source
and MIPS Code for the Euler Series (this will be
Sample 3 below) |
# euler.t: Euler series
n = 1; s = 0;
> m;
{ n - m ?
s = s + 1/(n*n);
< s; < N;
n = n + 1;
} $
### Compiled on: Sep 24, 2013
main: addu $s7, $ra, $zero
# addr of M:consts, vars, temps
la $s1, M
### Start of compiled code
# M[23] = M[1]
l.d $f2, 8($s1)
s.d $f2, 184($s1)
# M[28] = M[0]
l.d $f2, 0($s1)
s.d $f2, 224($s1)
# Read M[22] as double
li $v0, 7
syscall
s.d $f0, 176($s1)
|
WhileStart0:
# M[36] = M[23] - M[22]
l.d $f2, 184($s1)
l.d $f4, 176($s1)
sub.d $f6, $f2, $f4
s.d $f6, 288($s1)
l.d $f2, 288($s1)
l.d $f4, 0($s1)
c.eq.d $f2, $f4
bc1t WhileEnd0
# M[37] = M[23] * M[23]
l.d $f2, 184($s1)
l.d $f4, 184($s1)
mul.d $f6, $f2, $f4
s.d $f6, 296($s1)
# M[38] = M[1] / M[37]
l.d $f2, 8($s1)
l.d $f4, 296($s1)
div.d $f6, $f2, $f4
s.d $f6, 304($s1)
# M[39] = M[28] + M[38]
l.d $f2, 224($s1)
l.d $f4, 304($s1)
add.d $f6, $f2, $f4
s.d $f6, 312($s1)
|
# M[28] = M[39]
l.d $f2, 312($s1)
s.d $f2, 224($s1)
# Print M[28]
li $v0, 3
l.d $f12, 224($s1)
syscall
# Print NewL as ASCII char
li $v0, 4
la $a0, NewL
syscall
# M[40] = M[23] + M[1]
l.d $f2, 184($s1)
l.d $f4, 8($s1)
add.d $f6, $f2, $f4
s.d $f6, 320($s1)
# M[23] = M[40]
l.d $f2, 320($s1)
s.d $f2, 184($s1)
j WhileStart0
WhileEnd0:
### End of complied code
(standard stuff at the end)
### End of MIPS source
|
The four blue instructions are written as part of the call
to E() inside the while-condition. The final address
of the value of the expression is returned by E, in this case
it is 288
(my program returns 36 and it then multiplies by 8).
At this point, inside the while function W, the code can check
if the expression was 0, in which case it must terminate the while.
To do this, first it loads the value of the expression (first
red instruction), then it loads the constant 0 (second red
instruction. The third red instruction, c.eq.d
(see Page A-74), compares
the two double registers to see if they are equal. If so, it set
a condition flag in the floating point co-processor to 1 (true).
The fourth red instruction, bc1t
(see Page A-60),
will branch to the label in case
the condition flag is 1, that is, in case the original
expression worked out to be 0. (Wheh!)
Only the two red labels and the five red instructions are output
from inside the function W.
- Special problem: need for unique labels in MIPS:
In MIPS we cannot have duplicate statement labels, so with possibly
multiple while statements, both nested and sequential, one must ensure
that all labels are unique. As illustrated above, I propose to do
this by inserting a unique integer at the end of each label, an
integer different for each while or if-then-else. I suggest that you
maintain a separate counter to be tacked on at the end of these labels,
and increment this counter whenever you start a new while.
The while above is the first one, with the counter starting at 0.
- if-then-else statements:
I −−> '[' E
'?' L ':' L ']'
This part is left for you to work out for yourself. It is
similar to the while statement.
- if-then (no else) statements:
I −−>
'[' E '?' L ']'
This arises in case the parser doesn't find a ':' at the end of the
"then" part, but instead finds a "]", terminating the construct.
In this case your compiler needs to not output the
"else" parts.
- Truncated Division Operator @:
Below r should be in $f2, s in $f4,
result in $f6.
Calculate: r @ s |
div.d $f6, $f2, $f4 # divide, no trunc
trunc.w.d $f6, $f6 # truncate answer
cvt.d.w $f6, $f6 # convert to double
|
- Remainder Operator %:
For doubles r and s,
r % s is just
(r-(r/s)*s). This can be done with five MIPS instructions
(there may be other ways to do this).
Below r should be in $f2, s in $f4,
result in $f6.
Calculate: r % s |
div.d $f6, $f2, $f4 # \ truncated
trunc.w.d $f6, $f6 # | division
cvt.d.w $f6, $f6 # / see above
mul.d $f6, $f6, $f4 # multipy by s
sub.d $f6, $f2, $f6 # subtract from r
|
For integers MIPS has an instruction
rem that calculates the remainder on division, but there's
nothing similar for doubles.
- Exponentiation operator ^:
U −−>
F '^' U
| F
Calculate: r ^ s |
pow:
# truncate $f4
trunc.w.d $f4, $f4
cvt.d.w $f4, $f4
l.d $f6, 8($s1)
# check if $f4 == 0
l.d $f8, 0($s1)
c.eq.d $f4, $f8
bc1t end
# check if $f4 > 0
l.d $f8, 0($s1)
c.lt.d $f8, $f4
bc1t next
l.d $f8, 8($s1)
div.d $f2, $f8, $f2
neg.d $f4, $f4
# loop as long as $f4 == 0
next: l.d $f8, 0($s1)
c.eq.d $f4, $f8
bc1t end
mul.d $f6, $f6, $f2
l.d $f8, 8($s1)
sub.d $f4, $f4, $f8
b next
end: jr $ra
|
| |
This is similar to the other operators, except that MIPS has no hardware
instruction for exponentiation. Thus you should write a MIPS function to do
integer exponentiation, include the function at the end of your MIPS
program (by writing it out with the other stuff),
and write out code to call this function
as appropriate if you get to a ^ operator.
Below r should be in $f2, s in $f4,
result in $f6.
To use this in a MIPS program, include
the text at the left after "jr $ra" and before the ".data".
Load the base value into $r2. Load the exponent value
into $r4. Execute " jal pow". On return, the result will
be found in $r6. (Be careful, this also changes
$r4.)
|
|
- Unary Minus Operator:
MIPS has a double instruction neg.d that negates
its single operand. This is all you need.
Sample Inputs:
You should first test the while statement, then the if-then-else,
and then on to more complicated programs:
Test
while statements |
Sample 1:
Simple while | Sample 2:
Nested whiles |
> n;
{ n ? < n*n;
< B;
n = n - 1;
}
< N; $
% spim t1.s
4
16 9 4 1
% spim t1.s
6
36 25 16 9 4 1
| > n;
{ n ? < n;
< B;
m = n;
{ m ? < m*m*n;
< B;
m = m - 1;
}
< N;
n = n - 1;
} $
% spim t2.s
4
4 64 36 16 4
3 27 12 3
2 8 2
1 1
% spim t2.s
6
6 216 150 96 54 24 6
5 125 80 45 20 5
4 64 36 16 4
3 27 12 3
2 8 2
1 1
|
| |
My MIPS Code
for Sample 2 |
### Compiled on: Oct 19, 2013
main: addu $s7, $ra, $zero
# addr of M: const., vars,temps
la $s1, M
### Start of compiled code
# Read M[23] as double
li $v0, 7
syscall
s.d $f0, 184($s1)
WhileStart0:
l.d $f2, 184($s1)
l.d $f4, 0($s1)
c.eq.d $f2, $f4
bc1t WhileEnd0
# Print M[23]
li $v0, 3
l.d $f12, 184($s1)
syscall
# Print Blank as ASCII char
li $v0, 4
la $a0, Blank
syscall
# M[22] = M[23]
l.d $f2, 184($s1)
s.d $f2, 176($s1)
WhileStart1:
l.d $f2, 176($s1)
l.d $f4, 0($s1)
c.eq.d $f2, $f4
bc1t WhileEnd1
# M[36] = M[22] * M[22]
l.d $f2, 176($s1)
l.d $f4, 176($s1)
mul.d $f6, $f2, $f4
s.d $f6, 288($s1)
|
# M[37] = M[36] * M[23]
l.d $f2, 288($s1)
l.d $f4, 184($s1)
mul.d $f6, $f2, $f4
s.d $f6, 296($s1)
# Print M[37]
li $v0, 3
l.d $f12, 296($s1)
syscall
# Print Blank as ASCII char
li $v0, 4
la $a0, Blank
syscall
# M[38] = M[22] - M[1]
l.d $f2, 176($s1)
l.d $f4, 8($s1)
sub.d $f6, $f2, $f4
s.d $f6, 304($s1)
# M[22] = M[38]
l.d $f2, 304($s1)
s.d $f2, 176($s1)
j WhileStart1
WhileEnd1:
# Print NewL as ASCII char
li $v0, 4
la $a0, NewL
syscall
# M[39] = M[23] - M[1]
l.d $f2, 184($s1)
l.d $f4, 8($s1)
sub.d $f6, $f2, $f4
s.d $f6, 312($s1)
# M[23] = M[39]
l.d $f2, 312($s1)
s.d $f2, 184($s1)
j WhileStart0
WhileEnd0:
### (the rest left off ...)
|
|
Next run compile and run the Euler Series program above
as Sample 3.
- Test if-then-else and if-then statements:
Note in Sample 4 below that m-3 is 0 or false
and m-5 is -2, that is, non-zero or true.
To the right is another more thorough test, Sample 5.
Test
if-then-else and if-then statements |
Sample 4 |
m = 3;
[ m - 3 ? < 2; : < 3; ]
[ m - 5 ? < 4; : < 5; ]
[ m - 3 ? < 6; ]
[ m - 5 ? < 7; ]
$
% spim t1.s
347%
|
| |
Larger
Test |
Sample 5, Code |
Output |
> m;
i = m - 1;
> n;
{ m ? < m; m = m - 1; }
< N;
x = 2*5;
a = x;
{ i ?
[ n@a ? d = d; : < B; ]
a = a*x;
i = i - 1;
}
< n; < N; $
| % spim n2.s
8
44444
87654321
44444
% spim n2.s
6
4545
654321
4545
% spim n2.s
7
4
7654321
4
% spim n2.s
5
34343
54321
34343
|
|
More Complicated Sample Inputs:
Programs Sample 6 and Sample 7 can be found at:
Complicated Tiny Programs.
Test exponentiation operator ^:
Here are programs Sample 8, and Sample 9:
Test ^. Do these last.
What you should submit:
You should first give:
- the compiler source program.
Then for each sample program in turn, give the MIPS code itself
if it is short, and otherwise give the first 50 lines.
Then give the output
from running the MIPS code, using the inputs shown below.
- Sample 1 (Simple while):
Run this with input 7 to the MIPS code.
- Sample 2 (Nested whiles):
Run this with input 8 to the MIPS code.
- Sample 3 (Euler Series):
Run with input 25 to the MIPS code.
- Sample 4 (Test if-then-else):
Run this with no input to the MIPS code.
- Sample 5 (Larger Test):
Run this twice, first with inputs 5 and 333
and then with inputs 7 and 22.
- Sample 6 (Product Formula):
Run this with input 30 to the MIPS code.
- Sample 7 (Fibonacci factors):
Run this with input 40 to the MIPS code.
- Sample 8 (Geometric Series):
Run this with inputs 3, 5, and 10 to the MIPS code.
- Sample 9 (Accociativity of ^):
Run this with inputs 2, and 3 to the MIPS code.
Note: This is sort of the "grand finale" of a long set of recitations,
and it is the high point of the course. (Downhill from here on.)
That's why there are so many possible test programs.
You should especially try to get to Sample 6 and
Sample 7. Only do Sample 8 and Sample 9 (involving the ^
operator) last, if you are bored or crazy.
In case you have code written, but it doesn't compile any of the
sample programs, you should describe what you have done for part credit.
Revision date: 2013-10-24.
(Use ISO 8601,
an International Standard.)
|