CSC362 2004S, Class 24: Semantic Actions Admin: * Train data: 1:11 * Mea Culpa (or why never to ask SamR to write letters of recc.) * Break * Yay Jonathan! Yay Grinnell Putnam team Overview * Adding attributes to parse trees * Example: Evaluating expressions * Computing the values of attributes * Example: Typing expressions * Example: Sequences of assignments Reminder: Status * Front end: From source code to "intermediate code" * Lexical analysis (done) * Syntactic analysis (mostly done) * Type checking (now) * Intermediate code generation (soon) * Back end: From "intermediate code" to target code * Optimize * Translate * Optimize Attribute generation: Traverse the parse tree and compute "values" based on the structure of and values in the parse tree. * Traditionally, we attach these computed values to nodes in the treeq * Values are computed based on neighboring values * The value of the root is the "endpoint" of the process Traditional computer science method: add rules to the grammar that specify how values are computed E.g., Production: exp0 ::= exp1 PLUS exp2 Associated rule: exp0.value = exp1.value + exp2.value BUT THIS PRODUCTION IS NOT IN THE NORMAL UNAMBIGUOUS EXPRESSION GRAMMAR that uses term, factor, and such. exp0 ::= exp1 PLUS term exp0.value = exp1.value + term.value exp0 ::= exp1 MINUS term exp0.value = exp1.value - term.value exp ::= term exp.value = term.value term0 ::= term1 TIMES factor term0.value = term1.value * factor.value term0 ::= term1 DIVIDE factor term0.value = term1.value / factor.value term ::= factor term.value = factor.value factor ::= OPEN exp CLOSE factor.value = exp.value factor ::= NUM factor.value = NUM.value [Example on board] Observation: In this exampel, all the attributes are computed from attributes of children Question: Are there ever times we want the attributes to be computed from attributes of parents or neighbors? * One possibility: ::= * Symbol table: For each variable, give type of variable (and perhaps its memory location) * One way to compute a table .table ::= map(lambda (id) .type) .ids "The table assigns each id in id-list to the type given by type-id" * Another way to compute the table ::= .type = .type .in-table = empty-table ::= .out-table = .in-table + (.id -> .type) 0 ::= COMMA 1 1.in-table = 0.in-table + (.id -> .type) 1.type = 0.type 0.out-table = 1.out-table * ObservatioN: The first way is all "bottom up"; the second way is both top-down and bottom-up Suppose you want to be general about this: Allow both top-down and bottom-up dependencies of values. How do you decide what order in which to compute the attributes? * The theory response: Build a directed graph of dependencies and topologically sort it * Topological sort: Given a directed graph, put the nodes in order such that: No node appears before any of its predecessors * The practice response (1): Limit your rules (e.g. to only bottom-up) * Another practice response: Write programs that know how to navigate Almost everything you want to compute from here on (types, symbol tables, code) are done by walking the tree either using these kinds of rules or by writing "navigation programs" * next class: "Navigation programs" that type check