Quiz 9: Caesar cipher
Write a program in assembly that behaves as follows:
-
The user can type in some message on stdin (standard input) and can terminate the message with the end of file condition (Control-D).
-
The program reprints the message character by character. Like the cat program. However, the characters a, .., y, z are replaced with b, ..., z, a. That means the characters a to y are replaced with the next character in the alphabet, and z is replaced with a.
All other characters (e.g. upper case characters and punctuators) are reprinted unchanged.
Take advantage of the fact the in the ASCII table the characters a, .., z come in alphabetical order.
With some Unix magic you also can write a message first into a file:
1 2 3 | abcdefghijklmnopqrstuvwxz
Hallo, Welt!
hello, world!
|
and then redirect the file to stdin:
theon$ 1_ulm_build/caesar/ulm a.out < msg bcdefghijklmnopqrstuvwxya Hbmmp, Wfmu! ifmmp, xpsme! theon$
Required Instructions
Use the table for Ordered Relations (Session 5, Page 3) to provide the following instructions for conditional jumps:
-
ja (jump above) with opcode \(0\text{x}0C\). It can be used to branch if \(u(a) > u(b)\). The branch condition therefore is that a previous subtraction \(u(a) - u(b)\) was negative.
Example usage:
1 2 3
getc %1 # read character (its ASCII code) from stdin subq 'z', %1, %0 # compute: %1 - 'z' -> %0 ja not_in_range # jump if char in %1 comes after 'z' in ASCII table
-
jb (jump below) with opcode \(0\text{x}0D\). It can be used to branch if \(u(a) < u(b)\). The branch condition therefore is that a previous subtraction \(u(a) - u(b)\) was positive.
Example usage:
1 2 3
getc %1 # read character (its ASCII code) from stdin subq 'a', %1, %0 # compute: %1 - 'a' -> %0 jb not_in_range # jump if char in %1 comes before 'a' in ASCII table
Together with the instructions from Page 2 this is sufficient to realize the program. If you think more instructions are needed or would make it more convenient feel free to add more.
Getting Started
The right approach would probably be to figure out the perfect algorithm, represent it in a flow-chart and then implement.
Here I outline some hacker's approach where you approach the goal step by step. And each step will be expressed with some code that you can use as some kind of pseudo-code (but it actually compiles into an executable and solves some part of the problem).
After each step test it. So although you do not come up with the solution in a single step it will be a safe path.
First Step
Use the cat program. It already does everything, well, except for replacing the characters. In C coode you could express the cat program like that:
1 2 3 4 5 6 7 8 9 10 11 | #include <stdio.h>
int
main()
{
int ch;
while ((ch = getchar()) != EOF) {
putchar(ch);
}
}
|
Here the test:
theon$ ucc -o caesar0 caesar0.c theon$ caesar0 < ../caesar/msg abcdefghijklmnopqrstuvwxz Hallo, Welt! hello, world! theon$
Second Step
Now modify your assembly program by incrementing the stored ASCII code before you print it. So this replaces all characters with the next character in the ASCII table. So some characters are already replaced correct.
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdio.h>
int
main()
{
int ch;
while ((ch = getchar()) != EOF) {
++ch;
putchar(ch);
}
}
|
Here the test (note that the newline also gets replaced):
theon$ ucc -o caesar1 caesar1.c theon$ caesar1 < ../caesar/msg bcdefghijklmnopqrstuvwxy{Ibmmp-!Xfmu"ifmmp-!xpsme"theon$
Third Step
Only replace characters a to z with the next character. So except for z all characters are replaced correct.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <stdio.h>
int
main()
{
int ch;
while ((ch = getchar()) != EOF) {
if (ch >= 'a' && ch <= 'z') {
++ch;
}
putchar(ch);
}
}
|
Here the test (now the newline and punctuators are unchanged):
theon$ ucc -o caesar2 caesar2.c theon$ caesar2 < ../caesar/msg bcdefghijklmnopqrstuvwxy{ Hbmmp, Wfmu! ifmmp, xpsme! theon$
Last Step
Now deal with the special case that z should be replaced with a.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #include <stdio.h>
int
main()
{
int ch;
while ((ch = getchar()) != EOF) {
if (ch == 'z') {
ch = 'a';
} else if (ch >= 'a' && ch <= 'z') {
++ch;
}
putchar(ch);
}
}
|
Here the test:
theon$ ucc -o caesar3 caesar3.c theon$ caesar3 < ../caesar/msg bcdefghijklmnopqrstuvwxya Hbmmp, Wfmu! ifmmp, xpsme! theon$
Now, it is a matter of taste to replace ch <= 'z' with ch < 'z' ...
Submission for Quiz 8
Submit your description of the instruction set isa.txt and your program caesar.s with submit hpc quiz08 isa.txt caesar.s.