Computer Science 301 - 2002


Tutorial for week 13 - Multifunction programs in Parva - Solution

In this week's practical we shall be extending the Parva compiler to recognise and compile code for programs with more than one void function. Although these will not allow for parameters, inter-function communication can be achieved through the use of global variables, as exemplified by

      int global1, global2;

      void routine () {
        int local1, local2;
        local1 = global1 + local2;
      }

      void main () {
        int x;
        routine();
      }

where, to make it simple, all global declarations are to be made before any functions are defined, and where it is intended that the run time organisation will be on the lines of

              Stack frame for function                       Globals
      .-----------------------------------.        .--------------------------.
      |        |        |        |        |  ....  |        |        |        |
      `-----------------------------------'        `--------------------------'
                                          ^                                   ^
                                       CPU.BP                              CPU.GP

with addressing opcodes extended so that ADR -Local will push a local address (computed relative to CPU.BP) onto the stack and GAD -Global will push a global variable address (computed relative to CPU.GP) onto the stack. This tutorial explores some of the aspects of the system that you will need to incorporate into the compiler.

(a) The first Parva compiler had productions like

     Parva      = "void" "main" "(" [ "void" ] ")" Block .
     Block      = "{" { Statement } "}" .
     Statement  = ConstDeclaration | VarDeclarations | Assignment ...
     Assignment = Variable ( "=" Expression | "++" | "--" ) ";"

How would these have to be altered to handle multi-function programs?

     Parva      = { ConstDeclaration | VarDeclarations } { function } .
     Function   = "void" Identifier "(" [ "void" ] ")" Block .
     Block      = "{" { Statement } "}" .
     Statement  = ConstDeclaration | VarDeclarations | Assignment ...
     Assignment = Variable ( "=" Expression | "++" | "--" ) ";"

(b) Suggest what the runtime arrangement would be for the above program at the instant where main has started execution.

        Stack frame for main           Globals
      .--------------------------------------------.
      |   x    |   RA   |  DL    | global2| global1|
      `--------------------------------------------'
                                 ^                 ^
                              CPU.BP            CPU.GP

(c) What would the runtime arrangement be at the instant where main has called routine and routine has just started execution?

              Stack frame for routine       Stack frame for main           Globals
        500      501      502      503      504      505      506      507      508
      .--------------------------------------------------------------------------------.
      | local2 | local1 |   RA   |   DL   |   x    |   RA   |  DL    | global2| global1|
      `--------------------------------------------------------------------------------'
                                          ^                                            ^
                                       CPU.BP                                       CPU.GP

(d) Suggest what sort of code you should generate for the above program. You will clearly need to have two new opcodes, say CAL X to call a routine whose code begins at location X, and RET, to be able to return from a routine back to the caller.

             DSP   2       ; space for globals
             CAL   main    ; call main
             HLT           ; call it a day

  routine:   DSP   4       ; space for locals local1 + local2 + DL + RA
             ADR  -1
             GAD  -1
             VAL
             GAD  -2
             VAL
             ADD
             STO           ; local1 = global1 + local2;
             RET

  main:      DSP   3       ; space for local x + DL + RA
             CAL  routine  ; routine();
             RET

(e) Suggest how an emulator might handle the CAL and RET opcodes.

(f) What modifications would be needed to the symbol table handler to deal with such programs?

(g) To deal with the problem of mutually recursive functions one could introduce the concept of the "function prototype", as exemplified by

      void routine2 ();  // prototype, header only

      void routine1 () { routine2(); }

      void routine2 () { routine1(); }

      void main () { routine1(); }

What implications does this have for the grammar and the compiler, and how do you handle these?


Home  © P.D. Terry