The Problem

In this assignment we will continue our semantic analysis and semantic error generation of the abstract syntax tree. We will also add in the I/O library. Continue with files printree.cpp and sematic.cpp as in the last assignment.

Tiny Grammar Change

You may optionally change your grammar to only allow
mutable :  ID '[' exp ']'
Instead of:
mutable :  mutable '[' exp ']'
The latter was left from a previous version of the language. This eliminates the need to the second version of this error message: "ERROR(%d): Cannot index nonarray.\n" which does not have a %s in it. I will no longer be testing for that error (see error list next).

Semantic Errors

We will generate more errors that are tagged with useful line numbers and we will go back and improve a couple of error messages for readability. The list of all errors to be generate both last assignment and this are found in this organized list. A careful sdiff between the error list from last time and this time can be found in this all errors diff file. Note that some of the diffs are lines that are altered just a bit. The kinds of changes we have are:

  1. added single quotes to two warnings.
  2. removed the near duplicate error message: "ERROR(%d): Cannot index nonarray.\n"

Your job in writing the treeTraverse routine is to catch a variety of warnings and errors and duplicate my output for any input given. The test basicAll5.c- in the test suit will at least touch every error message and warning.

You should keep count of the number of warnings and errors and report that at the end of a run.

Here are some details:

  • For IO routines output, outputb, outputc, input, inputb, inputc, outnl, you will need to hand construct prototype equivalents into the abstract syntax tree. They have the C- prototypes:
    void output(int)
    void outputb(bool)
    void outputc(char)
    int input()
    bool inputb()
    char inputc()
    void outnl()
    The line numbers for the I/O routines are -1. The name for any parameter variables is "*dummy*".
  • While, If, and Elsif should check they have Boolean tests.
  • Loop should be sure that the range is set to things of integer type.
  • Assignments and operators should check that they have the proper type. Types of expressions will have to be passed up. Beware of Cascading Errors as discussed in class. Hint: it might be useful to have an undefined class that is used to when variables are undefined or the type is undefined.
  • For return check for return type matches. Note that it is easy to check that the return is of the same type as function. It is hard to check that a return is made out of every exit so we will not issue a error for that. However, I have added a warning for a much simplified check. Note that routines that do not return a value use the return without an argument. A routine whose code falls out the bottom will perform a return of the right type by default. (More on the value returned in the next assignment.)
  • For break check that the break is inside a loop.
  • For Ids you have to see if the variable has been defined or not and set the type of the Id node to the type of the declaration. If the Id is undefined then set the type of the id in the expression to UndefinedType (or some other indicator that the type information is missing). This is a type that when it does not match the required type of parent nodes it does not generate an error!!! Again to prevent cascading errors. Note: You may have to guard against UndefinedType in many places. Encapsulate redundant code as functions. There is not a lot of duplicate code in this assignment.
  • Errors for initialization include an error if the initialization value is not constant. This means tracking what parts of an expression are constant. Note at parse time you could use the attribute grammar aspect of Bison to compute the value of a constant expression and substitute that for the subtree! But that is NOT for us now.
  • For Ids, you can have arrays that are indexed. Once they are indexed, their type becomes nonarray. Check for indexing of nonarrays and using unindexed arrays where they can't be used.
  • Ids that are arrays can also be prefixed with '*' operator. That lets you get at the size of the array. Every array stores not only the values in the array but its size. This means that an array of size 10 (e.g. frog[10]) secretly needs 11 spaces allocated to it. More about this in the code generation assignment.
  • The function call is the trickiest of all. You must use the symbol table lookup to find the definition node and from there compare the types in the parameter list with the types of the arguments given. This means you must compare the type of the supplied argument to the type of the formal parameters for a type match. Also if you run out of formal parameters before you run out of actual arguments you need to issue an error. Same for running out actual arguments. See the error messages for an appropriate error.
  • Finally, if the function main is not defined then you must print out the error:
    ERROR(LINKER): Procedure main is not defined.


Homework will be submitted as an uncompressed tar file to the submit page which can be found in the services section of the class page. You can submit as many times as you like. The LAST file you submit BEFORE the deadline will be the one graded. Absolutely, no late papers. For all submissions you will receive email at your uidaho address showing how your file performed on the pre-grade tests. The grading program will use more extensive tests, so thoroughly test your program with inputs of your own.

If you have tests you really think are important or just cool please send them to me and I will consider adding them to the test suite.