2

I am trying to write the semantic rules for syntax directed translation of an expression following a given cfg into 3 code representation.

Consider,

enter image description here

Here, Why is || operator required ? gen() is the only thing needed it seems as it does what is required .

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
Novak007
  • 426
  • 1
  • 9
  • 23

1 Answers1

4

This set of rules describes an attributed grammar, a scheme for computing attributes for a tree. Such schemes are almost always purely functional (no side effects). It is computing attributes at each rule/tree node, named X.Y in the notation they are using, where X stands for the rule/tree (e.g S and E with variants E1 and E2. Y stands for the computed attribute (in this case, there are "code" and "place" attributes.

Each rule corresponds to a subtree, E = E1 + E2 to the tree (E+ E1 E2) in S-expression notation. "E.code:=..." means compute "..." and assign the result to attribute "code" at the root of the "E(+)" tree (a "synthesized" attribute); "E1.code:=..." means compute "..." and assign to the "E1" leaf (an "inherited attribute"). "X.Y" not on the left side of an assignment means "fetch the value of attribute Y on node X".

The computations used are "newtemp" (this should really be "newtemp()" as it isn't a variable, but a function), "gen( ... )" and "||". "gen" clearly is doing the key work of manufacturing the individual instructions. But what is its result? A simple answer would be "a string"; a more sophisticated answer might be a binary representation of the generated instructions.

The purpose of the "||" is assemble the results of code generation steps into a stream of generated code; if the gen result is a string, "||" could be a string concatenate, if the result is a binary records, it is concatenating lists of binary records into a single list.

You may have been confused by thinking that "gen" simply produced its results and wrote them an unmentioned output stream. That would violate the spirit of the attribute grammar, which does not allow such. The "||" operator is needed to compute functional results being passed up the tree.

You might bend the attribute grammar so gen does write to a hidden stream. In that case all the "||" operators go away, as do mentions of previously computed results such as "E1.code". You can make this work IF your attribute tree evaluation is left-to-right, (a big) and, the order in which the generated subtrees are combined to produce the result stream is correct when done strictly left to right. If the attribute grammar said "E.code = E2.code || E1.code || gen(...)", that is, it was reordering the generated code, then the hidden output stream trick will not work.

Taking a different perspective: imagine you wanted to evaluate this attribute grammar quickly on huge programs. If you stick to a pure functional grammar, then you can evaluate all the attributes in parallel! You use a recursive procedure that forks helper grains for each child. [Sound crazy? It is not, I have a attribute evaluator system (see my bio) that works on exactly this principle]. The hidden output stream won't work in this case, either, because parallelism may cause children to be visited in any order.

Ira Baxter
  • 93,541
  • 22
  • 172
  • 341