The Programming Language Core Wolfgang Schreiner Research Institute for Symbolic Computation (RISC-Linz) Johannes Kepler University, A-4040 Linz, Austria Wolfgang.Schreiner@risc.uni-linz.ac.at http://www.risc.uni-linz.ac.at/people/schreine Wolfgang Schreiner RISC-Linz
The Programming Language Core \Core" of values and operations establish fundamental capabilities of a language. { Numerical computation: numeric values. { Text editing: string values. { General purpose: core for many applications. Starting point for language design. Design programs and study their computational powers. Later extend core by conveniences. { Subroutines, modules,... Let's study the nature of a programming language core! Wolfgang Schreiner 1
A Core Imperative Language A while loop language Syntax domains. Syntax rules. C 2 Command E 2 Expression L 2 Location N 2 Numeral C ::= L:=E j C 1 ;C 2 j if E then C 1 else C 2 j while E do C od j skip E ::= N j @L j E 1 +E 2 j :E j E 1 =E 2 L ::= loc i, if i > 0 N ::= n, if n 2 Integer Example loc 1 := 0; while @loc 1 =0 do loc 2 :=@loc 1 +1 od Wolfgang Schreiner 2
Abstract Syntax Non-terminal symbols. { C, E, L, N. { Variables over syntax trees. Terminal symbols. { @, +, :=, skip { Labels of syntax trees. Inductive denition of syntax trees. Abstract syntax denes syntax trees! Wolfgang Schreiner 3
Example loc 1 := 0; while @loc 1 =0 do loc 2 :=@loc 1 +1 od C C ; C L := E while E do C loc_1 od N 0 E = E L := E loc_2 @L loc_1 N 0 E + E @L loc_1 N 1 Semantics gives meaning to syntax trees! Wolfgang Schreiner 4
Typing Rules Abstruct syntax does not dene wellformed programs only. { Phrase \(0=1)+2" allowed. { Cannot add boolean to integer. Rene abstract syntax denition. { Integer and boolean expressions. { Dene two distinct syntax domains? { Better: add typing annotations! Attributed syntax trees { Type attributes to all phrase forms. { Syntax tree is well typed if type attributes can be attached to all of its nonterminals. Inference rules used for describing type structures. Wolfgang Schreiner 5
Example C: comm C: comm ; C: comm L: intloc := E: intexp loc_1 while E: boolexp do C: comm od N: int E: intexp = E: intexp L: intloc := E: intexp 0 loc_2 @ L: intloc loc_1 N: 0 int E: intexp + E: inte @ L: intloc loc_1 N: 1 Each subtree is annotated with its type! Wolfgang Schreiner 6
Typing Rules Command L: intloc E: intexp C 1 : comm C 2 : comm L:=E: comm C 1 ;C 2 : comm E: boolexp C 1 : comm C 2 : comm if E then C 1 else C 2 : comm E: boolexp C: comm while E do C od: comm skip: comm Expression N: int N: intexp L: intloc @L: intexp E 1 : intexp E 2 : intexp E: boolexp E 1 +E 2 : intexp E 1 : exp E 2 : exp E 1 =E 2 : boolexp Location loc i : intloc, if i > 0 :E: boolexp if 2 fint, boolg Numeral n: int, if n 2 Integer Wolfgang Schreiner 7
Typing Rules One typing rule for each construction of each syntax rule. Conditions under which constructions are well typed. Linear Notation (full type annotation): { ((loc 1 ) intloc :=((0) int ) intexp (while ((@(loc 1 ) intloc ) intexp =((0) int ) intexp ) boolexp (do (loc 2 ) intloc := ((@(loc 1 ) intloc ) intexp + ((1) int ) intexp ) intexp ) comm ) comm ) comm. Abbreviation (root type annotation): { loc 1 := 0; while @loc 1 =0 do loc 2 :=@loc 1 +1 od: comm Wolfgang Schreiner 8
Typing Rules Logic assertion U:. { Tree U is well typed with type. Static typing for language. { Type attributes can be calculated without evaluating the program. Strongly typed language. { No run-time incompatibility errors. Unicity of typing. { Can a syntax tree be typed in multiple ways? Soundness of typing rules. { Are the typing rules sensible in their assignment of type attributes to phrases? Questions will be addressed later. Wolfgang Schreiner 9
Induction and Recursion Syntax rule E ::= true j :E j E 1 &E 2 Inductive denition: { true is in Expression. { If E is in Expression, then so is :E. { If E 1 and E 2 are in Expression, then so is E 1 &E 2. { No other trees are in expression. Expression = set of trees! Generate all trees in stages. { stage 0 = fg. { stage i+1 = stage i [ f :E j E 2 stage i g [ f E 1 &E 2 j E 1, E 2 2 stage i g. { Expression = [ i0 stage i. Any tree in Expression is constructed in a nite number of stages. Wolfgang Schreiner 10
Structural Induction Proof technique for syntax trees. { Goal: prove P (t) for all trees t in a a language. { Inductive base: Prove that P holds for all trees in stage 1. { Inductive hypothesis: Assume that P holds for all trees in stages stage j with j i. { Inductive step: Prove that P holds for all trees in stage i. Prove P (t) for all trees t in Expression. { P (true) holds. { P (:E) holds assuming that P (E) holds (for arbitrary E). { P (E 1 &E 2 ) holds assuming that P (E 1 ) holds and P (E 2 ) holds (for arbitrary E 1, E 2 ). Syntax rules guide the proof! Wolfgang Schreiner 11
Unicity of Typing Can a syntax tree be typed in multiple ways? Unicity of typing property. { Every syntax tree has as most one assignment of typing attributes to its nodes. { If P : holds, then is unique. Unicity of Typing holds for Numeral. { By single typing rule, if N: holds, then = int (for all N 2 Numeral). Unicity of Typing holds for Location. { By single typing rule, if L: holds, then = intloc (for all L 2 Location). Wolfgang Schreiner 12
Unicity of Typing Unicity of typing holds for Expression: { Case N. N:int holds. By single typing rule, N:intexp holds. { Case E 1 +E 2. By inductive hypothesis, E 1 : 1 and E 2 : 2 hold for unique 1 and 2. By single typing rule, E 1 :intexp and E 2 :intexp must hold. If 1 = 2 =intexp, then E 1 +E 2 :intexp. Otherwise, E 1 +E 2 has no typing. {... Unicity of typing holds for Command: { Case L := E. L:intloc holds. E: 1 holds for unique 1. By single typing rule, 1 must be intexp to have L:=E: comm. Otherwise, L:=E has no typing. {... Unicity of typing holds for all four syntax domains. Wolfgang Schreiner 13
Typing Rules Dene a Language Typing rules (not abstract syntax) dene language. { Only well-formed programs are of value. { Programs are well-typed trees. Signicance of unicity of typing: { Linear representation without type annotations represents (at most) one program. { Example: 0+1. Without unicity of typing: { Coherence: dierent tree derivations of a linear representation should have same meaning. { E:intexp E:realexp E 1 :realexp E 2 :realexp E 1 +E 2 :realexp { (((0) int +(1) int ) intexp ) realexp. { ((((0) int ) intexp ) realexp + (((1) int ) intexp ) realexp ) realexp Wolfgang Schreiner 14
Proof Trees Programs may be directly derived from typing rules. Typing rules form a logic. Set of axioms and inference rules. (Inverted) trees are logic proof trees. loc_1: intloc 1: int loc_1: intloc 0: int @loc_1: intexp 1: intexp @loc_1: intexp 0: intexp loc_2 : intloc @loc_1 +1: intexp @loc_1 =0 : intexp loc_2 :=@ loc_1 +1: comm while @loc_1 =0 do loc_2 :=@ loc_1+1 od : comm Wolfgang Schreiner 15
Semantics of the Core Language Denotational semantics Recursively dened function. { Mapping of a well-typed derivation tree to its mathematical meaning. Semantic algebras. { Meaning sets (domains) and operations. { Bool, Int, Location, Store. For each typing rule, a recursive denition. { L: intloc E: intexp L:=E: comm { [[L:=E: comm]]... =... [[L: intloc]]... [[E: intexp]]... Compositional semantic denitions. { Meaning of tree constructed from meanings of its subtrees. Function [[.]] is read as \the meaning of" Wolfgang Schreiner 16
Semantic Algebras Bool = ftrue, falseg not: Bool! Bool not(false) = true; not(true) = false equalbool: Bool Bool! Bool equalbool(m, n) = (m=n) Int = f..., -1, 0, 1,... g plus: Int Int! Int plus(m, n) = m + n equalint: Int Int! Bool equalint(m, n) = (m=n) Location = floc i j i > 0g Wolfgang Schreiner 17
Semantic Algebras Store = f hn 1 ; n 2 ; : : : ; n m i j n i 2 Int, 1 i m, m 0 g lookup: Location Store! Int lookup(loc j, hn 1 ; n 2 ; : : : ; n j ; : : : ; n m i) = n j (if j > m, then lookup(loc j, hn 1 ; : : : ; n m i) = 0) update: Location Int Store! Store update(loc j, j, hn 1 ; n 2 ; : : : ; n j ; : : : ; n m i) = hn 1 ; n 2 ; : : : ; n; : : : ; n m i (if j > m, then update(loc j, n, hn 1 ; : : : ; n m i) = hn 1 ; n 2 ; : : : ; n m i) if : Bool Store? Store?! Store? if (true, s 1, s 2 ) = s 1 if (false, s 1, s 2 ) = s 2 (Store? = Store [ f?g,? = \bottom" = non-termination) Wolfgang Schreiner 18
Command Semantics [[.: comm]]: Store! Store? [[L:=E: comm]](s) = update([[l: intloc]], [[E: intexp]](s), s) [[C 1 ;C 2 : comm]](s) = [[C 2 : comm]]([[c 1 : comm]](s)) [[if E then C 1 else C 2 : comm]](s) = if ([[E: boolexp]](s), [[C 1 : comm]](s), [[C 2 : comm]](s)) [[while E do C od: comm]](s) = w(s) where w(s) = if ([[E: boolexp]](s), w([[c: comm]](s)), s) [[skip: comm]](s) = s The meaning of a command is a function from Store to Store. Wolfgang Schreiner 19
Expression Semantics [[.: exp]]: Store! (Int [ Bool) [[N: intexp]](s) = [[N: int]] [[@L: intexp]](s) = lookup([[l: intloc]], s) [[:E: boolexp]](s) = not([[e: boolexp]](s)) [[E 1 +E 2 : intexp]](s) = plus([[e 1 : intexp]](s), [[E 2 : intexp]](s)) [[E 1 =E 2 : boolexp]](s) = equalbool([[e 1 : boolexp]](s), [[E 2 : boolexp]](s)) [[E 1 =E 2 : boolexp]](s) = equalint([[e 1 : intexp]](s), [[E 2 : intexp]](s)) [[.: intloc]]: Location [[loc i : intloc]] = loc i [[.: int]]: Int [[n: int]] = n The meaning of an expression is a function from Store to Int or Bool. Wolfgang Schreiner 20
Example P = Q; R Q = loc 2 :=1; R = if @loc 2 =0 then skip else S S = loc 1 :=@loc 2 +4 [[P: comm]](s) = [[R: comm]]([[q: comm]](s)) = [[R: comm]]update(loc 2, 1, s) = if ([[@loc 2 =0: boolexp]]update(loc 2, 1, s), [[skip: comm]]update(loc 2, 1, s), [[S: comm]]update(loc 2, 1, s)) = if (false, [[skip: comm]]update(loc 2, 1, s), [[S: comm]]update(loc 2, 1, s)) = [[S: comm]]update(loc 2, 1, s) = update(loc 1, [[@loc 2 +4: intexp]]update(loc 2, 1, s), update(loc 2, 1, s)) = update(loc 1, 5, update(loc 2, 1, s)) Program semantics can be studied independently of specic storage vector! Wolfgang Schreiner 21
Soundness of the Typing Rules. Are the typing rules sensible in their assignment of type attributes to phrases? Typing rules must be sound. { Every well-typed program has a meaning. Type attributes: { ::= int j bool { ::= intloc j exp j comm Mapping of attributes to meanings: { [[int]] = Int { [[bool]] = Bool { [[intloc]] = Location { [[ exp]] = Store! [[ ]] { [[comm]] = Store! Store? How are [[P:]] and [[]] related? Wolfgang Schreiner 22
Soundness Theorem [[P:]] 2 [[]], for every well-typed phrase P: Case n: int { [[n: int]] = n 2 Int = [[int]] Case @L: intexp { We know [[L: intloc]] = l 2 [[intloc]] = Location. Then, for every Store s, [[@L: intexp]](s) = lookup(l, s) 2 Int i.e. [[@L: intexp]] 2 Store! Int = [[intexp]]. Case C 1 ;C 2 : comm { We know [[C 1 : comm]] and [[C 2 : comm]] are elements of Store! Store?. For every Store s, we have [[C 1 ;C 2 : comm]](s) = [[C 2 : comm]]([[c 1 : comm]](s)) and [[C 2 :comm]](s) = s 1 2 Store?. If s 1 =?, [[C 2 : comm]](s 1 )=? 2 Store?. If s 1 2 Store, then [[C 2 : comm]](s 1 ) 2 Store?. Hence, [[C 1 ;C 2 : comm]] 2 Store! Store? = [[comm]]. Prove one case for each typing rule. Wolfgang Schreiner 23
Operational Properties Denotational semantics constructs mathematical functions. { Function extensionality for reasoning. Operational semantics reveals computational patterns. { Computation steps undertaken for evaluating the program. Denotational semantics has operational ower. { [[loc 3 :=@loc 1 +1: comm]]h3; 4; 5i ) update(loc 3, [[@loc 1 +1: intexp]]h3; 4; 5i, h3; 4; 5i) )... ) update(loc 3, 4, h3; 4; 5i) ) h3; 4; 4i Can we use denotational denitions as operational rewrite rules? Wolfgang Schreiner 24
Denotations as Rewrite Rules Op. semantics reduces programs to values. A program is a phrase [[C: comm]]s 0. Values are from semantic domains. { Booleans, numerals, locations, storage vectors. Equational denitions get rewrite rules. { Denotation: f (x 1 ; x 2 ; : : : ; x n ) = v { Rule: f (x 1 ; x 2 ; : : : ; x n ) ) v Computation is a sequence of rewrite steps p 0 ) pn. { p 0 ) p 1 ) : : : ) p n. { Each computation step p i ) p i+1 replaces a subphrase (the redex) in p i according to some rewrite rule. If pn is a value, computation terminates. Which properties shall semantics fulll? Wolfgang Schreiner 25
Properties of Operational Semantics Soundness. { If p has an underlying \meaning" m and p ) p 0, then p 0 means m as well. { By denition of ). Subject reduction. { If p has an underlying \type" and p ) p 0, then p 0 has as well. { By soundness of typing. Strong typing. { If p is well-typed and p ) p 0, then p 0 contains no operatoroperand incompatibilities. { By induction over computation rules. Computational adequacy. { A program p's underlying meaning is a proper meaning m, if there is some value v such that p ) v and v means m. Wolfgang Schreiner 26
Computability of Phrases Predicate comp (computable): { comp intloc (p) := p ) v and v means l where l 2 Location is the meaning of p. { comp exp (p) := p(s) ) v and v means n where s 2 Store and p(s) means n 2 [[ ]]. { compcomm(p) := p(s) ) v and v means s 0 where s 2 Store and p(s) means s 0 2 Store. comp [[U: ]] holds for all well-typed phrases U:. { Induction on typing rules. Computational adequacy follows from soundness of typing, soundness of operational semantics and the computability of phrases. Wolfgang Schreiner 27
Design of a Language Core Contradictory design objectives: Oriented towards a specic problem area. General purpose. User friendly. Ecient implementation possible. Extensible by new language features. Secure agains programming errors. Simple syntax and semantics. Logical support for verication.... Design is an artistic activity! Wolfgang Schreiner 28
Orthagonality A language should be based on few fundamental principles that may be combined without unneccessary restrictions. Orthagonal languages are easier to understand for programmers and implementors. Denotational semantics may help to achieve this. { Dene sets of meanings and operations. { Give syntactic representations. { Organize into abstract syntax denition. In the following we will study a set of basic design principles. Wolfgang Schreiner 29