Class 16: Abstract parse trees
Held Monday, October 5, 1998
- Remember that
assignment 5: parser
and assignment 6: parsing are
due Wednesday at 5pm. Are there any questions on those assignments?
- As you might guess, the next three (!!) assignments are ready. Two
are due before break, one is due after break.
- Assignment 7 is to extend your
parser to build abstract parse trees.
- Assignment 8 is a short
collection of written work on attribute grammars and type checking.
- Assignment 9 is the type
checker for your compiler. It is not due until after break.
- The midterm examination will be a take-home exam. See the
review sheet for more information.
Note that I will do my best to have all written assignments
graded by the time of the midterm.
- Tonight at 8pm in the South Lounge (I think) is a cool talk by Carey
Heckman on intelectual property, the Internet, and liberal arts
education. Consider attending.
- If you haven't done so already, you should start to read Chapter five.
There appear to be a lot of errors in that chapter (or at least in the
code in the Java version), so make sure to have the
- It appears that there have been a number of rumours about hiring in the
department for this year. The college and the department have been
doing everything we can to find people. It's just a horrible year to
be hiring. A number of schools nationwide found themselves in the
same situation that we did (or even worse situations).
- If it feels like we're going slowly, we're not. While we're covering
a little less than I'd hoped, we're still on track to finishing our
projects on time. We've also covered what takes 342 pages to discuss
in the textbook I previously used.
- Recall that we were looking at evaluation of expressions in the
context of assignments. In order to do such evaluation, we
needed to compute a symbol table that mapped each
symbol to its corresponding value.
- We found that we had to pass the table both down and up the parse
tree. In particular, an assignment statement might need a
symbol table to determine the value assigned (i.e., if variables
appear in the expression), but also updates the table.
- We might write
statement ::= ID ASSIGN exp
exp.table = statement.intable
statement.outtable = statement.intable + ID.str -> exp.val
- Similarly, when dealing with sequences of statements, we might write
slist ::= statement SEMI slist1
statement.intable = slist.table
slist1.table = statement.outtable
- We also need to pass tables down through expressions. For example,
exp ::= exp1 PLUS term
exp1.table = exp.table
term.table = exp.table
factor ::= id
factor.value = lookup(factor.table, id.sym)
- Recall that attribute grammars extend traditional BNF
grammars with attributes and rules for computing
- An attribute is an value one might associate with a symbol.
In our examples, we associated parse tables, numeric values,
and types with various parts of the parse tree.
- A rule describes how to compute attributes based on surrounding
attributes. Each rule is associated with a particular production.
- There are, in effect, three kinds of attribute dependencies
- An attribute of a node may depend on an attribute or attributes
of its parent node. Such an attribute is called inherited.
- An attribute of a node may depend on an attribute or attributes of
its children. Such an attribute is called synthesized.
- An attribute of a node may depend on an attribute or attributes of
its siblings. Such an attribute is also called inherited.
- How are attributes computed? By applying the rules. How do we
decide which order to apply the rules? In the abstract, we determine
dependencies (e.g., attribute x depends on attribute y)
do a topological sort of attributes based on those dependencies, and then
apply the rules in order.
- In practice (e.g., when using typical parser generators), we apply the
rules when we apply the production.
- In predictive parsers, we can apply different rules at different
``stages'' of the production. This is because we choose a RHS as
soon as we see a symbol. Predictive parsers permit synthesized
attributes and selected inherited attributes (a nonterminal can
inherit from its parent and from ``prior'' siblings).
- In LR parsers, we apply rules after completing the production. Since
we don't know which RHS we're matching until we've completed the RHS,
we can't do intermediate work. LR parsers typically permit only
- Different compiler designers differ in how much work is done by
this syntax-directed analysis. Some put much of the work
in the rules (e.g., it is even possible to generate code). Others
suggest doing multiple phases.
- Note that in LR parsers, type checking is difficult to do purely
``all at once''
yacc (yet another compiler compiler) is the standard
general-purpose parser generator. It's been around for a long time.
bison is the GNU project's version of
It's slightly nicer. If you want to read a lot about
yacc, read the
CUP is the Java equivalent of
uses a slightly different syntax.
- For all of these, we typically name our terminals and nonterminals.
- To simplify grammars, we are allowed to assign precedence and
associativity to rules.
Precedence and associativity help resolve shift-reduce and
- In Appel's style of compiling, the only syntax-directed translation
we do is the construction of abstract syntax trees.
- Such trees provide a way of representing programs that is somewhat
independent of not just the concrete syntax, but also the grammar
used to do the parsing.
- Recall that for some types of parsing it becomes necessary to
write fairly unreadable rules.
- Why build abstract syntax trees?
- They make the syntax tree independent of the grammar used to construct
the tree. This is particularly useful as we write grammars that
don't match the logical structure (e.g., left-factored grammars).
- They permit us to focus on the core structure, without the syntactic
sugar. For example, we don't need to worry about helper symbols nor
about ambiguity in designing abstract syntax trees.
- They unify related structures. For example, there are at least two
ways to declare variables in Tiger. We can use an empty type
identifier for variable declarations that don't contain such an
- They allow us to change the surface syntax of the language without
changing the rest of the compiler. (Note that this is rarely done.)
- Created Friday, October 2, 1998 (blank template).
- Filled in the details on Monday, October 5, 1998. The section on
parser generators was taken from the previous outline. The
introductory sections, although newly written, were based on
dicussions in the previous classes and the previous outline.
- On Wednesday, October 7, 1998, I removed topics not covered
(selected issues in abstract syntax trees and a section on
environments) and added ``selected reasons to use asts''.
- On that same day, after class, I removed the body of the outline
since the class digressed into a long but worthwhile proof session.
Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.
Source text last modified Wed Oct 7 15:35:18 1998.
This page generated on Thu Oct 8 10:51:32 1998 by SiteWeaver.
Contact our webmaster at firstname.lastname@example.org