CS558 Programming Languages

Similar documents
CS558 Programming Languages

CS558 Programming Languages

CS558 Programming Languages. Winter 2013 Lecture 3

CS 330 Lecture 18. Symbol table. C scope rules. Declarations. Chapter 5 Louden Outline

The SPL Programming Language Reference Manual

CS321 Languages and Compiler Design I Winter 2012 Lecture 13

Programming Languages Third Edition. Chapter 7 Basic Semantics

CS558 Programming Languages Winter 2018 Lecture 4a. Andrew Tolmach Portland State University

CS558 Programming Languages

Chapter 5. Names, Bindings, and Scopes

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler Front-End

The role of semantic analysis in a compiler

The PCAT Programming Language Reference Manual


In Java we have the keyword null, which is the value of an uninitialized reference type

Lecture 7: Type Systems and Symbol Tables. CS 540 George Mason University

CS 536 Introduction to Programming Languages and Compilers Charles N. Fischer Lecture 11

Design Issues. Subroutines and Control Abstraction. Subroutines and Control Abstraction. CSC 4101: Programming Languages 1. Textbook, Chapter 8

Topics Covered Thus Far CMSC 330: Organization of Programming Languages

CS558 Programming Languages

Short Notes of CS201

Static Semantics. Lecture 15. (Notes by P. N. Hilfinger and R. Bodik) 2/29/08 Prof. Hilfinger, CS164 Lecture 15 1

The Compiler So Far. CSC 4181 Compiler Construction. Semantic Analysis. Beyond Syntax. Goals of a Semantic Analyzer.

Programmin Languages/Variables and Storage

CS201 - Introduction to Programming Glossary By

Chapter 5 Names, Binding, Type Checking and Scopes

Semantic Analysis. Outline. The role of semantic analysis in a compiler. Scope. Types. Where we are. The Compiler so far

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages. Memory Management and Garbage Collection

Names, Scope, and Bindings

Anatomy of a Compiler. Overview of Semantic Analysis. The Compiler So Far. Why a Separate Semantic Analysis?

SE352b: Roadmap. SE352b Software Engineering Design Tools. W3: Programming Paradigms

1 Lexical Considerations

CS558 Programming Languages

Lecture 16: Static Semantics Overview 1

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

CMSC 330: Organization of Programming Languages

Attributes, Bindings, and Semantic Functions Declarations, Blocks, Scope, and the Symbol Table Name Resolution and Overloading Allocation, Lifetimes,

G Programming Languages - Fall 2012

CS558 Programming Languages

Qualifying Exam in Programming Languages and Compilers

CMSC 330: Organization of Programming Languages

CSE 504. Expression evaluation. Expression Evaluation, Runtime Environments. One possible semantics: Problem:

CSC 533: Organization of Programming Languages. Spring 2005

CSE 307: Principles of Programming Languages

The Compiler So Far. Lexical analysis Detects inputs with illegal tokens. Overview of Semantic Analysis

CS321 Languages and Compiler Design I. Winter 2012 Lecture 2

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

Names, Scope, and Bindings

Lexical Considerations

Syntax Errors; Static Semantics

CSCE 314 Programming Languages. Type System

Topics Covered Thus Far. CMSC 330: Organization of Programming Languages. Language Features Covered Thus Far. Programming Languages Revisited

Name, Scope, and Binding. Outline [1]

Lexical Considerations

Informal Semantics of Data. semantic specification names (identifiers) attributes binding declarations scope rules visibility

Run-time Environments

Run-time Environments

CS558 Programming Languages. Winter 2013 Lecture 4

Class Information ANNOUCEMENTS

CPSC 213. Introduction to Computer Systems. Instance Variables and Dynamic Allocation. Unit 1c

CS558 Programming Languages

Programming Languages Third Edition. Chapter 10 Control II Procedures and Environments

Advances in Programming Languages: Regions

Names, Bindings, Scopes

CPSC 3740 Programming Languages University of Lethbridge. Data Types

INF 212 ANALYSIS OF PROG. LANGS FUNCTION COMPOSITION. Instructors: Crista Lopes Copyright Instructors.

Weeks 6&7: Procedures and Parameter Passing

Next: What s in a name? Programming Languages. Data model in functional PL. What s in a name? CSE 130 : Fall Lecture 13: What s in a Name?

Outline. Java Models for variables Types and type checking, type safety Interpretation vs. compilation. Reasoning about code. CSCI 2600 Spring

CS321 Languages and Compiler Design I. Fall 2013 Week 8: Types Andrew Tolmach Portland State University

Binding and Storage. COMP 524: Programming Language Concepts Björn B. Brandenburg. The University of North Carolina at Chapel Hill

Functional Programming. Pure Functional Programming

Compiler Construction

Semantic Analysis. Lecture 9. February 7, 2018

Heap, Variables, References, and Garbage. CS152. Chris Pollett. Oct. 13, 2008.

G Programming Languages - Fall 2012

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

CS 360 Programming Languages Interpreters

Runtime. The optimized program is ready to run What sorts of facilities are available at runtime

Names, Scope, and Bindings

Static Semantics. Winter /3/ Hal Perkins & UW CSE I-1

Scope, Functions, and Storage Management

Compilers. Type checking. Yannis Smaragdakis, U. Athens (original slides by Sam

THE GOOD, BAD AND UGLY ABOUT POINTERS. Problem Solving with Computers-I

CMSC 330: Organization of Programming Languages. Ownership, References, and Lifetimes in Rust

Computer Science Department Carlos III University of Madrid Leganés (Spain) David Griol Barres

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

CS 430 Spring Mike Lam, Professor. Data Types and Type Checking

CPSC 213. Introduction to Computer Systems. Winter Session 2017, Term 2. Unit 1c Jan 24, 26, 29, 31, and Feb 2

Storage. Outline. Variables and updating. Copy vs. Ref semantics Lifetime. Dangling References Garbage collection

CSCI-GA Scripting Languages

Static Program Analysis Part 1 the TIP language

Compiler construction

CSE 307: Principles of Programming Languages

G Programming Languages - Fall 2012

Names, Scopes, and Bindings. CSE 307 Principles of Programming Languages Stony Brook University

Structure of Programming Languages Lecture 10

Types II. Hwansoo Han

Transcription:

CS558 Programming Languages Fall 2017 Lecture 3a Andrew Tolmach Portland State University 1994-2017

Binding, Scope, Storage Part of being a high-level language is letting the programmer name things: variables constants types functions classes modules fields operators... Generically, we call names identifiers An identifier binding makes an association between the identifier and the thing it names An identifier use refers to the thing named The scope of a binding is the part of the program where it can be used 2

Scala Example object Printer { def print(expr: Expr) : String = unparse(expr).tostring() } def unparse(expr: Expr) : SExpr = expr match { case Num(n) => SNum(n) case Add(l,r) => SList(SSym("+")::unparse(l)::unparse(r)::Nil) case Mul(l,r) => SList(SSym("*")::unparse(l)::unparse(r)::Nil) case Div(l,r) => SList(SSym("/")::unparse(l)::unparse(r)::Nil) } binding use keyword Identifier syntax is language-specific Usually unbounded sequence of alpha numeric symbol(?) Further rules/conventions for different categories Identifiers are distinct from keywords! Some identifiers are pre-defined 3

Names, values, variables Most languages let us bind variable names to memory cells (the store) that contain values Name gives access to cell for read or update Many languages also let us bind names directly to (immutable) values computed by expressions Sometimes (confusingly) also called variables Scala var vs. val They let us share expressions to save repeated writing and, maybe, evaluation 4

Local Value Bindings expr ::= num expr + expr... (expr) id let id = expr in expr scope Add (let a = 8 + 5 in a * 3) + 3 Leta Num3 Add Mul binding use Num8 Num5 Vara Num3 5

Bound vs. Free A variable use x is bound if it appears in the scope of a binding for x Otherwise, it is free Bound and free are relative to an enclosing subexpression, e.g. a is bound in (let a = 8 + 5 in a * 3) but free in a * 3 We cannot evaluate a free variable 6

scopea scopeb Parallel Scopes Add (let a = 8 + 5 in a * 3) + (let b = 1 in b + 2) Leta Letb Add Mul Num1 Add Num8 Num5 Vara Num3 Varb Num2 What if both let s bind a? 7

Nested Scopes (let a = 8 + 5 in let b = a - 10 in a * b) + 2 Leta Add Num2 Add Letb scopea scopeb Mul Num8 Num5 Sub Vara Varb scopea scopea&b Vara Num10 8

scopea Shadowing Add (let a = 8 + 5 in let a = a - 10 in 36 + a) + 3 Leta Num3 Add Leta scopea Num8 Num5 Sub Add Vara Num10 Num36 Vara Nearest enclosing binding wins 9

Functions and parameters Consider adding functions with parameters to our expression language We give names to these parameters The scope of a parameter is the function body The value of each parameter is provided at the function call (or application ) site declaration AST (f x (+ x 3)) application AST (@ f (* 13 3)) { { function name formal parameter body 10 function name actual parameter

Function parameter scoping (f x (+ x 3)) Fundeff,x Add scopex Varx Num3

Function Name Scoping Typically, we want to allow functions to be recursive Scope of function s name includes its own body scopef letfun f x = if x = 0 then 1 else x*f(x-1) in f(42) 12

Mutually Recursive Definitions letrec f(x) = g(x + 1) and g(y) = f(y - 1) in f(2) + g(4) scopef,g Many earlier languages were designed to be compiled by a single pass through the source code and therefore use forward declarations void g (double y); /* declares g but doesn t define it */ void f(double x) { g(x+1.0); } void g(double y) { f(y-1.0); } /* definition is here */ C In some languages, all top-level definitions are (implicitly) treated as mutually recursive.

Dynamic Scope What should happen in the following program? letfun f(x) = x + y in f(42) How about this one? letfun f(x) = x + y in let y = 2 in f(42) One possible answer: let the value of y leak into f This is an example of dynamic scope Bad idea! 14 Why?

Static scope / Lexical scope Better if this program remains erroneous letfun f(x) = x + y in let y = 2 in f(42) Looking at a function declaration, we can always determine if and where a variable is bound without considering the dynamic execution of the program! Some scripting languages still use dynamic scope, but as programs get larger, its dangers become obvious 15

Re-using names What happens when the same name is bound twice in the same scope? If the bindings are to different kinds of things (e.g. types vs. variables), can often disambiguate based on syntax, so no problem arises (except maybe readability): type Foo = Int val Foo : Foo = 10 val Bar : Foo = Foo + 1 Scala Here we say that types and variables live in different name spaces If the bindings are in the same namespace, typically an error. But sometimes additional info (such as types) can be used to pick the right binding; this is called overloading

Named scopes: modules, classes Often, the construct that delimits a scope can itself has a name, allowing the programer to manage explicitly the visibility of the names inside it OCaml modules module Env = struct type env = (string * int) list let empty : env = [] let rec lookup (e:env) (k:string) : int =... end let e0 : Env.env = Env.empty in Env.lookup e0 "abc" Java classes class Foo { static int x; static void f(int x); } int z = Foo.f(Foo.x)

Semantics via Environments An environment is a mapping from names to their bindings The environment at a program point describes all the bindings in scope at that point Environment is extended when binding constructs are evaluated Environment is consulted to determine the meaning of names during evaluation

Environments for everything Environments can hold binding information for all kinds of names a variable name is (typically) bound to location [in the store] containing the variable a value (constant) name may be bound directly bound to the value [environment = store] a function name is bound to description of the function s parameters and body a type name is bound to a type description, including the layout of its values a class name is bound to a list of the class s content etc.

Variables, Environment, Store In most imperative languages, variable names are bound to locations, which in turn contain values. So creating a variable involves two things: 1. allocating a new store location (and possibly initializing its contents) 2. creating a new binding from the variable name to that location

Initialization Values Many languages require variables to be declared before they are used: this gives them a scope, perhaps a type, and (maybe) an initial value given by an expression It is surely a bug to use any variable as an r-value unless it has been previously assigned a value. But many languages let us write such code, resulting in runtime errors either checked (e.g. as in Python) or unchecked (e.g. as in C) Simplest fix is to require an initial value to be given for every declared variable (e.g. as in Scala)

Checking Initialization Java takes a more sophisticated approach variables do not need to be initialized at the point of declaration, but they must be initialized before they are used int a; if (b) /* b is boolean */ a = 3; else a = 4; a = a + 1; But checking initialization before use is uncomputable in general! (Why?) a legal Java program

Definite Assignment So the Java definition carefully details a conservative, computable, set of conditions, which every program must meet, that guarantee the absence of uses before definition. This is called the definite assignment property; just defining it takes 16 pages of the reference manual. Having these rules in the Java definition ensures portability Being conservative means that some programs that actually do initialize before use will be rejected int a; if (b) a = 3; if (!b) a = 4; a = a + 1; an illegal Java program

Describing the Store In most languages, there are other ways to allocate storage too, such as explicit new operations or implicit boxing operations Simplistic store model: mutable map from locations to values Better models require distinguishing different classes of storage based on the lifetime of the data

Storage Lifetimes Typical computations use far more memory locations in total than they use at any one point So most language implementations support re-use of memory locations that are no longer needed lifetime time allocation deallocation The lifetime of every object should cover all moments when the object is being used Otherwise, we get a memory safety bug

Storage Classes: Static Data Lifetime = Entire Execution Typically used for global variables and constants If language has no recursion, can also be used for function-local variables Fixed address known before program executes No runtime allocation/deallocation costs

Storage Classes: Stack Data Nested Lifetimes (last allocated is first deallocated) Typically used for function-local variables (and internal control data for function calls) Works because function call lifetimes also nest Allocation/deallocation are very cheap (just adjust the stack pointer) Produces good locality for caches, virtual memory

Storage Classes: Heap Data Arbitrary Lifetimes Typically used for explicitly allocated objects Some languages implicitly heap-allocate other data structures, e.g. bignums, closures, etc. Allocation/deallocation are relatively expensive Run-time library must decide where to allocate Deallocation can be done manually (risking memory bugs) or by a garbage collector

Scope, Lifetime, Memory Safety Lifetime and scope are closely connected For a language to be memory safe, it suffices to make sure that in-scope identifiers never point (directly or indirectly) to deallocated objects For stack-allocated local variables, this happens naturally Stack locations are deallocated only when function returns and its local variables go out of scope forever For heap data, easiest to enforce safety using a garbage collector (GC) GC typically works by recursively tracing all objects reachable from names that are currently in scope (or that might come back into scope later) Only unreachable objects are deallocated, making their locations available for future re-allocation

Explicit Deallocation Many older languages (notably C/C++) support explicit deallocation of heap objects Somewhat more efficient than GC char *foo() { char *p = malloc(100); free(p); return p;} But makes language unsafe: dangling pointer bug occurs if we deallocate an object that is still in use [unchecked runtime error] Converse problem: space leak bug occurs if we don t deallocate an unneeded object. Not a safety problem, but may unnecessarily make program run slower or crash with out of memory error