CS 541 Lecture -*- Outline -*- ** sequential aspects of SR often like C *** values and types **** primitive types -------------- SR PRIMITIVE TYPES bool (true, false) int real char 'c' string "a string" C escapes || is string concatenation length, maxlength var s = string[20] s[2:5] -------------- **** composite types ---------------- SR COMPOSITE TYPES arrays type real_matrix = [10,10] real type grades_array = ['a':'e'] int var rm : real_matrix, a[1:10]: int rm := ([10] ([10] 0.0)) ------------- lower bound is implicitly 1, can specify it if want to use lb and ub to get them ------------- enum as in C type color = enum(red, green,blue) records type dims = rec ( h: real; w: real) var ds: dims := dims(7.3, 2.9) ds.h ---------------- order of fields matters! ----------------- unions (not tagged, as in C) type uper = union(nam: string[10]; b: bool) pointer types type pint = ptr int type void_star = ptr any var x: int, p: pint p := @x; p := new(int); p^ ------------------ @ is address-of operator ^ is dereference **** type equivalence ------------------ SR TYPE SYSTEM checking: static equality: STRUCTURAL basic elements same (recursively) arrays: by dimensions num of elements in each dimen. types of indexes don't matter [2,2] int records/unions: number and type field names don't matter! rec(int; real) union(int; real) enum, same number (!) of literals coercions: int to real r := i string[k] to string[n] if k <= n long := short ---------------------- **** expressions aggregates for arrays and records, as shown above. no if expressions *** statements --------------------- SR STATEMENTS skip; stop; begin ... end if x < y -> m := x [] x > y -> m := y [] else -> m := x fi --------------------- guards evaluated in arbitrary order, if none are true, do else part (else is not equivalent to true) if no else part, nothing happens (not abort) -------------------- do x < y -> y := y-x [] y < x -> x := x-y od -------------------- terminates when no guard is true use of else can lead to infinite looping -------------------- fa i := 1 to 10 -> write(i) af fa i := 1 to 3, j := i-1 downto 0 -> write(i,j) af ------------------- writes 1 0 2 1 2 0 3 2 3 1 3 0 ------------------- fa i := 1 to 20 by 2 -> write(i) af cnt := 0 fa i := lb(v) to ub(v) st v[i] = 0 -> cnt++ af ------------------- st stands for "such that" can use exit (like C break) and next (like C continue) to get out of or go around again in a loop. *** bindings **** scope the usual static scoping declarations visible from point of declaration to end of block for mutual recursion have to have some kind of forward decl **** declarations see above for examples can have variable definitions (uninitialized) can also declare contants (const) may be mixed with statements only sequential decls (may depend on previous values) **** blocks block commands only: begin ... end implicit blocks in bodies of most statements *** abstraction **** procedure and function abstractions ------------- SR PROCEDURES procedure sort(var a[*]: int) fa i := lb(a) to ub(a)-1, j := i+1 to ub(a) st a[i] > a[j] -> a[i] :=: a[j] af end procedure id(x : int) returns y: int y := x end call sort(my_arr) sort(my_arr) 4 + id(3) -------------- Pascal like way to return a value: assign to formal result **** parameters -------------- SR PARAMETER PASSING MODE MECHANISM val value res result var value-result (!) ref reference default is val (value) --------------- the return value is passed by result (copied out) **** other aspects of procedures ***** return statement return ends procedure call ***** operation and proc declarations ---------------- SEPARATING DECLARATION AND BODY op sort(var b[*]: int) # ... a comment ... proc sort(a) fa i := lb(a) to ub(a)-1, j := i+1 to ub(a) st a[i] > a[j] -> a[i] :=: a[j] af end ---------------- types and modes aren't repeated ***** operation types formal names can be different! ---------------- ### another way ### optype sort_t = (var b[*]: int) op sort : sort_t proc sort(a) fa i := lb(a) to ub(a)-1, j := i+1 to ub(a) st a[i] > a[j] -> a[i] :=: a[j] af end ---------------- ***** operation capabilities ---------------- OPERATION CAPABILITIES cap sort_t is a type (pointer to op) var sorter: cap sort_t var sorter2: cap (var b[*]: int) constants: noop null ---------------- *** encapsulation the main organizing units in SR are the global and the resource --------------- ORGANIZING SR PROGRAMS resources: are classes instances (objects) created dynamically can be parameterized variables hidden! indirect naming of procs r.p() globals: like a single, unparameterized resource automatically created collection of variables shared in an address space (vm) direct naming of procs by clients p() --------------- resources like Modula-2 modules, but dynamic *** resources abstraction of a physical resource ---------------- RESOURCES resource Stack type result = enum(OK, OVER, UNDER) op push(item: int) returns r: result op pop(res item: int) returns r: result body Stack(size: int) var store[1:size]: int, top: int := 0 proc push(item) returns r if top < size -> store[++top] := item; r := OK [] top = size -> r := OVER fi end proc pop(item) returns r if top > 0 -> item := store[top--]; r := OK [] top = 0 -> r := UNDER if end end Stack ---------------- this declaration by itself does NOT create any stack resources the code outside of procs is "initialization code" executed when stack created **** separate compilation ----------------- SEPARATE RESOURCE SPEC AND BODY resource Stack type result = enum(OK, OVER, UNDER) op push(item: int) returns r: result op pop(res item: int) returns r: result body Stack(size: int) separate ### later... ### body Stack var store[1:size]: int, top: int := 0 proc push(item) returns r if top < size -> store[++top] := item; r := OK [] top = size -> r := OVER fi end proc pop(item) returns r if top > 0 -> item := store[top--]; r := OK [] top = 0 -> r := UNDER if end end Stack ----------------- **** use ----------------- IMPORT & CREATION OF RESOURCE resource Stack_User body Stack_User() import Stack var x: Stack.result var s1, s2: cap Stack # capabilities var y: int s1 := create Stack(10) s2 := create Stack(20) #... s1.push(4); s1.push(37) s2.push(98) if s1.pop(y) = OK -> write(y) fi end ----------------- can destroy resources using destroy statement **** capabilities ----------------- RESOURCE CAPABILITIES - pointers to resource instances constants: null, noop - returned by create Type compatability: same number of signature compatible ops (can't have more or less ops) in same order (names don't matter!) parameters don't matter resource St # compatible with Stack type status = enum(NORM, OVR, UNDR) op add(it: int) returns s: status op drop(res it: int) returns s: status body St() separate ----------------- **** finalization final ... end anywhere in body often used to print results, executed just before resource disappears **** extension ------------------ EXTENDING RESOURCES resource NewStack extend Stack op count() returns r: int body NewStack(size: int) separate ------------------ **** abstract resources sometimes want to write a resource only as the basis for extension, no body ------------------ ABSTRACT RESOURCES resource Abstract_Stack type result = enum(OK, OVER, UNDER) op push(item: int) returns r: result op pop(res item: int) returns r: result end Abstract_Stack resource Stack import Abstract_Stack body Stack(size: int) # ... as before ... end Stack ------------------ *** globals ------------------ GLOBALS global Screen op refresh(), up(), down() op move_to(x,y: int) body Screen proc refresh() # ... end proc move_to(x,y) # ... end var where_x: int := 0, where_y: int := 0 refresh(); move_to(0,0) #... end ------------------ this is like a resource, but called differently may be more efficient to call these, as known to be in same address space