CSE 6341 Programming Languages Neelam Soundarajan Computer Sc

  • Slides: 22
Download presentation
CSE 6341 Programming Languages Neelam Soundarajan Computer Sc. & Eng. Dreese Labs 579 e-mail:

CSE 6341 Programming Languages Neelam Soundarajan Computer Sc. & Eng. Dreese Labs 579 e-mail: neelam@cse

Outline n Main Topic: n n n Ways to formally define syntax and semantics

Outline n Main Topic: n n n Ways to formally define syntax and semantics of PLs Plus … a bit about programming methodologies Tentative Schedule: n n n Attribute grammars: 3 weeks Operational Semantics (including Lisp & its interpreter): 3. 5 weeks Axiomatic Semantics: 3. 5 weeks Denotational Semantics: 1 week Other topics: ? ? Exams etc. : 0. 5 week CSE 6341

References Unfortunately, no good books for the course. Mainly depend on slides, class discussions,

References Unfortunately, no good books for the course. Mainly depend on slides, class discussions, your notes. Repeat: Slides are NOT class notes; slides are just bulletpoints DO NOT miss classes. Some useful references: 1. Formal specification of programming languages, F. Pagan 2. Formal syntax and semantics of programming languages, Kurtz and Slonnegar 3. Lisp 1. 5 programmer’s manual, Mc. Carthy and others Copies of all on reserve in the Sc. /Eng. Library CSE 6341

Attribute Grammars (Ref. : Pagan (Ch. 2. 3); Kurtz (Ch. 3)) Fact: Context-free conditions:

Attribute Grammars (Ref. : Pagan (Ch. 2. 3); Kurtz (Ch. 3)) Fact: Context-free conditions: specified using BNF Question: How do we specify context-sensitive (CS) conds? Answer: Using Attribute Grammars (AGs) An AG is: a BNF grammar + attributes + rules for evaluating attributes + conditions (to capture c. s. requirements) CSE 6341

Example L = { an bn cn | n >= 1 } <as>: :

Example L = { an bn cn | n >= 1 } <as>: : = a Na(<as>)← 1 | a<as>1 Na(<as>)← Na(<as>1)+1 <bs>: : = b Nb(<bs>)← 1 | b<bs>1 Nb(<bs>)← Nb(<bs>1)+1 <cs>: : = c | c<cs>1 Nc(<cs>)← Nc(<cs>1)+1 <as><bs><cs> Cond: Na(<as) = Nb(<bs>) = Nc(<cs>) <ls> : : = Na: Synthesized attribute of <as> Nb: Synthesized attribute of <bs> Nc: Synthesized attribute of <cs> No inherited attributes in this grammar. CSE 6341

Some Comments 1. 2. 3. 4. Consider how the grammar works with a parse

Some Comments 1. 2. 3. 4. Consider how the grammar works with a parse tree, allowing, say, "aabbcc", and disallowing "aabcc" Attributes are NOT program variables; can't have: Na(<as>) ← Na(<as>) + 1 In rules/conditions, can only refer to attributes of nonterminal on the left and the non-terminals in the current alternative. Can't look at "grand children" etc. Could have used N (instead of Na, Nb, Nc) as the name of all three attributes. CSE 6341

Example (revisited) L = { an bn cn | n >= 1 } <ls>

Example (revisited) L = { an bn cn | n >= 1 } <ls> : : = <as><bs><cs> Exp. Nb(<bs>) ← Na(<as>) Exp. Nc(<cs>) ← Na(<as>) a | a<as>1 Na(<as>)← Na(<as>1)+1 <bs>: : = b | b<bs>1 Cond: Exp. Nb(<bs>) =1 Exp. Nb(<bs>1) ← Exp. Nb(<bs>) − 1 <cs>: : = c | c<cs>1 Cond: Exp. Nc(<cs>) =1 Exp. Nc(<cs>1) ← Exp. Nc(<cs>) − 1 Na: Exp. Nb: Exp. Nc: Synthesized attribute of <as> Inherited attribute of <bs> Inherited attribute of <cs> Consider all strings over {a, b, c} (i. e. , a's, b's, c's may be in any order) and require: no. of a's = no. of b's = no. of c's (using synh. & synth+inh. attr) CSE 6341

Some Comments 1. 2. 3. 4. 5. An AG is a BNF grammar plus

Some Comments 1. 2. 3. 4. 5. An AG is a BNF grammar plus a set of attributes, some synth. , others inh. Each attribute is associated with a specific non-terminal. If S is a synth. attrib. of <N>, then for each alternative in <N>'s production, must have an eval. rule that will be used to compute S(<N>) whenever that alternative is used. If I is an inh. attrib. of <N>, then for each occurrence of <N> on the right side of any production, must have eval. rule that will be used to computer I(<N>) if that alternative is used. Conditions are associated with individual alternatives of individual productions. If any condition in a tree evaluates to false, the tree collapses CSE 6341

Context-free condns. using AGs CF conditions can also be expressed using AGs. L =

Context-free condns. using AGs CF conditions can also be expressed using AGs. L = { an bn | n >= 1 } <ls> : : = <as><bs> Cond: Na(<as>) = Nb(<bs>) AGs can be used to capture precedence, i. e. , specify how a string is to be parsed: Consider all strings over {a, b}. Given "abab", want to ensure it is parsed as a(b(a(b))), not as (ab) etc. : <str> : : = a | b N(<str>)← 1 | <str>1<str>2 N(<str>) ← N(<str>1) + N(<str>2) Cond: (N(<str>1) = 1) CSE 6341

Context-sens. condns. in PLs Main condition: Id's that are used must have been declared

Context-sens. condns. in PLs Main condition: Id's that are used must have been declared <prog>: : = <block> : : = begin <decl seq> <stmt seq> end; How to ensure that in <stmt seq> we only use objects declared in <decl seq>? Using synthesized attributes: <block> : : = begin <decl seq> <stmt seq> end; Cond: Used. Ids(<stmt seq>) Decl. Ids(<decl seq>) Using inherited attributes: <block> : : = begin <decl seq> <stmt seq> end; Allowed. Ids(<stmt seq>) ← Decl. Ids(<decl seq>) CSE 6341

CS conditions in PLs (contd. ) Problem: Nested blocks (what are they? ) Solution:

CS conditions in PLs (contd. ) Problem: Nested blocks (what are they? ) Solution: Use a sequence of sets, each containing Ids declared in a (surrounding) block <block> : : = begin <decl seq> <stmt seq> end; Nest(<stmt seq>) ← append(Nest(<block>), Decs(<decl seq>)) <stmt seq> : : = <stmt> Nest(<stmt>) ← Nest(<stmt seq>) | <stmt><stmt seq>1 Nest(<stmt>), Nest(<stmt seq>1) ← Nest(<stmt seq>) <program> : : = <block> Nest(<block>) ← <> CSE 6341

CS conditions in PLs (contd. ) Problem: Different types of Ids Solution: An element

CS conditions in PLs (contd. ) Problem: Different types of Ids Solution: An element of Decs() is of the form: ("xy", int), or ("ab", bool), or ("PQ", proc) (For procedures, also need info about no. /types of pars) Where do we check (that the CS conds. are satisfied)? <assign> : : =<id> : = <int exp>; Cond: last. Type(Name(<id>, Nest(<assign>) = int <id> : = <bool exp>; Cond: last. Type(Name(<id>, Nest(<assign>) = bool CSE 6341

CS conditions in PLs (contd. ) <proc call> : : = call <id>(); Cond:

CS conditions in PLs (contd. ) <proc call> : : = call <id>(); Cond: last. Type(Name(<id>), Nest(<proc call>)) = proc par. Types(Name(<id>), Nest(<proc call>)) = <> | call <id>(<arg list); Cond: last. Type(Name(<id>), Nest(<proc call>)) = proc par. Types(Name(<id>), Nest(<proc call>)) =. . . Question: What about double declarations? <ds> : : = <decl> Decs(<ds>) ← Decs(<decl>); Nest(<decl>)←Nest(<ds>) | <decl> <ds>1 Decs(<ds>) ← Decs(<decl>) Decs(<ds>1) Nest(<decl>), Nest (<ds>1) ← Nest(<ds>) Cond: Decs(<decl>) Decs(<ds>1) = // Not quite? CSE 6341

**Note: Maybe better to look at e. g. in pp. 15/16 before grammar rules

**Note: Maybe better to look at e. g. in pp. 15/16 before grammar rules below** Questions: How do elements get into Decs()? How do procs access surr. block/call other procs? (Ans: Need to pass Nest also to the <decl>s. ) <block> : : = begin <decl seq> <stmt seq> end; Nest(<stmt seq>) ← append(Nest(<block>), Decs(<decl seq>)) Nest(<decl seq>) ← append(Nest(<block>), Decs(<decl seq>)) <decl> : : = int <id>; Decs(<decl>) ← {(Name(<id>), int)} | bool <id>; Decs(<decl>) ← {(Name(<id>), bool)} | proc <id>() <block> Decs(<decl>) ← {(Name(<id>), proc, <>)} Nest(<block>) ← Nest(<decl>) // need to change? | proc <id>(<par list>) <block> Decs(<decl>) ← {(Name(<id>), proc, Partypes(<par list>))} Nest(<block>) ← append(Nest(<decl>), Decs(<par list>)) CSE 6341

<prog> <block> <ds> <ss> <ds> int X, Y <d> proc P(int U, bool Y)

<prog> <block> <ds> <ss> <ds> int X, Y <d> proc P(int U, bool Y) <ds> <d> <block> proc Q() <ds> <ss> <d> <stmt> proc X() <block> <ds> <d> proc X() CSE 6341 <block> <ss> <block>

<prog> <block> D 1 N 1 <ds> D 2 <ss> N 2 D 3

<prog> <block> D 1 N 1 <ds> D 2 <ss> N 2 D 3 N 3 <d> <ds> D 5 N 5 D 4 N 4 int X, Y <d> <ds> <d> D 7 N 7 proc P(int U, bool Y) D 6 N 6 D 17 D 18 <block> proc Q() D 8 N 8 D 18 N 18 <ss> <ds> D 9 N 9 D 10 N 10 <stmt> <d> D 10 N 10 proc X() <block> D 11 N 11 <block> D 12 N 12 <ds> N 14 <d> D 14 <ss> D 13 N 13 D 15 N 15 proc X() <block> D 16 N 16 CSE 6341

Translational Semantics AGs also used to specify translations (code generation) (e. g. : YACC)

Translational Semantics AGs also used to specify translations (code generation) (e. g. : YACC) (Ref: Pagan (ch. 3. 2); Kurtz (ch. 7)) Basic idea: <stmt>: : = <stmt>1; <stmt>2 Code(<stmt>)← append(Code(<stmt>1), Code(<stmt>2)) but the details are more complex. . . E. g. : How to ensure the same label is not used in Code(<stmt>1) and Code(<stmt>2) ? A simple imperative language (we will call it IMP; taken from Pagan): <prog> : : = <stmt> : : = skip; | <assign> | <stmt>1; <stmt>2 | if <be> then<stmt>1 else <stmt>2 | while <be> do <stmt>1 <assign> : : = <id> : = <ae>; <ae> : : = <id> | <int> | <ae>1+<ae>2 | <ae>1 * <ae>2 <be> : : = true | false | <ae>1=<ae>2 | <ae>1 < <ae>2 | <be>1 <be>2 CSE 6341

Translational Semantics (contd. ) Key attributes: n Code: a synth. attribute of <stmt>, <ae>,

Translational Semantics (contd. ) Key attributes: n Code: a synth. attribute of <stmt>, <ae>, <be>: The seq. of assembly instructions corresponding to a particular <stmt>, <ae>, <be> n Labin (inh. ), Labout (synth. ): keep track of next available label n Temp (inh. ): keeps track of next available memory loc. for temporary use <prog> : : = <stmt> Code(<prog>) ← Code(<stmt>) Labin(<stmt>) ← 1 <stmt> : : = <stmt>1; <stmt>2 Code(<stmt>) ← append(Code(<stmt>1), Code(<stmt>2)) Labin(<stmt>1) ← Labin(<stmt>) Labin(<stmt>2) ← Labout(<stmt>1) Labout(<stmt>) ← Labout(<stmt>2) CSE 6341

Translational Semantics (contd. ) <stmt> : : = | | <assign> Code(<stmt>) Labout(<stmt>) ←

Translational Semantics (contd. ) <stmt> : : = | | <assign> Code(<stmt>) Labout(<stmt>) ← Code(<assign>) ← Labin(<stmt>) // why? if <be> then <stmt>1 else <stmt>2 Labin(<stmt>1) ← Labin(<stmt>) + 2 // why? Labin(<stmt>2) ← Labout(<stmt>1) Labout(<stmt>) ← Labout(<stmt>2) Code(<stmt>) ← append( Code(<be>), ("BZ", Labin(<stmt>)), // slight problem Code(<stmt>1), ("BR", label(Labin(<stmt>)+1)), (label(Labin(<stmt>)) "No-Op"), Code(<stmt>2), (label(Labin(<stmt>)+1) "No-Op") ) while <be> do <stmt>1 Labin(<stmt>1) ←. . . Labout(<stmt>) ←. . . Code(<stmt>) ←. . . BZ: "branch on zero"; BR: "unconditional branch"; "No-Op": "continue". CSE 6341

Translational Semantics (contd. ) <assign> : : = <id> : = <ae>; Code(<assign>) ←

Translational Semantics (contd. ) <assign> : : = <id> : = <ae>; Code(<assign>) ← append(Code(<ae>), ("STO", Name(<id>)) Temp(<ae>) ← 1 <ae> : : = <int> Code(<ae>) | <id> Code(<ae>) | ← <("LOAD" Value(<int>))> ← <("LOAD" Name(<id>))> <ae>1+<ae>2 Code(<ae>) ← append( Code(<ae>1), ("STO" temp(Temp(<ae>)), Code(<ae>2), ("ADD" temp(Temp(<ae>))) ) Temp(<ae>1) ←Temp(<ae>) Temp(<ae>2) ←Temp(<ae>) + 1 // why? CSE 6341

Static Scope (Algol, Pascal, C, C++, . . . ) Entities accessible in a

Static Scope (Algol, Pascal, C, C++, . . . ) Entities accessible in a procedure: Entities declared in that procedure + Entities declared in the “surrounding” procedure (less those with name conflicts) + Entities declared in procedure surrounding the surrounding procedure +. . . Visualize: Each procedure is a box whose sides are one-way mirrors: you can look out of the box, but you can’t look into a box Some languages are not quite static scope but are close. CSE 6341

Example program A, B, C: integer; Q: procedure // no parameters begin B :

Example program A, B, C: integer; Q: procedure // no parameters begin B : = B+2; C : = C+2; print A, B, C; end (Q); R: procedure A: integer; begin A : = 3; C : = 2; call Q; B : = A+C; print A, B, C; end (R); S: procedure A, C: integer; A Q: procedure // nested in S C: integer; Q A begin A : = A+1; C : = B+1; print A, B, C; end (S. Q); begin // body of S C A C B : = 3; C : = 1; A : = 4; print A, B, C; call R; print A, B, C; end (S); begin // main body A : = 1; B : = 1; C : = 1; call R; print A, B, C; call S; print A, B, C; end (main); CSE 6341 C R S Q