Syntax-Directed Translation for Infix → Prefix Arithmetic Expressions (Annotated Parse Trees)
To translate arithmetic expressions from infix (e.g., ) into prefix (Polish) notation (e.g., ), a standard approach in compiler construction is to use a syntax-directed translation scheme 2. The key idea is to attach semantic actions to productions of a grammar so that, as the parse tree is constructed, we compute the corresponding prefix string.
We will use a grammar with precedence encoded via nonterminals for addition/subtraction vs. multiplication/division. Then we define synthesized attributes that compute a string .val representing the prefix form of each subtree 2.
Mermaid view of the translation concept:
Footnotes
-
(Compiler Construction) Syntax-directed translation overview and attribute evaluation: https://en.wikipedia.org/wiki/Syntax-directed_translation - Defines SDT and attributes. ↩ ↩2
-
(Compiler Construction) Attribute grammars and synthesized attributes: https://en.wikipedia.org/wiki/Attribute_grammar - Covers synthesized vs inherited attributes and evaluation on parse trees. ↩ ↩2
Grammar (with precedence) and translation attributes
Let the grammar generate expressions with correct precedence and left associativity:
Here:
- handles
+and- - handles
*and/ - handles parentheses and identifiers/numbers
We define a synthesized attribute 2val for each nonterminal; the attribute is computed from children nodes in the parse tree:
-
For :
E.val = "+" + " " + E1.val + " " + T.val
-
For :
E.val = "-" + " " + E1.val + " " + T.val
-
For :
E.val = T.val
-
For :
T.val = "*" + " " + T1.val + " " + F.val
-
For :
T.val = "/" + " " + T1.val + " " + F.val
-
For :
T.val = F.val
-
For :
F.val = E.val
-
For :
F.val = lexeme(id)(or just the number token as a string)
keyword="Attribute computed at a node from the values of its children"}
keyword="A translation scheme that computes output values via grammar-attached semantic actions"}
keyword="Tree representation of how input tokens match grammar productions"}
keyword="Notation where the operator precedes its operands (e.g., + a b)"}
Footnotes
-
(Compiler Construction) Syntax-directed translation overview and attribute evaluation: https://en.wikipedia.org/wiki/Syntax-directed_translation - Defines SDT and attributes. ↩
-
(Compiler Construction) Attribute grammars and synthesized attributes: https://en.wikipedia.org/wiki/Attribute_grammar - Covers synthesized vs inherited attributes and evaluation on parse trees. ↩
Constructing the syntax-directed translation scheme (SDT) for infix→prefix
- 1Step 1
Use nonterminals like (for ), (for , and (for parentheses/ids) so the parse tree structure matches operator precedence.
- 2Step 2
For each nonterminal (), define a synthesized attribute
valthat will contain the prefix representation of that subtree. - 3Step 3
For each binary operator production (e.g., ), set the parent’s
valto the operator followed by the child prefixes in the correct order:op left right. - 4Step 4
For , set
F.valto the token lexeme; for parentheses, forward the inner expression value. - 5Step 5
Because the attributes are synthesized, once the parse tree is built the prefix strings are computed bottom-up, yielding the final result in
E.valat the root.
Annotated parse tree for
Given the grammar and , with left associativity, the expression parses as:
- First compute , then add
So the parse tree shape is:
- Root: producing
- Left child: producing
- Right child: for
2
Annotated parse tree (with prefix values):
A more explicit tree (ASCII-style) with synthesized attributes:
-
-
-
-
-
-
id(9)⇒
-
-
--
-
id(5)⇒
-
- Apply :
-
+-
-
id(2)⇒
-
- Apply :
-
-
Final prefix output:
Annotated parse tree for
Because has higher precedence than , the parse is:
- First compute , then subtract from
So we expect:
- Root: producing
- Left child: for
9 - Right child: producing
Annotated parse tree:
-
-
-
-
-
id(9)⇒
-
-
--
-
-
-
id(5)⇒
-
*-
id(2)⇒
- Apply :
-
-
- Apply :
-
-
Final prefix output:
Tip: Use synthesized attributes for prefix strings
If val is synthesized, you only need bottom-up evaluation on the parse tree: each operator production prepends the operator and concatenates child prefix strings.
Warning: Parentheses must forward the inner expression
For , do not add extra operator symbols—set so grouping in the infix expression is preserved in the parse tree.
From infix tokens to prefix string
Tokenize
1) LexingRead numbers/ids and operators: 9, -, 5, +, 2 or *."
Build parse tree
2) ParsingUse grammar so precedence is reflected in tree shape."
Apply semantic actions
3) TranslationCompute val at each node using rules like E.val = "+" + E1.val + T.val."
Return root attribute
4) OutputThe final prefix expression is the synthesized attribute at the start symbol ()."
Expected prefix forms (using correct precedence/associativity)
Compare the two infix inputs and their computed prefix outputs.
Common pitfalls and checks
Syntax-Directed Translation (SDT) for Expression Grammars
Knowledge Check
For the production , what is a correct synthesized-attribute semantic rule to compute the prefix string?