Type Checking Binary Operators

Similar documents
Type Checking While Loops

Type Checking Binary Operators

Run-Time Data Structures

Type Checking Simple Variable Declarations

Classes, Structs and Records. Internal and External Field Access

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

Introduction to Programming Using Java (98-388)

1 Lexical Considerations

12/4/18. Outline. Implementing Subprograms. Semantics of a subroutine call. Storage of Information. Semantics of a subroutine return

Lexical Considerations

Implementing Subprograms

Programming Languages: Lecture 12

Chapter 10. Implementing Subprograms ISBN

The Decaf Language. 1 Lexical considerations

Short Notes of CS201

Qualifying Exam in Programming Languages and Compilers

Subprograms, Subroutines, and Functions

Implementing Subroutines. Outline [1]

CS201 - Introduction to Programming Glossary By

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

Lexical Considerations

Chapter 9. Def: The subprogram call and return operations of a language are together called its subprogram linkage

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

FORM 2 (Please put your name and form # on the scantron!!!!)

The Decaf language 1

CIT Week13 Lecture

CA Compiler Construction

Module 27 Switch-case statements and Run-time storage management

Chapter 10. Implementing Subprograms

Naming in OOLs and Storage Layout Comp 412

Implementing Subprograms

IC Language Specification

CS356: Discussion #6 Assembly Procedures and Arrays. Marco Paolieri

Today's Topics. CISC 458 Winter J.R. Cordy

Functions in MIPS. Functions in MIPS 1

Run-time Environments

Run-time Environments

The compilation process is driven by the syntactic structure of the program as discovered by the parser

CSE P 501 Compilers. Static Semantics Hal Perkins Winter /22/ Hal Perkins & UW CSE I-1

System Software Assignment 1 Runtime Support for Procedures

SEMANTIC ANALYSIS TYPES AND DECLARATIONS

! Those values must be stored somewhere! Therefore, variables must somehow be bound. ! How?

G Programming Languages Spring 2010 Lecture 4. Robert Grimm, New York University

Chapter 14 Functions

COMP 303 Computer Architecture Lecture 3. Comp 303 Computer Architecture

Chapter 6 Introduction to Defining Classes

Semantic actions for declarations and expressions

Run-time Environments. Lecture 13. Prof. Alex Aiken Original Slides (Modified by Prof. Vijay Ganesh) Lecture 13

CS 536 Spring Programming Assignment 1 Identifier Cross-Reference Analysis

Semantic actions for declarations and expressions. Monday, September 28, 15

Chapter 2A Instructions: Language of the Computer

Object Oriented Programming: In this course we began an introduction to programming from an object-oriented approach.

Subprograms. Copyright 2015 Pearson. All rights reserved. 1-1

CSE 401/M501 Compilers

Scope, Functions, and Storage Management

Concepts Introduced in Chapter 7

Semantic Analysis and Type Checking

CS143 Handout 03 Summer 2012 June 27, 2012 Decaf Specification

CS 112 Introduction to Computing II. Wayne Snyder Computer Science Department Boston University

CSE 504: Compiler Design. Runtime Environments

IR Generation. May 13, Monday, May 13, 13

We cover recursion in 150. Why do it again in 151?

Programming Languages

Machine Language Instructions Introduction. Instructions Words of a language understood by machine. Instruction set Vocabulary of the machine

Storage in Programs. largest. address. address

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

Three-Address Code IR

Compiling Techniques

Chapter 5 Names, Bindings, Type Checking, and Scopes

// the current object. functioninvocation expression. identifier (expressionlist ) // call of an inner function

Decaf Language Reference Manual

Advanced Programming & C++ Language

AP COMPUTER SCIENCE JAVA CONCEPTS IV: RESERVED WORDS

Statement Basics. Assignment Statements

Pointers II. Class 31

An Activation Record for Simple Subprograms. Activation Record for a Language with Stack-Dynamic Local Variables

The Procedure Abstraction

Chapter 10 Implementing Subprograms

1 Epic Test Review 2 Epic Test Review 3 Epic Test Review 4. Epic Test Review 5 Epic Test Review 6 Epic Test Review 7 Epic Test Review 8

CSE443 Compilers. Dr. Carl Alphonce 343 Davis Hall

Semantic actions for declarations and expressions

G Programming Languages - Fall 2012

Code Generation. Dragon: Ch (Just part of it) Holub: Ch 6.

Chapter 9 Subprograms

Example. program sort; var a : array[0..10] of integer; procedure readarray; : function partition (y, z :integer) :integer; var i, j,x, v :integer; :

FORM 1 (Please put your name and section number (001/10am or 002/2pm) on the scantron!!!!) CS 161 Exam II: True (A)/False(B) (2 pts each):

Implementing Coroutines with call/cc. Producer/Consumer using Coroutines

Stack Frames. September 2, Indiana University. Geoffrey Brown, Bryce Himebaugh 2015 September 2, / 15

LAB C Translating Utility Classes

Compiler Design. Code Shaping. Hwansoo Han

Course Administration

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

Decaf Language Reference

Topic 7: Activation Records

Procedure and Object- Oriented Abstraction

Lecture 5. Announcements: Today: Finish up functions in MIPS

Compilers and Code Optimization EDOARDO FUSELLA

Racket: Modules, Contracts, Languages

Programming Language Concepts Scoping. Janyl Jumadinova January 31, 2017

The SPL Programming Language Reference Manual

Transcription:

Type Checking Binary Operators binaryopnode expr tree expr tree Type checking steps: 1. Type check left and right operands. 2. Check that left and right operands are both scalars. 3. binaryopnode.kind = Value. 352

4. If binaryopnode.operator is a plus, minus, star or slash: (a) Check that left and right operands have an arithmetic type (integer or character). (b) binaryopnode.type = Integer 5. If binaryopnode.operator is an and or is an or: (a) Check that left and right operands have a boolean type. (b) binaryopnode.type = Boolean. 6. If binaryopnode.operator is a relational operator: (a) Check that both left and right operands have an arithmetic type or both have a boolean type. (b) binaryopnode.type = Boolean. 353

Type Checking Assignments asgnode namenode expr tree Type checking steps: 1. Type check the namenode. 2. Type check the expression tree. 3. Check that the namenode s kind is assignable (Variable, Array, ScalarParm, or ArrayParm). 4. If the namenode s kind is scalar then check the expression tree s kind is also scalar and that both have the same type. Then return. 354

5. If the namenode s and the expression tree s kinds are both arrays and both have the same type, check that the arrays have the same length. (Lengths of array parms are checked at runtime). Then return. 6. If the namenode s kind is array and its type is character and the expression tree s kind is string, check that both have the same length. (Lengths of array parms are checked at run- time). Then return. 7. Otherwise, the expression may not be assigned to the namenode. 355

Type Checking While Loops whilenode identnode stmtnode expr tree Type checking steps: 1. Type check the condition (an expr tree). 2. Check that the condition s type is Boolean and kind is scalar. 3. If the label is a null node then type check the stmtnode (the loop body) and return. 356

4.If there is a label (an identnode) then: (a) Check that the label is not already present in the symbol table. (b) If it isn t, enter label in the symbol table with kind= VisibleLabel and type= void. (c) Type check the stmtnode (the loop body). (d) Change the label s kind (in the symbol table) to HiddenLabel. 357

Type Checking Breaks and Continues breaknode identnode Type checking steps: 1. Check that the identnode is declared in the symbol table. 2. Check that identnode s kind is VisibleLabel. If identnode s kind is HiddenLabel issue a special error message. 358

Type Checking Returns returnnode expr tree It is useful to arrange that a static field named currentmethod will always point to the methoddeclnode of the method we are currently checking. Type checking steps: 1. If returnval is a null node, check that currentmethod.returntype is Void. 2. If returnval (an expr) is not null then check that returnval s kind is scalar and returnval s type is currentmethod.returntype. 359

Type Checking Method Declarations (no Overloading) methoddeclnode identnode typenode args tree decls tree stmts tree Type checking steps: 1. Create a new symbol table entry m, with type = typenode.type and kind = Method. 2. Check that identnode.idname is not already in the symbol table; if it isn t, enter m using identnode.idname. 3. Create a new scope in the symbol table. 4. Set currentmethod = this methoddeclnode. 360

5. Type check the args subtree. 6. Build a list of the symbol table nodes corresponding to the args subtree; store it in m. 7. Type check the decls subtree. 8. Type check the stmts subtree. 9. Close the current scope at the top of the symbol table. 361

Type Checking Method Calls (no Overloading) callnode identnode args tree We consider calls of procedures in a statement. Calls of functions in an expression are very similar. Type checking steps: 1. Check that identnode.idname is declared in the symbol table. Its type should be Void and kind should be Method. 362

2. Type check the args subtree. 3. Build a list of the expression nodes found in the args subtree. 4. Get the list of parameter symbols declared for the method (stored in the method s symbol table entry). 5. Check that the arguments list and the parameter symbols list both have the same length. 6. Compare each argument node with its corresponding parameter symbol: (a) Both must have the same type. (b) A Variable, Value, or ScalarParm kind in an argument node matches a ScalarParm parameter. An Array or ArrayParm kind in an argument node matches an ArrayParm parameter. 363

Reading Assignment Read Chapters 9 and 12 of Crafting a Compiler. 364

Virtual Memory & Run-Time Memory Organization The compiler decides how data and instructions are placed in memory. It uses an address space provided by the hardware and operating system. This address space is usually virtual the hardware and operating system map instruction- level addresses to actual memory addresses. Virtual memory allows: Multiple processes to run in private, protected address spaces. Paging can be used to extend address ranges beyond actual memory limits. 365

Run-Time Data Structures Static Structures For static structures, a fixed address is used throughout execution. This is the oldest and simplest memory organization. In current compilers, it is used for: Program code (often read- only & sharable). Data literals (often read- only & sharable). Global variables. Static variables. 366

Stack Allocation Modern programming languages allow recursion, which requires dynamic allocation. Each recursive call allocates a new copy of a routine s local variables. The number of local data allocations required during program execution is not known at compile- time. To implement recursion, all the data space required for a method is treated as a distinct data area that is called a frame or activation record. Local data, within a frame, is accessible only while a subprogram is active. 367

In mainstream languages like C, C+ + and Java, subprograms must return in a stack- like manner the most recently called subprogram will be the first to return. A frame is pushed onto a runtime stack when a method is called (activated). When it returns, the frame is popped from the stack, freeing the routine s local data. As an example, consider the following C subprogram: p(int a) { double b; double c[10]; b = c[a] * 2.51; } 368

Procedure p requires space for the parameter a as well as the local variables b and c. It also needs space for control information, such as the return address. The compiler records the space requirements of a method. The offset of each data item relative to the start of the frame is stored in the symbol table. The total amount of space needed, and thus the size of the frame, is also recorded. Assume p s control information requires 8 bytes (this size is usually the same for all methods). Assume parameter a requires 4 bytes, local variable b requires 8 bytes, and local array c requires 80 bytes. 369

Many machines require that word and doubleword data be aligned, so it is common to pad a frame so that its size is a multiple of 4 or 8 bytes. This guarantees that at all times the top of the stack is properly aligned. Here is p s frame: Padding Space for c Space for b Space for a Control Information Total size= 104 Offset = 20 Offset = 12 Offset = 8 Offset = 0 370

Within p, each local data object is addressed by its offset relative to the start of the frame. This offset is a fixed constant, determined at compile- time. We normally store the start of the frame in a register, so each piece of data can be addressed as a (Register, Offset) pair, which is a standard addressing mode in almost all computer architectures. For example, if register R points to the beginning of p s frame, variable b can be addressed as (R,12), with 12 actually being added to the contents of R at runtime, as memory addresses are evaluated. 371

Normally, the literal 2.51 of procedure p is not stored in p s frame because the values of local data that are stored in a frame disappear with it at the end of a call. It is easier and more efficient to allocate literals in a static area, often called a literal pool or constant pool. Java uses a constant pool to store literals, type, method and interface information as well as class and field names. 372

Accessing Frames at Run- Time During execution there can be many frames on the stack. When a procedure A calls a procedure B, a frame for B s local variables is pushed on the stack, covering A s frame. A s frame can t be popped off because A will resume execution after B returns. For recursive routines there can be hundreds or even thousands of frames on the stack. All frames but the topmost represent suspended subroutines, waiting for a call to return. The topmost frame is active; it is important to access it directly. The active frame is at the top of the stack, so the stack top 373

register could be used to access it. The run- time stack may also be used to hold data other than frames. It is unwise to require that the currently active frame always be at exactly the top of the stack. Instead a distinct register, often called the frame pointer, is used to access the current frame. This allows local variables to be accessed directly as offset + frame pointer, using the indexed addressing mode found on all modern machines. 374

Consider the following recursive function that computes factorials. int fact(int n) { if (n > 1) return n * fact(n-1); else return 1; } 375

The run- time stack corresponding to the call fact(3) (when the call of fact(1) is about to return) is: Space for n = 1 Top of Stack Control Information Return Value = 1 Space for n = 2 Frame Pointer Control Information Return Value Space for n = 3 Control Information Return Value We place a slot for the function s return value at the very beginning of the frame. Upon return, the return value is conveniently placed on the stack, just beyond the end of the caller s frame. Often compilers return scalar values in specially 376

designated registers, eliminating unnecessary loads and stores. For values too large to fit in a register (arrays or objects), the stack is used. When a method returns, its frame is popped from the stack and the frame pointer is reset to point to the caller s frame. In simple cases this is done by adjusting the frame pointer by the size of the current frame. 377

Dynamic Links Because the stack may contain more than just frames (e.g., function return values or registers saved across calls), it is common to save the caller s frame pointer as part of the callee s control information. Each frame points to its caller s frame on the stack. This pointer is called a dynamic link because it links a frame to its dynamic (runtime) predecessor. 378

The run- time stack corresponding to a call of fact(3), with dynamic links included, is: Space for n = 1 Dynamic Link Return Value = 1 Space for n = 2 Dynamic Link Top of Stack Frame Pointer Return Value Space for n = 3 Dynamic Link = Null Return Value 379

Classes and Objects C, C+ + and Java do not allow procedures or methods to nest. A procedure may not be declared within another procedure. This simplifies run- time data access all variables are either global or local. Global variables are statically allocated. Local variables are part of a single frame, accessed through the frame pointer. Java and C+ + allow classes to have member functions that have direct access to instance variables. 380

Consider: class K { int a; int sum(){ int b; return a+b; } } Each object that is an instance of class K contains a member function sum. Only one translation of sum is created; it is shared by all instances of K. When sum executes it needs two pointers to access local and object- level data. Local data, as usual, resides in a frame on the run- time stack. 381

Data values for a particular instance of K are accessed through an object pointer (called the this pointer in Java and C+ + ). When obj.sum() is called, it is given an extra implicit parameter that a pointer to obj. Space for a Object Obj Space for b Object Pointer Control Information Top of Stack Frame Pointer Rest of Stack When a+b is computed, b, a local variable, is accessed directly through the frame pointer. a, a member of object obj, is accessed indirectly through the object pointer that is stored in the frame (as all parameters to a method are). 382

C+ + and Java also allow inheritance via subclassing. A new class can extend an existing class, adding new fields and adding or redefining methods. A subclass D, of class C, maybe be used in contexts expecting an object of class C (e.g., in method calls). This is supported rather easily objects of class D always contain a class C object within them. If C has a field F within it, so does D. The fields D declares are merely appended at the end of the allocations for C. As a result, access to fields of C within a class D object works perfectly. 383