mainto be defined and procedures other than
printIntto be called.
You should do the portion of this lab headed "the basics" first, after which you can work on the remaining parts in almost any order. I would like to see everyone achieve at least a couple of the non-basic parts.
Remember to test your work frequently. You don't need to complete this whole section in order to conduct useful tests; each paragraph can be tested.
If you haven't already done this, revise the
statements so they don't neeed to have that one specific name before
the left parenthesis; they can have any name. Whatever name is used
should wind up in the
jal instruction in the generated
assembly code. This gives you relatively general procedure call
statements, though they all still require one integer argument.
Change the syntax of a program so that there can be any number of
procedure definitions (each with any name), rather than always just a
single definition of
main. Be sure to reset the
register allocators between generating code for each procedure and the
next, so that each procedure has the full range of registers
Because each procedure call passes in one argument, it would be
nice if each procedure were expecting an argument. The syntax of
a procedure definition should no longer have an empty pair of
parentheses. Instead, include the keyword
a variable name. This should be treated just like the corresponding
local variable declaration would, except that the assembly code for
the procedure should also include a
move instruction that
copies the argument value from
$a0 into the variable's
returnstatement, which can translate into a
jinstruction that jumps to a label just before the saved registers are restored from the stack. (Keep in mind that each procedure will need its own label.)
printIntas predefined with one argument.) Also, check that no two procedure definitions use the same name.
Unless you want every procedure to return an integer, you might
want to differentiate those that do from those that don't by starting
each definition with the keyword
You will need a
return statement that includes an
expression whose value should be returned. This expression's value
should be moved into the
$v0 register. After that, the
code should jump to the tail end of the procedure where registers are
restored from the stack.
You will want to allow procedure calls to serve as expressions. The generated assembly can be the same as for procedure call statements, provided that you limit the contexts in which procedure call expressions are allowed, as described in the following paragraph.
To keep the assembly code for procedure call expressions just as
simple as for procedure call statements, you will need to set up your
grammar so that calls can only appear as top-level expressions. That
is, a procedure call can show up as the right hand side of an
assignment statement, as the test expression in a
if statement, or as the expression in a
statement. A procedure call can't show up as a subexpression inside
an arithmetic expression, nor as an argument to another procedure
call. (Actually, the first argument would be OK, but there is no
point in getting too fancy.) Subject to this limitation, the same
assembly language can be generated as for a call statement. The
expression's value will wind up in
If you are really adventuresome, you could allow procedure call
expressions to serve as subexpressions, rather than only as top-level
expressions. However, this requires that you save any
$a registers before the call and restore them
afterward. Moreover, you can't leave the return value in
$v0 because the same overall expression might have more
than one procedure call, each with its own return value.