abstract syntax tree is what happens when CFGs is applied to text (i.e., the parser traces the AST in time). Building an AST Generally, each production will have an action, which is the relevant computation. X -> Y1... Yn { action } Each symbol X admits an attribute X.val for each terminal, val is the associated lexeme for non-terminals, val is the expression’s value (i.e., from the values of the subexpressions) you job is to compose the subexpressions’ values and stick it into X.val. Notably, cycles are not allowed because we typically parse bottom-up, left ot right. actually doing it For instance, consider: E -> int { E.ast = mkleaf(int.lexval) } | E1 + E2 { E.ast = mkplus(E.ast, E2.ast) } | E.ast = E1.ast s-attribute …or synthesized attributes, are calculated from attributes of descendent in the parse tree. For instance, E.val is a synthesized attribute inherited-attribute, which is rarer, is attributes parsed from teh parent. declarative vs imperative style Two parsing ordering styles… Declarative style resolution is not specified parser figures it out Imperative style evalution is fixed suppose action manipulates global state an example Consider the grammar E -> Int | E + E | (E) For instance: E -> int { E.val = int.val } | E1 + E2 { E.val = E1.val + E2.val } | ( E1 ) = { E.val = E1.val } example E -> int | (E) | E + E and the string 5 + (2 + 3) We would draw a tree and crunch that into a data structure (where exprs can point to other structures.)

[[curator]]
I'm the Curator. I can help you navigate, organize, and curate this wiki. What would you like to do?