230 likes | 244 Views
This article explores the importance of semantic analysis in programming languages and discusses syntax-directed translations. It covers scope rules, forward declarations, and name-type compatibility. Examples are provided using the languages C, Pascal, and Tiger.
E N D
Semantic Analysis Mooly Sagiv Schrierber 317 03-640-7606 Wed 10:00-12:00 html://www.cs.tau.ac.il/~msagiv/courses/wcc02.html
Outline • What is Semantic Analysis • Why is it needed? • Syntax directed translations • Semantic analysis in Tiger (Targil)
Semantic Analysis • The “meaning of the program” • Requirements related to the “context” in which a construct occurs • Context sensitive requirements - cannot be specified using a context free grammar • Requires complicated and unnatural context free grammars
Example Semantic Condition • In C (and Tiger)break statements can only occur inside switch or loop statements
Partial Grammar for C Stm ::= Exp; Stm ::= if (Exp) Stm StList ::= StList Stm Stm ::= if (Exp) Stm else Stm StList ::=emptyString Stm ::= while (Exp) do Stm Stm ::= break; Stm ::= {StList }
LStm ::= Exp; LStm ::= if (Exp) LStm LStm ::= if (Exp) LStm else LStm LStList ::= LStList LStm LStm ::= while (Exp) do LStm LStm ::= {LStList } LStList ::=emptyString LStm ::= break; Refined Grammar for C Stm ::= Exp; Stm ::= if (Exp) Stm StList ::= StList Stm Stm ::= if (Exp) Stm else Stm StList ::=emptyString Stm ::= while (Exp) do LStm Stm ::= {StList }
A Possible Abstract Syntax for C typedef struct A_St_ *A_St; struct A_St { enum {A_if, A_while, A_break, A_block, ...} kind; A_pos pos; union { struct { A_Exp e; A_St st1; A_St st2; } if_st; struct { A_Exp e; A_St st; } while_st; struct { A_St st1; A_St st2; } block_st; ... } u ; } A_St A_IfStm(A_Exp, A_St, A_St); A_St A_WhileStm(A_Exp A_St); A_St A_BreakStm(void); A_St A_BlockStm(A_St, A_St);
Partial Bison Specification stm : IF ‘(‘ exp ‘)’ stm { $$ = A_IfStm($3, $5, NULL) ; } | IF ‘(‘ exp ‘)’ stm ELSE stm { $$ = A_IfStm($3, $5, $7) ; } | WHILE ‘(‘ exp ‘)’ stm { $$ = A_WhileStm($3, $5); } | ‘{‘ stmList ‘}’ { $$ = $2; } | BREAK `;' { $$ = A_BreakStm(); } ; stmList :stmList st { $$ = A_BlockStm($1, $2) ;} | /* empty */ {$$ = NULL ;}
A Semantic Check(on the abstract syntax tree) void check_break(A_St st) { switch (st->kind) { case A_if: check_break(st-> u.if_st.st1); check_break(st->u.if_st.st2); break; case A_while: break ; case A_break: error(“Break must be enclosed within a loop”, st->pos); break; case A_block: check_break(st->u.block_st.st1) check_break(st->u.block_st.st2); break; } }
Syntax Directed Solution %{static int loop_count = 0 ;%} %% stm : exp ‘;’ | IF ‘(‘ exp ‘)’ stm | IF ‘(‘ exp ‘)’ stm ELSE stm | WHILE ‘(‘ exp ‘)’ m stm { loop_count--;} | ‘{‘ stmList ‘}’ | BREAK ‘;’ { if (!loop_count) error(“Break must be enclosed within a loop”, line_count); } ; stmList :stmList st | /* empty */ ; m : /* empty */ { loop_count++ ;} ;
Problems with Syntax Directed Translations • Grammar specification may be tedious (e.g., to achieve LALR(1)) • May need to rewrite the grammar to incorporate different semantics • Modularity is impossible to achieve • Some programming languages allow forwarddeclarations (Algol, Tiger, ML and Java)
Example Semantic Condition: Scope Rules • Variables must be defined within scope • Dynamic vs. Static Scope rules • Cannot be coded using a context free grammar
Dynamic vs. Static Scope Rules procedure p; var x: integer procedure q ; begin { q } … x … end { q }; procedure r ; var x: integer begin { r } q ; end; { r } begin { p } q ; r ; end { p }
Example Semantic Condition • In Pascal (and Tiger)Types in assignment must be “compatible”'
Partial Grammar for Pascal Stm ::= id Assign Exp Exp ::= IntConst Exp ::= RealConst Exp::= Exp + Exp Exp::= Exp -Exp Exp::= ( Exp ) Refined Grammar for Pascal
Syntax Directed Solution %% ... stm : id Assign exp {compat_ass(lookup($1), $4) ; } ; exp : exp PLUS exp {compat_op(PLUS, $1, $3); $$ = op_type(PLUS, $1, $3); } | exp MINUS exp {compat_op(MINUS, $1, $3); $$ = op_type(MINUS, $1, $3); } | ID { $$ = lookup($1); } | INCONST { $$= ty_int ; } | REALCONST { $$ = ty_real ;} | ‘(‘ exp ‘)’ { $$ = $2 ; } ;
Features of Tiger • Static scoping • Possible forward declarations of (recursive) functions and structures • Name Type Compatibly
Static Scoping of Tiger env0 function f(a: int, b: int, c: int) (print_int(a+c), let var j := a+b var a := “hello” in print(a); print_int(j) end; print_int(b) ) env1 =env0+[aint, bint, cint] env2 =env1 +[jint] env3=env2 + [astring] How to implement?
Forward Declarations of Fields type intlist = {hd: int, tl: intlist} type tree = {key: int, children: treelist } type treelist = {hd: tree, tl: treelist}
Forward Declarations of Functions type tree = {key: int, children: treelist } type treelist = {hd: tree, tl: treelist} function treeLeaves(t: tree): int = if t = nil then 1 else treeListLeaves(t.children) function treeListLeaves(L: treelist): int = if t = nil then 0 else treeLeaves(L.hd) + treeListLeaves(L.tl)
Name Type Compatibility let type a = { x: int, y : int} type b = { x: int, y : int } var i: a := ... var j: b := ... in i := j let type a = { x: int, y : int } type b = a var i: a := ... var j: b := ... in i := j
Type Checking Module • Top-down traversal on the syntax tree/* semant.h */void SEM_transProg(A_exp exp); • Imperative hashing symbol tables (two environments) • Use C equality for type checking • Process “headers” of recursive declarations first • Generate code for expressions (will be studied later)
Summary • Several ways to enforce semantic correctness conditions • syntax • syntax directed • traversals on the abstract syntax tree • later compiler phases? • Runtime? • There are tools that automatically generate semantic analyzer from specification(Based on attribute grammars)