Computer Science 301 - Translators


Tutorial 10 - Implementing the Switch statement in Parva

In last week's tutorial we asked you to investigate the static semantics of a version of the switch statement described by the context-free productions:

    SwitchStatement
    =  "switch" "(" Expression ")" "{"
          { CaseLabelList Statement { Statement } }
          [ "default" ":" { Statement } ]
       "}" .
    CaseLabelList = CaseLabel { CaseLabel } .
    CaseLabel     = "case" [ "+" | "-" ] Constant ":" .

A grammar suitably attributed to do so might look as follows:

  SwitchStatement<StackFrame frame>         (. int expType;
                                               ArrayList<Integer> labelList = new ArrayList<Integer>();
                                               boolean hasClauses = false; .)
  =  "switch" "("
       Expression<out expType>              (. if (isRef(expType) || expType == Entry.noType)
                                                 SemError("invalid selector type"); .)
     ")" "{"
        { CaseLabelList<expType, labelList>
          Statement<frame>                  (. hasClauses = true; .)
          { Statement<frame> }
        }
        [   "default" ":"
            { Statement<frame>              (. hasClauses = true; .)
            }
        ]
     "}"                                    (. if (!hasClauses) Warning("Empty switch statement"); .) .

  CaseLabelList<. int expType, ArrayList<Integer> labelList .>
  =  CaseLabel<expType, labelList>
     { CaseLabel<expType, labelList>
     } .

  CaseLabel<. int expType, ArrayList<Integer> labelList .>
                                            (. ConstRec con;
                                               int factor = 1;
                                               boolean signed = false; .)
  =  "case"
     [ ( "+" | "-"                          (. factor = -1; .)
       )                                    (. signed = true; .)
     ] Constant<out con> ":"                (. if (!compatible(con.type, expType)
                                                   || signed && con.type != Entry.intType)
                                                 SemError("invalid label type");
                                               int lab = factor * con.value;
                                               if (labelList.contains(lab))
                                                 SemError("duplicated case label");
                                               else labelList.add(lab); .)

Firstly - we have suggested the use of the ArrayList collection to build up a list of labels. Would it be possible or preferable to use some other data structure? If so, what would this be, and why, and if not, why not?

Secondly - how could we add to the grammar to generate code for the PVM?

The semantics here require that the Expression be evaluated once, and its value compared for membership of one of the sets of CaseLabelLists, a match being followed by execution of the associated statement list. If no match is found, the statement list associated with the optional default clause is executed (or, in the absence of the default option, no action is taken at all). There are many variations on this theme, but for the one illlustrated here we suggest that (a) there is an automagic BreakStatement introduced at the end of each statement list so that there is no need to include an explicit BreakStatement in each statement list, although these may occur if needed (b) the concept of "falling through" in the absence of an explicit BreakStatement thus does not apply (c) more than one CaseLabel may be associated with a given statement list and (d) each CaseLabelList must be separated from the next one by at least one statement in its statement list (even if this is an empty statement).

Here is an example of a (silly) switch statement:

    switch (i + j) {
      case 2   : if (i === j) break; write("i = " , i); read(i, j);
      case 4   : write("four"); i = 12;
      case 6   : write("six");
      case -9  :
      case 9   :
      case -10 :
      case 10  : write("plus or minus nine or ten"); i = 12;
      default  : write("not 2, 4, 6, 9 or 10");
    }

It might occur to you that one way to implement this would be to generate code matching an equivalent set of IfStatements on the lines of the following, where we have taken some liberties with syntax, though the effect should be obvious:

        if    (i + j == 2) { if (i === j) goto out; write("i = " , i); read(i, j); goto out; }
        elsif (i + j == 4) { write("four"); i = 12; goto out; }
        elsif (i + j == 6) { write("six"); goto out; }
        elsif (i + j in (-9, 9, -10, 10)) { write("plus or minus nine or ten"); i = 12; goto out; }
        else write("not 2, 4, 6, 9 or 10");
    out: ...

but it should not take much imagination to see that we might initially be at a loss for a way repeatedly to inject the code for the selector Expression into the code generation process if we are restricted to use an incremental compilation technique.

Feel free, however, to add opcodes to the PVM if you feel this would make life easier.


Home  © P.D. Terry