|
|
CS 3721
Programming Languages
Spring 2013 |
Recitation 7.
Semantics 2: If-else and while
|
Week 7: Feb 25 - Mar 1
|
Submit following directions at:
submissions
and rules at:
rules.
Deadlines are:
- 2013-03-08 23:59:59
(that's Fri, 08 Mar 2013, 11:59:59 pm)
for full credit.
- 2013-03-18 23:59:59 (that's Mon, 18 Mar 2013, 11:59:59 pm)
for 75% credit.
|
Overview:
This recitation extends the previous one to translate
- while loops, using the { ? } syntax,
- if-then-(optional)else, using the
[ ? : ] syntax,
- input statements,using the > symbol,
- the exponentiation operator, using the hat
(^) operator, and
- the remainder operator, using the percent
(%) operator, and
as well as everything translated before.
You need to add extra code to
your parser to translate these additional constructs.
You will now be using the full grammar from Recitation 5.
(Below the part in bold red type
is what needs to be implemented
for this recitation.)
Grammar for Tiny language |
M ---> { S } '$'
S ---> I | W | G | A | P | C
I ---> '[' E '?' { S } ':' { S } ']' | '[' E '?' { S } ']'
W ---> '{' E '?' { S } '}'
A ---> lower-case '=' E ';'
P ---> '<' E ';'
G ---> '>' lower-case ';'
C ---> '<' upper-case ';'
E ---> T {('+' | '-') T}
T ---> U {('*' | '/' | '%') U}
U ---> F '^' U | F
F ---> '(' E ')' | 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).
- Input statements:
G ---> '>' lower-case ';'
For example, suppose the input statement is: > m;
This could be translated to the following MIPS code:
> g ; (read value for g) |
# Read M[22] as integer
li $v0, 5
syscall
sw $v0, 88($s1)
|
Be careful: Each item read must be on a separate line, as illustrated below.
Also, any integer can be input, even though the language only allows
single-digit integers without a sign as constants.
- Remainder Operator %:
As I said in class, for integers r and s,
r % s is just
(r-(r/s)*s). This can be done with three MIPS instructions:
Calculate: r % s |
# r is in $t1, s is in $t2, r%s is in $t3
div $t4, $t1, $t2 # $t4 = $t1 / $t2
mul $t5, $t4, $t2 # $t5 = $t4 * $t2
sub $t3, $t1, $t5 # $t3 = $t1 - $t5
|
After using this I discovered that MIPS has an instruction
rem that calculates the remainder on division, so your
compiler can treat this operator exactly like * or /, except
using rem in place of mul or div.
- while statements:
W --->
'{' E '?' { S } '}'
For example, consider the following program on the left, consisting mostly
of just a simple while statement, which prints the integers from 1 to 9
on separate lines. This could be translated to the MIPS code
on the right,
with the key parts in red. All the black parts of the code
below will be generated by the code from the previous recitation.
Notice that the code below is just one of many possible ways to do the
translation.
Sample Input 1 |
n = 0;
{ n - 9 ?
n = n + 1;
< n; < N;
}
$
|
Output |
1
2
3
4
5
6
7
8
9
|
| |
Sample 1 MIPS |
### Compiled on: Fri Feb 15 15:54:26 CST 2013
main: addu $s7, $ra, $zero
la $s1, M
### Start of compiled code
# M[23] = M[0]
lw $t1, 0($s1)
sw $t1, 92($s1)
WhileStart0:
# M[36] = M[23] - M[9]
lw $t1, 92($s1)
lw $t2, 36($s1)
sub $t3, $t1, $t2
sw $t3, 144($s1)
lw $t1, 144($s1)
beq $t1, $zero, WhileEnd0
# M[37] = M[23] + M[1]
lw $t1, 92($s1)
lw $t2, 4($s1)
add $t3, $t1, $t2
sw $t3, 148($s1)
# M[23] = M[37]
lw $t1, 148($s1)
sw $t1, 92($s1)
# Print M[23]
li $v0, 1
lw $a0, 92($s1)
syscall
# Print NewL as ASCII char
li $v0, 4
la $a0, NewL
syscall
j WhileStart0
WhileEnd0:
### End of complied code
addu $ra, $s7, $zero
jr $ra
.data
M: .word 0,1,2,3,4,5,6,7,8,9 # constants
.space 104 # variables a to z
.space 500 # temporaries
Blank: .asciiz " "
NewL: .asciiz "\n"
Tab: .asciiz "\t"
|
|
- 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
'?' { S } ':' { S } ']'
For example, suppose the input statement is on the left
and the MIPS output just for that statement is on the right below:
Input |
[ f%2 ? < 1; : < 2; ]
|
Output |
% spim -file source11.s
8
2
% spim -file source11.s
7
1
|
| |
MIPS Output (just for the portion
shown |
# Start of if-then-else number 1
# M[39] = M[15] % M[2]
lw $t1, 60($s1)
lw $t2, 8($s1)
rem $t3, $t1, $t2
sw $t3, 156($s1)
lw $t1, 156($s1)
beq $t1, $zero, ThenEnd1
# Print M[1]
li $v0, 1
lw $a0, 4($s1)
syscall
j ElseEnd1
ThenEnd1:
# Print M[2]
li $v0, 1
lw $a0, 8($s1)
syscall
ElseEnd1:
|
|
Give an initial test of your if-then-else using the following.
(This program prints a 1 if f is an
odd integer, and prints a 2
if f is an even integer.)
Sample Input 2 |
> f;
[ f%2 ? < 1; : < 2; ]
< N;
$
|
- if-then (no else) statements:
I --->
'[' E '?' { S } ']'
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 just needs to not output the
"else" parts shown in the previous item.
- Exponentiation operator ^:
U --->
F '^' U
| F
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.
(The mistake that I made here initially was not to return 1
as a special case if the exponent is 0. Eventually, I returned 1
for all exponents less than 1. My initial code went into an infinite
loop for exponent 0.)
Sample Inputs:
In addition to the two sample inputs above, here are three more:
Sample Input 3 |
Partial Output |
f = 0; g = 1; n = 0;
{ n - 8*5 ?
h = f + g;
< n; < B; < f; < B;
[ f%2 ? < 1; : < 2; ]
< N;
n = n + 1;
f = g; g = h;
} $
| % javac Tiny.java
% java Tiny < fib1.tiny > fib1.s
% spim -file fib1.s
0 0 2
1 1 1
2 1 1
3 2 2
4 3 1
5 5 1
6 8 2
7 13 1
|
which produces as output successive Fibonacci numbers followed
by a 1 or a 2 depending on whether the number is odd or even:
Full Output, or
Sample Input 4 |
Partial Output |
f = 1; g = 2; n = 3; > m;
{ m - n ?
< n; < T; < g; < T;
j = g; d = 2; t = 1;
{ t ?
[ j%d ? e = 0; : e = 1; ]
{ e ?
j = j/d; < d; < B;
[ j%d ? e = 0; : e = 1; ]
}
[ j - 1 ? t = 1; : t = 0; ]
[ d - 2 ? d = d + 2; : d = 3; ]
}
< N;
n = n + 1;
h = f + g;
f = g; g = h;
} $
| % javac Tiny.java
% java Tiny < fib2.tiny > fib2.s
% spim -file fib2.s
40
3 2 2
4 3 3
5 5 5
6 8 2 2 2
7 13 13
8 21 3 7
9 34 2 17
10 55 5 11
11 89 89
12 144 2 2 2 2 3 3
13 233 233
14 377 13 29
15 610 2 5 61
16 987 3 7 47
17 1597 1597
18 2584 2 2 2 17 19
19 4181 37 113
|
which inputs the number 40 and produces as output successive Fibonacci numbers followed
by the factorization of the number into primes: Full Output
Sample Input 5 |
Output |
> a; > r; > n; < N;
i = 0; s = 0;
{ n - i ?
t = a*r^i;
s = s + t;
< i; < T;
< t; < T;
< s; < N;
i = i + 1;
}
< N; < s; < T;
< a*(1 - r^n)/(1 - r);
< N; $ | % javac Tiny.java
% java Tiny < geom.tiny > geom.s
% spim -file geom.s
2
3
10
0 2 2
1 6 8
2 18 26
3 54 80
4 162 242
5 486 728
6 1458 2186
7 4374 6560
8 13122 19682
9 39366 59048
59048 59048
|
which inputs three numbers a, r, and
n and calculates the sum of a geometric series with
initial term a, ratio r, and
number of terms n. The program calculates the sum by
adding the terms, and compares the answer with the formula (shown below).
(The above program requires that your exponentiation operator return
a 1 for exponent 0.)
a + ar + ar2 + ar3 + . . . + arn-1 = a(1 - rn)/(1 - r)
Sample Input 6 |
Output |
> i; > j;
< i; < T;
< j; < N; < N;
n = 1;
{ 2*5 - n ?
b = 1;
< n; < T;
e = n ^ i ^ j;
f = n ^ (i ^ j);
g = (n ^ i) ^ j;
< e; < T;
< f; < T;
< g; < N;
n = n + 1;
}$ | % javac Tiny.java
% java Tiny < tab.tiny > tab.s
% spim -file tab.s
3
2
3 2
1 1 1 1
2 512 512 64
3 19683 19683 729
4 262144 262144 4096
5 1953125 1953125 15625
6 10077696 10077696 46656
7 40353607 40353607 117649
8 134217728 134217728 262144
9 387420489 387420489 531441
|
This last program compares the value of n^(i^j)
with (n^i)^j. (A few extra tabs were inserted into the output.)
What you should submit:
Refer to the submissions directions and to
deadlines at the top of this page. If two people are working
together, be sure that both signed in as a pair and that both
names appear at the top of the submission.
You should first give the compiler source program.
Then for the sample programs in turn, the MIPS code and the output
from running the MIPS code. You should complete as many of the
sample programs as you can. (Samples 5 and 6 require the
exponentiation operator, which I didn't give you enough information
to implement.)
Key ideas: This recitation just adds
features to the language. I hope that some of you are struck by how easy
it is to add such complex statements as general whiles and
if-elses,
where each can appear in an arbitrary nested fashion.
Revision date: 2013-02-15.
(Use ISO 8601,
an International Standard.)
|