First, you have pseudo code, so very good!
Next, as a general rule, make sure your pseudo code actually works (so test it), as debugging design issues in assembly is very difficult, and small changes to the design (in pseudo code) can require large changes in the assembly (e.g. rewriting a lot of code).
You're doing some things in Python that are rather involved in assembly language, so you ought to write your pseudo code in C first, since that will make you address those differences.
in
— represents a loop in C or assembly
+=
and +
on strings — represents either some simple operations on global buffer, or, some complicated memory management (hint: go for the former)
.isDigit()
is conditional conjunction or disjunction depending on how you code it
.update()
will need some alternative translation
**
also represents a loop in C or assembly
The next big complication is the calling of functions. Function calling in MIPS assembly language is probably the most complex topic, due to the requirements register usage and stack handling.
Recursion is a bit of a red herring for assembly language: it appears hard but it is actually no harder and even no different in assembly language than functions calling other functions without involving recursion (this is true assuming the assembly instruction set has a runtime stack for function calling, MIPS does (but if it didn't you'd have to simulate a call stack)).
You'll need to study up on this, it is somewhat involved. Look for other example, fibonacci, for example.
When translating to MIPS one function that calls another function, we need an analysis of variables and values that are "live across a function call". These variables need special consideration, since some registers are wiped out by calling another function. You'll see this in fibonacci, for example.
Part of recursive fib, is fib(n-1)+fib(n-2)
. The return value from the first call to fib
must be given special handling since it ultimately needed for the addition (+
), so it is live across the 2nd call to fib
, and without special handling, will be lost by making that 2nd call. Also, n
is live across the first call yet needed again to make the second call, and without some special handling would similarly be wiped out by that first call.
This is a consequence of functions calling functions in MIPS whose instruction set does not automatically stack things and requires the assembly language programmer or compiler to do so manually. Some or all of this is also needed on other architectures. This is not a consequence of recursion, so a(n)+b(n)
would involve the same requirements for analysis and special handling of variables and values.
When you have a good algorithm (e.g. in C) and it works, your ready for assembly. Translate your data first: global variables. Next translate functions, similarly: translate your local variables into MIPS, then translate each structured statement, (e.g. if
, for
) following its assembly language pattern. Nested structured statements also nest in assembly language, and it doesn't matter if you translate the inner statements first or outer statements first, as long as you exactly observe the nesting.
In order to translate structured statements into assembly I first use intermediate forms in C, for example:
for ( int i = 0; i < n; i++ ) {
..body of for..
}
Note that in the above the "body of the for" could easily contain control structures, like another for
or an if
. These then, are nested structure statements — just translate them one at a time, each structured statement following its complete pattern, and make sure the nesting in C is equally observed in assembly.
Translate for
to while
:
...
int i = 0;
while ( i <n ) {
..body of for..
i++;
}
...
Next, apply "if-goto-label" intermediate form :
...
int i = 0;
loop1:
if ( i >= n ) goto endLoop1;
..body of for..
i++;
goto loop1;
endLoop1:
...
As you apply patterns, you'll need to create label names; new label names for each application of the pattern.
Then this translates into assembly fairly easily. If the "body of for" also has control structures make sure their entire translation is embedded and located at the "body of for" section in the above pattern.
Notice how the i < n
in assembly sometimes translates into i >= n
— here because control flow in if-goto-label form make is say: exit the loop on the logically opposite condition of the while
statement in C.
And finally, translate expressions within statements in your C code into assembly.