Some sample exam 2 questions:
- BRIEFLY define the following terms and give an example of how each term is used: (4 each, no more than six on the midterm)
- Precedence Declaration
- LR(k) Parsing
- SLR Parsing
- Canonical LR(1) Table
- LR(0) Items
- LALR Parsing
- Closure of a Set of LR(0) Items
- Syntax-directed translation
- Abstract syntax tree
- Static scoping
- Dynamic scoping
- Declaration of a name
- Use of a name
- Undeclared name
- Multiply declared name
- Symbol table
- Overloading
- Parameter passing
- Call by value
- Call by reference
- Call by value-result
- Base/immutable type
- Type constructor
- Type coercion
- Overloading
- Type polymorphism
- Name equivalence for types
- Structural equivalence for types
- Interpreter
- Just In Time Compiling
- Describe the relationship between a production and an item
in an LR(0) grammar. How does this relate to the notion of the
stack in an LR(0) grammar? Give an algorithm for constructing
the closure of a set of items LR(0) with respect to a particular
grammar.
- For the following grammar, construct the set of LR(0) states to
recognize viable prefixes of this language. Then fill out an SLR
parse table for this grammar and indicate whether the grammar is
ambiguous.
- S -> A $
- A -> -- A B | ++ A B | id B
- B -> -- B | ++ B | .
- What is the difference between SLR and LR(1) parsing? What changes
when constructing an LR table versus an SLR table? How does an LALR
parser differ from SLR and LR(1) parsers?
- In bison, how do you (1) resolve conflicts related to operator
precedence, (2) resolve conflicts due to operator associativity,
and (3) attach a syntax-directed translation action to a production?
- Below is a grammar for understanding simple arithmetic expressions:
- E -> E * E
- | E + E
- | ( E )
- | int
Assuming that precedence and associativity have been handled, what translation
actions would you add to the grammar to get it to print out the input
expression in a postfix notation (e.g., (3 + 5) * 4 would print out as 3 5 + 4 *).
Now add actions to print out the expression in a prefix notation (* + 3 5 4).
- Discuss how the semantic stack works for an LL parser and how an AST
can emerge from that stack. Show the actions you would attach to the
grammar in the previous question to build up an AST. Once you have
added the actions, show any further adjustments you would need to make
to the grammar to make it LL (1). (Assume * has higher precedence than
+ and both are left associative.)
- Describe static and dynamic scoping and how they differ. Give an example
of a program that has different output assuming static versus dynamic
scoping.
- Most programming languages have scoping rules with respect to variables.
Why? Give an example of a situation that requires scoping rules to
resolve (and where scoping is useful). Would it be possible to avoid
having scoping rules (and if so, what are the advantages and
disadvantages of your approach)?
- Define parameter passing and the parameter passing methods call by
value and call by reference. Give an example of a program that works
differently under the two different mechanisms.
- What are the two main jobs of a symbol table? What types of errors
does it catch in performing these jobs?
- What are the main operations for a symbol table? Discuss the data
structures associated with a symbol table maintained as a list of
hashtables and how the operations of a symbol table are implemented
in that case. Give an example of what your symbol table would look
like for a sample program.
- Answer the previous question but where the symbol table is maintained
as a hash table of lists.
- What is a type system? Who defines it and how is it used in creating
a compiler?
- Give three examples of tasks that are typically performed in a type
checker. What types of errors are recognized in a type checker?
- What are three of the constructors available for constructing types?
What operations are typically associated with these constructors and
how are they used in type checking?
- What is the difference between static and dynamic type checking?
What is the difference between name and structural equivalence? What
is a cyclic type? Give examples to demonstrate your answers.
- Show an outline of how a piece of code might work to type check a
divide operator that can apply to two operands of type int or float but
does not apply to values of type bool. How would your code change if
coercion from bools to ints and ints to floats is allowed (but not bools
to floats)?
- How would you type check a for statement from C++? What symbol table
issues are introduced by a for statement?
- What does it mean for a name to be overloaded? What sections of your
compiler must be adapted to allow for overloading?
- What are the advantages and disadvantages of an interpreter? Describe two different types of interpreters (as discussed in class).
- What are some of the key questions that must be answered in order to implement an interpreter that works by first parsing an entire file and then executing the resulting AST (you may indicate other steps of compilation you think should be included before intepretation occurs)?