Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Semantic Analysis. 2 Semantic Analyzer Attribute Grammars Syntax Tree Construction Top-Down Translators Bottom-Up Translators Recursive Evaluators Type.

Similar presentations


Presentation on theme: "1 Semantic Analysis. 2 Semantic Analyzer Attribute Grammars Syntax Tree Construction Top-Down Translators Bottom-Up Translators Recursive Evaluators Type."— Presentation transcript:

1 1 Semantic Analysis

2 2 Semantic Analyzer Attribute Grammars Syntax Tree Construction Top-Down Translators Bottom-Up Translators Recursive Evaluators Type Checking

3 3 Semantic Analyzer Lexical Analyzer Syntax Analyzer Semantic Analyzer Symbol Table source program correct program syntax tree

4 4 Semantic Analysis Type-checking of programs Translation of programs Interpretation of programs

5 5 Attribute Grammars An attribute grammar is a context free grammar with associated semantic attributes and semantic rules Each grammar symbol is associated with a set of semantic attributes Each production is associated with a set of semantic rules for computing semantic attributes

6 6 An Example - Interpretation L → E ‘\n’{print(E.val);} E → E 1 ‘+’ T{E.val := E 1.val + T.val;} E → T{E.val := T.val;} T → T 1 ‘*’ F{T.val := T 1.val * F.val;} T → F{T.val := F.val;} F → ‘(’ E ‘)’{F.val := E.val;} F → digit{F.val := digit.val;} Attribute val represents the value of a construct

7 7 Annotated Parse Trees L E.val = 19 ‘+’E.val = 15T.val = 4 F.val = 5T.val = 3 T.val = 15 ‘*’ digit.val = 5 F.val = 4 digit.val = 4 F.val = 3 digit.val = 3 3 * 5 + 4 ‘\n’ print(E.val)

8 8 Semantic Attributes A (semantic) attribute of a node (grammar symbol) in the parse tree is synthesized if its value is computed from that of its children An attribute of a node in the parse tree is inherited if its value is computed from that of its parent and siblings

9 9 Synthesized Attributes L → E ‘\n’{print(E.val);} E → E 1 ‘+’ T{E.val := E 1.val + T.val;} E → T{E.val := T.val;} T → T 1 ‘*’ F{T.val := T 1.val * F.val;} T → F{T.val := F.val;} F → ‘(’ E ‘)’{F.val := E.val;} F → digit{F.val := digit.val;}

10 10 Synthesized Attributes L E.val = 19 ‘+’E.val = 15T.val = 4 F.val = 5T.val = 3 T.val = 15 ‘*’ digit.val = 5 F.val = 4 digit.val = 4 F.val = 3 digit.val = 3 3 * 5 + 4 ‘\n’ print(E.val)

11 11 Inherited Attributes D → T {L.in := T.type;} L T → int{T.type := integer;} T → float{T.type := float;} L → {L 1.in := L.in;} L 1 ‘,’ id{addtype(id.entry, L.in);} L → id{addtype(id.entry, L.in);}

12 12 Inherited Attributes D T.type = float float L.in = float; ‘,’L.in = float; id 3 L.in = float;‘,’ id 2 id 1 addtype()

13 13 Semantic Rules Each grammar production A   is associated with a set of semantic rules of the form b := f (c 1, c 2, …, c k ) where f is a function and 1. b is a synthesized attribute of A and c 1, c 2, …, c k are attributes of A or grammar symbols in , or 2. b is an inherited attribute of one of the grammar symbols in  and c 1, c 2, …, c k are attributes of A or grammar symbols in 

14 14 Dependencies of Attributes In the semantic rule b := f(c 1, c 2, …, c k ) we say b depends on c 1, c 2, …, c k The semantic rule for b must be evaluated after the semantic rules for c 1, c 2, …, c k The dependencies of attributes can be represented by a directed graph called dependency graph

15 15 Dependency Graphs D T float L ‘,’Lid 3 L‘,’id 2 id 1 1 typein 2 in 4 in 3 6 10 8 5 entry 9 entry 7 entry

16 16 S-Attributed Attribute Grammars An attribute grammar is S-attributed if it uses synthesized attributes exclusively

17 17 An Example L → E ‘\n’{print(E.val);} E → E 1 ‘+’ T{E.val := E 1.val + T.val;} E → T{E.val := T.val;} T → T 1 ‘*’ F{T.val := T 1.val * F.val;} T → F{T.val := F.val;} F → ‘(’ E ‘)’{F.val := E.val;} F → digit{F.val := digit.val;}

18 18 L-Attributed Attribute Grammars An attribute grammar is L-attributed if each attribute computed in each semantic rule for each production A  X 1 X 2 … X n is a synthesized attribute, or an inherited attribute of X j, 1  j  n, depending only on 1. the attributes of X 1, X 2, …, X j-1 2. the inherited attributes of A

19 19 An Example D → T L{L.in := T.type;} T → int{T.type := integer;} T → float{T.type := float;} L → L 1 ‘,’ id{L 1.in := L.in; addtype(id.entry, L.in);} L → id{addtype(id.entry, L.in);}

20 20 A Counter Example A → {L.i := l(A.i);} L {M.i := m(L.s);} M {A.s := f(M.s);} A → {Q.i := q(R.s);} Q {R.i := r(A.i);} R {A.s := f(Q.s);}

21 21 Construction of Syntax Trees An abstract syntax tree is a condensed form of parse tree if-stmt ifexprthenstmtelsestmt if-stmt exprstmt E E+ T F 4 E* T F 5 T F 3 + *4 53

22 22 Syntax Trees for Expressions Interior nodes are operators Leaves are identifiers or numbers Functions for constructing nodes – mknode(op, left, right) – mkleaf(id, entry) – mkleaf(num, value)

23 23 An Example + - id num p1 := mkleaf(id, entry a ); p2 := mkleaf(num, 4); p3 := mknode(‘-’, p1, p2); p4 := mkleaf(id, entry b ); p5 := mknode(‘+’, p3, p4); a - 4 + b 4a b

24 24 An Example E → E 1 ‘+’ T {E.ptr := mknode(‘+’, E 1.ptr, T.ptr);} E → E 1 ‘-’ T {E.ptr := mknode(‘-’, E 1.ptr, T.ptr);} E → T {E.ptr := T.ptr;} T → ‘(’ E ‘)’ {T.ptr := E.ptr;} T → id {T.ptr := mkleaf(id, id.entry);} T → num {T.ptr := mkleaf(num, num.value);}

25 25 Top-Down Translators For each nonterminal, – inherited attributes  formal parameters – synthesized attributes  returned values For each production, – for each terminal X with synthesized attribute x, save X.x; match(X); – for nonterminal B, c := B(b 1, b 2, …, b k ); – for each semantic rule, copy the rule to the parser

26 26 An Example - Interpretation E  T { R.i := T.nptr } R { E.nptr := R.s } R  addop T { R 1.i := mknode(addop.lexeme, R.i, T.nptr) } R 1 { R.s := R 1.s } R   { R.s := R.i } T  ‘(’ E ‘)’ { T.nptr := E.nptr } T  num { T.nptr := mkleaf(num, num.value) }

27 27 An Example syntax_tree_node *E( ); syntax_tree_node *R( syntax_tree_node * ); syntax_tree_node *T( );

28 28 An Example syntax_tree_node *E( ) { syntax_tree_node *enptr, *tnptr, *ri, *rs; switch (token) { case ‘(’: case num: tnptr = T( ); ri = tnptr;/* R.i := T.nptr */ rs = R(ri); enptr = rs;/* E.nptr := R.s */ break; default: error(); } return enptr; }

29 29 An Example syntax_tree_node *R(syntax_tree_node * i) { syntax_tree_node *nptr, *i1, *s1, *s; char add; switch (token) { case addop: add = yylval; match(addop); nptr = T(); i1 = mknode(add, i, nptr); /* R 1.i := mknode(addop.lexeme, R.i, T.nptr) */ s1 = R(i1); s = s1; break; /* R.s := R 1.s */ case EOF: s = i; break;/* R.s := R.i */ default: error(); } return s; }

30 30 An Example syntax_tree_node *T( ) { syntax_tree_node *tnptr, *enptr; int numvalue; switch (token) { case ‘(’: match(‘(’); enptr = E( ); match(‘)’); tnptr = enptr; break;/* T.nptr := E.nptr */ case num: numvalue = yylval; match(num); tnptr = mkleaf(num, numvalue); break; /* T.nptr := mkleaf(num, num.value) */ default: error( ); } return tnptr; }

31 31 Bottom-Up Translators Keep the values of synthesized attributes on the parser stack symbolval X Y Z X.x Y.y Z.z... topval[top] val[top-1] val[top-2] A  X Y Z {val[ntop] := f(val[top-2], val[top-1], val[top]);} A  X Y Z {A.a := f(X.x, Y.y, Z.z);}

32 32 Evaluation of Synthesized Attributes When a token is shifted onto the stack, its attribute value is placed in val[top] Code for semantic rules are executed just before a reduction takes place If the left-hand side symbol has a synthesized attribute, code for semantic rules will place the value of the attribute in val[ntop]

33 33 An Example L → E ‘\n’{print(val[top-1]);} E → E 1 ‘+’ T{val[ntop] := val[top-2] + val[top];} E → T{val[top] := val[top];} T → T 1 ‘*’ F{val[ntop] := val[top-2] * val[top];} T → F{val[top] := val[top];} F → ‘(’ E ‘)’{val[ntop] := val[top-1];} F → digit{val[top] := digit.value;}

34 34 An Example Input symbol val production used 3*5+4n *5+4ndigit3 *5+4nF3F  digit *5+4nT3T  F 5+4nT *3 _ +4nT * digit3 _ 5 +4nT * F3 _ 5F  digit +4nT15T  T * F +4nE15E  T

35 35 An Example Input symbol val production used +4nE15E  T 4nE +15 _ nE + digit15 _ 4 nE + F15 _ 4F  digit nE + T15 _ 4T  F nE19E  E + T E n19 _ L_L  E n

36 36 Evaluation of Inherited Attributes Removing embedding actions from attribute grammar by introducing marker nonterminals E  T R R  “+” T {print(‘+’)} R | “-” T {print(‘-’)} R |  T  num {print(num.val)} E  T R R  “+” T M R | “-” T N R |  T  num {print(num.val)} M   {print(‘+’)} N   {print(‘-’)}

37 37 Evaluation of Inherited Attributes Inheriting synthesized attributes on the stack A  X {Y.i := X.s} Y symbolval X Y X.s... top

38 38 An Example D  T {L.in := T.type;} L T  int {T.type := integer;} T  float {T.type := float;} L  {L 1.in := L.in} L 1 ‘,’ id {addtype(id.entry, L.in);} L  id {addtype(id.entry, L.in);} D  T L T  int {val[ntop] := integer;} T  float {val[ntop] := float;} L  L 1 ‘,’ id {addtype(val[top], val[top-3]); } L  id {addtype(val[top], val[top-1]); }

39 39 An Example Input symbol val production used int p,q,r p,q,rint_ p,q,rTiT  int,q,rT idi e,q,rT Li _L  id q,rT L,i _ _,rT L, idi _ _ e,rT Li _L  L “,” id rT L,i _ _ T L, idi _ _ e T Li _L  L “,” id D

40 40 Evaluation of Inherited Attributes Simulating the evaluation of inherited attributes Inheriting the value of a synthesized attribute works only if the grammar allows the position of the attribute value to be predicted

41 41 An Example S  a A C {C.i := A.s} S  b A B C {C.i := A.s} C  c {C.s := g(C.i)} S  a A C {C.i := A.s} S  b A B M C {M.i := A.s; C.i := M.s} C  c {C.s := g(C.i)} M   { M.s := M.i }

42 42 Another Example S  a A C {C.i := f(A.s)} S  a A N C {N.i := A.s; C.i := N.s} N   { N.s := f(N.i) }

43 43 From Inherited to Synthesized D  L “:” T L  L “,” id | id T  integer | char D L :T L, id L, int D  id L L  “,” id L | “:” T T  integer | char D id L, L, L :T int

44 44 Bison line : expr ‘\n’ {printf(“%d\n”, $1);} ; expr: expr ‘+’ term {$$ = $1 + $3;} | term ; term: term ‘*’ factor {$$ = $1 * $3;} | factor ; factor: ‘(’ expr ‘)’ {$$ = $2;} | DIGIT ; %token DIGIT %

45 45 Bison %union { char op_type; int value; } %token DIGIT %type op %type expr factor %

46 46 Bison expr: expr op factor {$$ = $2 == ‘+’ ? $1 + $3 : $1 - $3;} | factor ; op: + {$$ = ‘+’;} | - {$$ = ‘-’;} ; factor: DIGIT ;

47 47 Bison program: { init_symbol_table(); } PROGRAM ID { declare_program_name($3); } IS declarations BODY statements END { build_program( $3, $6, $8 ); } ;

48 48 Recursive Evaluators The parser constructs a syntax tree A recursive evaluator is a function that traverses the syntax tree and evaluates attributes A recursive evaluator can traverse the syntax tree in any order A recursive evaluator can traverse the syntax tree multiple times

49 49 An Example E 1.val

50 50 An Example S  { B.ps := 10 } B { S.ht := B.ht } B  { B 1.ps := B.ps } B 1 { B 2.ps := B.ps } B 2 { B.ht := max(B 1.ht, B 2.ht) } B  { B 1.ps := B.ps } B 1 sub { B 2.ps := shrink(B.ps) } B 2 { B.ht := disp(B 1.ht, B 2.ht) } B  text { B.ht := text.h  B.ps }

51 51 An Example ps B ht ps B 1 htps B 2 ht Sht B psht B ps texth

52 52 An Example function B(n, ps); var ps1, ps2, ht1, ht2; begin case production at node n of ‘B  B 1 B 2 ’: ps1 := ps; ht1 := B(child(n, 1), ps1); ps2 := ps; ht2 := B(child(n, 2), ps2); return max(ht1, ht2); ‘B  B 1 sub B 2 ’: ps1 := ps; ht1 := B(child(n, 1), ps1); ps2 := shrink(ps); ht2 := B(child(n, 3), ps2); return disp(ht1, ht2); ‘B  text’: return ps  text.h; default: error end end;

53 53 An Example with Right-to-Left Order A → {L.i := l(A.i);} L {M.i := m(L.s);} M {A.s := f(M.s);} A → {Q.i := q(R.s);} Q {R.i := r(A.i);} R {A.s := f(Q.s);}

54 54 An Example i A s i L si M s i A s i Q si R s

55 55 An Example function A(n, ai); var li, ls, mi, ms, ri, rs, qi, qs; begin case production at node n of ‘A  L M’: li := l(ai); ls := L(child(n, 1), li); mi := m(ls); ms := M(child(n, 2), mi); return f(ms); ‘A  Q R’: ri := r(ai); rs := R(child(n, 2), ri); qi := q(rs); qs := Q(child(n, 1), qi); return f(qs); default: error end end;

56 56 An Example with Multiple Passes S → E{ E.i := g(E.s); S.r := E.t; } E → E 1 E 2 { E.s := fs(E 1.s, E 2.s); E 1.i := fi1(E.i); E 2.i := fi2(E.i); E.t := ft(E 1.t, E 2.t); } E → id{ E.s := id.s; E.t := h(E.i); }

57 57 An Example E1E1 si t E2si t Esi t Esi t id s S r Esi t S r Esi t Esi t s Esi t s

58 58 An Example function Es(n); var s1, s2; begin case production at node n of ‘E  E 1 E 2 ’: s1 := Es(child(n, 1)); s2 := Es(child(n, 2)); return fs(s1, s2); ‘E  id’: return id.s; default: error end end;

59 59 An Example function Et(n, i); var i1, t1, i2, t2; begin case production at node n of ‘E  E 1 E 2 ’: i1 := fi1(i); t1 := Et(child(n, 1), i1); i2 := fi2(i); t2 := Et(child(n, 2), i2); return ft(t1, t2); ‘E  id’: return h(i); default: error end end;

60 60 An Example function Sr(n); var s, i, t; begin s := Es(child(n, 1)); i := g(s); t := Et(child(n, 1), i); return t end;

61 61 Type Systems A type system is a collection of rules for assigning types to the various parts of a program A type checker implements a type system Types are represented by type expressions

62 62 Type Expressions A basic type is a type expression – boolean, char, integer, real, void, type_error A type constructor applied to type expressions is a type expression – array: array(I, T) – product: T 1  T 2 – record: record((N 1  T 1 )  (N 2  T 2 )) – pointer: pointer(T) – function: D  R

63 63 Type Declarations P  D “;” E D  D “;” D | id “:” T { addtype(id.entry, T.type) } T  char { T.type := char } T  integer { T.type := int } T  “*” T 1 {T.type := pointer(T 1.type) } T  array “[” num “]” of T 1 { T.type := array(num.value, T 1.type) }

64 64 Type Checking of Expressions E  literal {E.type := char} E  num {E.type := int} E  id {E.type := lookup(id.entry)} E  E 1 mod E 2 {E.type := if E 1.type = int and E 2.type = int then int else type_error} E  E 1 “[” E 2 “]” {E.type := if E 1.type = array(s, t) and E 2.type = int then t else type_error} E  “*” E 1 {E.type := if E 1.type = pointer(t) then t else type_error}

65 65 Type Checking of Statements P  D “;” S S  id “:=” E {S.type := if lookup(id.entry) = E.type then void else type_error} S  if E then S 1 {S.type := if E.type = boolean then S 1.type else type_error} S  while E do S 1 {S.type := if E.type = boolean then S 1.type else type_error} S  S 1 “;” S 2 {S.type := if S 1.type = void and S 2.type = void then void else type_error}

66 66 Type Checking of Functions T  T 1 “  ” T 2 {T.type := T 1.type  T 2.type} E  E 1 “(” E 2 “)” {E.type := if E 1.type = s  t and E 2.type = s then t else type_error}


Download ppt "1 Semantic Analysis. 2 Semantic Analyzer Attribute Grammars Syntax Tree Construction Top-Down Translators Bottom-Up Translators Recursive Evaluators Type."

Similar presentations


Ads by Google