# A basic grammar for arithmetic expressions. # Only single-digit numbers are allowed. # We have to use { } for parentheses, since ( ) are already used for # delimiting constituents in the parse tree that you will print. # ---------------------------------------------------------------------- # # Example: # The sentence 3 * 5 + 6 * { 5 - 3 - 2 } + sqrt { 7 } # has the parse # (ROOT (EXPR (EXPR (EXPR (TERM (TERM (FACTOR (Num 3))) # * # (FACTOR (Num 5)))) # + # (TERM (TERM (FACTOR (Num 6))) # * # (FACTOR { # (EXPR (EXPR (EXPR (TERM (FACTOR (Num 5)))) # - # (TERM (FACTOR (Num 3)))) # - # (TERM (FACTOR (Num 2)))) # }))) # + # (TERM (FACTOR sqrt # { # (EXPR (TERM (FACTOR (Num 7)))) # })))) # # If you run that parse through # buildattrs arith.gra # then the ROOT node ends up with the attribute # sem=plus(plus(times(3,5),times(6,minus(minus(5,3),2))),sqrt(7)) # ---------------------------------------------------------------------- # The semantics of the rule's left-hand-side are defined in terms of # the semantics of its right-hand-side. You saw this notation in class. 1 EXPR[sem=plus(x,y)] EXPR[sem=x] + TERM[sem=y] 1 EXPR[sem=minus(x,y)] EXPR[sem=x] - TERM[sem=y] 1 EXPR[sem=x] TERM[sem=x] # For the sake of illustration, the following TERM rules use a more # abbreviated notation. In the definition of a sem attribute, "1" and "3" # refer to the sem attributes of the first and third child, respectively. # # Despite the notational difference, these rules are strictly # analogous to the EXPR rules above -- they handle multiplication and # division, whereas the EXPR rules handled the lower-precedence # operations of addition and subtraction. 1 TERM[sem=times(1,3)] TERM * FACTOR 1 TERM[sem=div(1,3)] TERM / FACTOR 1 TERM[sem=1] FACTOR 1 FACTOR[sem=1] Num 1 FACTOR[sem=2] { EXPR } # In the following rule, the "1" refers to the sem attribute of sqrt. # But sqrt is a terminal symbol: what is its sem attribute? # Just the string "sqrt": the head and sem attributes of a terminal # are automatically set to the terminal itself. 1 FACTOR[sem=1(3)] sqrt { EXPR } # Now we give the start rule of the grammar. This demonstrates a # further abbreviation: writing "=1" is like writing "x=1" for # all attributes x that are not explicitly mentioned in the rule. # Thus, ROOT will copy any attributes that EXPR happens to have. 1 ROOT[=1] EXPR # We should also use =1 on our preterminals so that they inherit # all their attributes from the terminals (namely head and sem). # However, as a notational convenience, buildattrs will assume # [=1] on a left-hand-side that has no brackets at all (if there # is only one thing on the right-hand side). So we can just # leave them off altogether; if we really wanted no attributes we # could write Num[] instead of Num. 1 Num 0 1 Num 1 1 Num 2 1 Num 3 1 Num 4 1 Num 5 1 Num 6 1 Num 7 1 Num 8 1 Num 9 1 Num pi 1 Num e 1 Num 0.5 # Some more numbers.