You will be assigned one of the following tasks. Please let me know prior to Monday January 29 any preference you might have. I will give you a definite assignment no later than Wednesday January 31. Most students will be assigned the first task, compiling global declarations, which is the primary goal to be accomplished by this phase. This phase ends on Sunday February 18.
You should use the "bucket" module to process the type qualifiers, storage class specifiers and type specifiers. The "types" module should be used to represent the type of the declaration. The declared identifier should be installed in the symbol table along with the type, the storage class (if one), and the qualifiers (if any).
You should also generate Alpha code for declarations that require it. In doing this, two code generation utility functions should be written. The first should evaluate the size of a variable in bytes on the Alpha, given the C type of the variable. The second function should provide the alignment requirements for a variable on the Alpha, given the C type of the variable. The Alpha code to generate will be discussed in class.
If the declaration does not declare an identifier, it is an error. Are there any other semantic errors that need to be reported?
A global variable must be utilized that turns on and off special processing in the scanner. The hard part is deciding when to set and clear this global variable.
In addition to the coding and testing, this assignment will require you to discuss in class both the typedef "problem" and your solution. Most probably this will happen later in the semester, after this phase is complete.
A big issue that must be decided is how to internally represent the constant values. Should we keep them as strings or convert them to their "native" formats? If we convert them, are there portability issues? (We would like to restrict all machine-specific code to the code generator.) You will be expected to lead the discussion on making these decisions.
A second concern is to do the necessary semantic checking. In particular, does a given constant value fit in their designated type on the target machine? And, again, how do we implement this in a portable way?
Then you will write actions to build trees for all the syntax rules for expressions and statements. Note that you are not doing semantic analysis, but rather you are simply building "raw" trees with many fields (e.g. type) not yet filled in. Allocation of tree nodes should be made from an expandable pool, which will allow all previously allocated trees to be re-claimed by simply re-setting the pool. You also need to write a debugging routine that will display a tree in human-readable form (perhaps one tree node per line).
In addition, write two routines that will check whether a tree denotes an "lvalue" or a "modifiable lvalue" (ANSI C, section 3.2.2.1). Conceptually these functions return a Boolean value, either true or false.
Harbison and Steele is a good reference for this task. See section 6.3 for information about conversions. Section 7.1.1 has a concise discussion of lvalues.
The code for a "skeleton" scanner, a "skeleton" parser, the "bucket" module, the "message" module, the symbol table, and the "types" module can be found in ~cs712/public/pcc3. This directory also contains a Makefile. Note that the compiler will read from stdin and write to stdout.
Comments and questions should be directed to pjh@cs.unh.edu