A LISP Interpreter in ML

Similar documents
Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Principles of Programming Languages 2017W, Functional Programming

Project 2: Scheme Interpreter

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

Functional Programming

Intro. Scheme Basics. scm> 5 5. scm>

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

Documentation for LISP in BASIC

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

CS 360 Programming Languages Interpreters

Functional Programming. Pure Functional Programming

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

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

Lecture 09: Data Abstraction ++ Parsing is the process of translating a sequence of characters (a string) into an abstract syntax tree.

C311 Lab #3 Representation Independence: Representation Independent Interpreters

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

SCHEME The Scheme Interpreter. 2 Primitives COMPUTER SCIENCE 61A. October 29th, 2012

CS 61A Discussion 8: Scheme. March 23, 2017

CS109A ML Notes for the Week of 1/16/96. Using ML. ML can be used as an interactive language. We. shall use a version running under UNIX, called

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

FP Foundations, Scheme

11/6/17. Functional programming. FP Foundations, Scheme (2) LISP Data Types. LISP Data Types. LISP Data Types. Scheme. LISP: John McCarthy 1958 MIT

CS 211 Programming Practicum Fall 2018

Comp 311: Sample Midterm Examination

CS 4240: Compilers and Interpreters Project Phase 1: Scanner and Parser Due Date: October 4 th 2015 (11:59 pm) (via T-square)

SCHEME AND CALCULATOR 5b

COP4020 Programming Assignment 1 - Spring 2011

6.001: Structure and Interpretation of Computer Programs

Lecture #24: Programming Languages and Programs

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

6.001 Notes: Section 15.1

UNIVERSITY OF CALIFORNIA Department of Electrical Engineering and Computer Sciences Computer Science Division. P. N. Hilfinger

Procedures. EOPL3: Section 3.3 PROC and App B: SLLGEN

Functional programming in LISP

CS 211 Programming Practicum Spring 2017

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

Streams, Delayed Evaluation and a Normal Order Interpreter. CS 550 Programming Languages Jeremy Johnson

Functional Programming. Big Picture. Design of Programming Languages

Introduction to Typed Racket. The plan: Racket Crash Course Typed Racket and PL Racket Differences with the text Some PL Racket Examples

Lisp. Versions of LISP

CS251 Programming Languages Handout # 47 Prof. Lyn Turbak May 22, 2005 Wellesley College. Scheme

Functional Programming. Pure Functional Languages

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

Functional Programming. Pure Functional Languages

Why do we need an interpreter? SICP Interpretation part 1. Role of each part of the interpreter. 1. Arithmetic calculator.

The PCAT Programming Language Reference Manual

User-defined Functions. Conditional Expressions in Scheme

Introduction to LISP. York University Department of Computer Science and Engineering. York University- CSE V.

1 Lexical Considerations

CS 231 Data Structures and Algorithms, Fall 2016

C: How to Program. Week /Mar/05

CMSC 330: Organization of Programming Languages

Introduction to Programming Using Java (98-388)

UMBC CMSC 331 Final Exam

Organization of Programming Languages CS3200/5200N. Lecture 11

More Scheme CS 331. Quiz. 4. What is the length of the list (()()()())? Which element does (car (cdr (x y z))) extract from the list?

A quick introduction to SML

61A LECTURE 18 SCHEME. Steven Tang and Eric Tzeng July 24, 2013

CS 211 Programming Practicum Spring 2018

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. More Common Lisp

Introduction to Functional Programming

Racket. CSE341: Programming Languages Lecture 14 Introduction to Racket. Getting started. Racket vs. Scheme. Example.

CS 415 Midterm Exam Spring 2002

Chapter 2 - Introduction to C Programming

15 Unification and Embedded Languages in Lisp

Lexical Considerations

A First Look at ML. Chapter Five Modern Programming Languages, 2nd ed. 1

Fifth Generation CS 4100 LISP. What do we need? Example LISP Program 11/13/13. Chapter 9: List Processing: LISP. Central Idea: Function Application

CSE 142 Su 04 Computer Programming 1 - Java. Objects

CS 275 Name Final Exam Solutions December 16, 2016

Overview of the Ruby Language. By Ron Haley

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

Common LISP Tutorial 1 (Basic)

Programs as data first-order functional language type checking

Symbolic Computation and Common Lisp

Midterm 2 Solutions Many acceptable answers; one was the following: (defparameter g1

A Small Interpreted Language

Scheme Quick Reference

Chapter 2 Using Data. Instructor s Manual Table of Contents. At a Glance. Overview. Objectives. Teaching Tips. Quick Quizzes. Class Discussion Topics

Fall Semester, The Metacircular Evaluator. Today we shift perspective from that of a user of computer langugaes to that of a designer of

Principles of Programming Languages

Language Reference Manual simplicity

Scheme as implemented by Racket

Imperative languages

CSSE 304 Assignment #13 (interpreter milestone #1) Updated for Fall, 2018

Lambda Calculus see notes on Lambda Calculus

Maciej Sobieraj. Lecture 1

Introduction to Scheme

Chapter 15. Functional Programming Languages

F28PL1 Programming Languages. Lecture 11: Standard ML 1

UNIVERSITY OF CALIFORNIA Department of Electrical Engineering and Computer Sciences Computer Science Division. P. N. Hilfinger

INF4820: Algorithms for Artificial Intelligence and Natural Language Processing. Common Lisp Fundamentals

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

Full file at

Chapter 1. Fundamentals of Higher Order Programming

Modern Programming Languages. Lecture LISP Programming Language An Introduction

Transcription:

UNIVERSITY OF OSLO Department of Informatics A LISP Interpreter in ML Mandatory Assignment 1 INF3110 September 21, 2009

Contents 1

1 Introduction The purpose of this assignment is to write an interpreter, in ML, for a subset of the LISP dialect Scheme. An interpreter is a program that executes instructions written in a programming language. Large parts of the interpreter are already completed in the pre-code, which is posted at the course homepage. LISP is chosen as the target language for four reasons: 1. Ease of scanning and parsing (not curriculum, completed in pre-code) 2. The dynamic nature of the language. 3. Its compactness and expressiveness. 4. Small core, most of LISP is written in LISP. 2 General Description of the Interpreter The interpreter accepts input, from keyboard or from a file. A part of the program called a lexer (given as pre-code) converts a stream of characters to a stream of tokens. Some of these tokens has meta-data. An ID token has a name as meta-data, while a LPAR (left-parenthesis) token has none. The parser will try to make sense of the stream of tokens delivered from the lexer and build a data structure, called a parse tree. For example, if a LPAR token (left-parenthesis) is read, the parser creates a List containing every structure until the enclosing RPAR token is read. The parse tree is constructed using different variants of the sexp datatype. The sexp data type represents both code and data internally in the interpreter. Most procedures accept and return values of this datatype. Remember that pattern matching in ML may be used to expose the encapsulating data and to act on the different sexp variants in a meaningful way. Here s the definition of the sexp datatype used in the pre-code. datatype sexp = Int of int Symbol of sexp Name of string List of sexp list Procedure of sexp WordHashTable. hash_ table list * sexp list * sexp list option Bool of bool VOID DOT ; 2

The environment is implemented as a list of S-expression Hash Tables, where each hash table corresponds to a given scope level. The base scope consists of all the primitives in the target language. The three procedures scopelookup, scopeadd and scopecreate are recommended for maintaining the environment. The hash table is a mutable data structure. Eval evaluates S-expressions in relation to an environment. A S-expression typically evaluates to another (simpler) S-expression, or to itself. A list S- expression is evaluated as a procedure call. This is a quite complex operation and should be performed with the help of the three procedures: procedurecall, primitive and bindparamstovalues. The Procedure constructor in the sexp datatype is defined as: Procedure of sexp WordHashTable. hash_ table list * sexp list * sexp list option This tells us that a procedure consists of an environment, a list of parameter names and an optional body of a list of S-expressions. If the body is NONE (the body is optional), then the procedure is a primitive and the implementation must be done in ML. Otherwise, the body is SOME S-expression that may be evaluated, together with an environment, as the procedure body. 3 What has to be Implemented The following procedures must be implemented: stringrep primitive procedurecall (done for primitives) bindparamstovalues 3.1 stringrep This procedure should accept any form of a S-expression and return a meaningful string representation. For example, the sexp List(Int 1, Int 2, Int 3) should have the string representation of (1 2 3). 3.2 primitive This procedure should have a match against every target procedure primitive. All supported primitives are listed in the variable named primitives (see precode). The arguments to the procedure are not evaluated before entry. This is vital for, among other, the if statement. The if-statement should only evaluate one of the two possible bodies, depending on the if-test result. The usage of each primitive in Scheme is described in section??. 3

3.3 procedurecall Normal procedures must get a local scope before their evaluation. It s also vital to make sure that the parameters are correctly initialized (see bindparamsto- Values). 3.4 bindparamstovalues Receives an environment, a list of sexp Names and a list of argument values. Performs the mapping between these lists. Make sure to support the sexp DOT notation used to express an unknown number of arguments that should be bundled together as a list. procedure that counts the number of arguments ( define ( param- count. l) ( length l)) ( param-count ) ; 0 ( param- count 3) ; 1 ( param- count 3 3 3) ; 3 4 A Crash Course in Scheme The target language is a subset of Scheme that supports integers, lists, symbols and closures. It s missing strings, floating point numbers, tail call optimization, mutable state and some other advanced features of the language. 4.1 Lists A list is something encapsulated by parentheses. This may be numbers, names (+, -, map, etc), symbols (something quoted), procedures, or other lists. (+ 1 2 3) a list 4.1.1 Procedure Calls When the interpreter evaluates lists, it treats them as procedure calls. The first element of the list is expected to be a procedure that operates on the rest of the elements. (+ 3 5 7) ; -> 15 Adds the numbers 3 5 7 4

4.1.2 Precedence There s no operator precedence rules, since the use of parenthesis removes any ambiguity. (* (+ 1 2) 3) No operator precedence 4.1.3 Quote A quote delays the evaluation of the following item. So, when something quoted is evaluated, it evaluates to itself. In particular, a delayed list will evaluate to a list. It s usual to refer to a delayed list as a list and a normal list as a procedure call. This is because of it s usage. When we write an interpreter, we need to focus on the correct definition. (+ 3 5 7) ; -> (+ 3 5 7) A list of four elements + ; -> + A symbol 4.2 Print Takes one argument and outputs it. ( print (1 2 3)) (1 2 3) print 4.3 Variable and Procedure Definitions Since procedures are first-class values, variables and procedures are defined in a similar manner. ( define a 3) ( define b (+ a 3)) ( define (c d e) (+ d e)) (c 3 2) ; -- > 5 two variables a procedure procedure call (c a b) ; -- > 9 procedure call with variable form earlier example 5

Procedures with an unknown number of arguments are defined using a dot notation. ( define ( sum. l) ( apply + l)) a procedure with an unknown number of arguments procedure call ( sum 1 2 3 4 5 6 7 8 9 10) ; -- > 55 4.4 Lambda Procedures The lambda primitive is used to create anonymous procedures. They may also be bound to a name using let or define. lambda compared to regular procedure definitions ( define a1 ( lambda (x y) (+ xy))) ; proc named a1 adds its two arguments ( define ( a2 x y) (+ xy)) ; proc named a2 adds its two arguments Lambda is often used when a small code snippet is needed. lambda usage ( map ( lambda (x) (+ x 1)) (1 2 3 4)) ; -> (2 3 4 5) 4.5 Let Let is used to create local variable bindings. ( define ( complexproc a b c) ( let ((i (* a b)) (k (* b c))) (+ i k))) let usage 4.6 List operations: cons, car and cdr The last element of every list is the empty list. () The empty list This is for all our purposes exactly the same as nil in ML and null in Java. 6

4.6.1 Cons Another way to create a list is to use the procedure cons. Cons takes an element and a list as arguments and creates a new list with the element argument in front of the the list argument. NB: our implementation allows a cons of two elements to become a new list of two elements. This makes the implementation a bit easier. This would become a pair of two elements in ordinary LISP. normal cons ( cons 1 (2 3)) ; -- > (1 2 3) normal canonical cons ( cons 1 ( cons 2 ())) ; -- > (1 2) ( cons 1 2) ; -- > (1 2) non canonical cons 4.6.2 Car Car returns the first element in a list ( car (1 2 3)) ; -- > 1 car of a list 4.6.3 Cdr Cdr returns a list without the first element. cdr of a list ( cdr (1 2 3)) ; -- > (2 3) 4.6.4 List procedure Takes an unknown number of arguments and constructs a list of them. the list procedure ( list 1 2 3); -> (1 2 3) ( list 1 (+ 2 3) 4) -> (1 5 4) 4.7 Arithmetic The interpreter only supports whole numbers at this point. 7

4.7.1 Addition (+ 1 2 3) ; -> 6 (+) ; -> 0 (+ 1) ; -> 1 some addition 4.7.2 Subtraction (- 10 2 3) ; -> 5 (- 1) ; -> ~1 (-) ; -> error some subtraction 4.8 Multiplication (* ) ; -> 1 (* 1 2 3) ; -> 6 usage of * 4.9 Remainder ( remainder 3 7) ; -> 3 ( remainder 13 7) ; -> 6 The leftover after an integer division 4.10 Quotient ( quotient 3 7) ; -> 0 ( quotient 13 7) ; -> 1 The result of an integer division 4.11 Comparisons 4.11.1 Null? Null? checks if a list is empty ( null? ()) ; -> true ( null? (1)) ; -> false null? tests 8

4.11.2 Pair? and List? These are identical in our implementation (pair? is a primitive and list? is implemented using pair? in the file stdlib.scm) pair? tests ( pair? (1)) ; -> true ( contains pair of 1 and () ) ( pair? ()) ; -> false ( pair? 1) ; -> false 4.11.3 Equal (= 1 2 3) ; false (= 1 1 1 (- 3 2)) ; true equality test 4.11.4 Greater Than (> 3 2 1) ; true (> 3 2 2) ; false (> 5 2) ; true greater than 4.11.5 Less Than (< 1 2 3) ; true (< 1 2 2) ; false (< 2 5) ; true less than 4.12 What s true? In LISP, it s more correct to ask what s false. False is false, everything else is true. 4.12.1 And Evaluates an unknown number of arguments and checks that none is false. Returns the last value if all true, else false. usage of and ( and ) ; -> true ( and (= 3 2) (= 2 2)) ; -> false ( and 1 2 3) ; 3 9

4.12.2 Or Evaluates an unknown number of arguments and checks if any of them is true. usage of or (or ) ; -> false (or (= 3 2) (= 2 2)) ; -> true (or 1 2 3) ; -> 1 Calling eval from lisp There s a ML procedure called eval that tries to evaluate every lisp data structure. This procedure is the heart of the interpreter and we re also able to call it directly from lisp. There s one subtle difference: call. (+ 1 2 3) ; -> (+ 1 2 3) ( eval (+ 1 2 3)) ; -> 6 the eval procedure is special The ability to dynamically create and evaluate data is a very useful feature of LISP. 5 Programming Tips ML has a strict type system and some quite obscure error messages. This page tries to explain the different messages [http://www.smlnj.org/doc/errors.html]. The SML/NJ compiler does not support a debugger, or even a stack trace (backtrace). It s therefore very useful to develop each procedure locally and test them using constructed arguments. The ptest() procedure will return a parsed result of its input, which might come in handy. Emacs has a nice SML-mode that makes developing a bit easier. http://www.smlnj.org/doc/emacs/sml-mode.html Send a buffer to the compiler using C-c C-b and jump to the nearest error using C-x. There are a couple of books about Standard ML at the library, the website [http://www.smlnj.org/] contains some documentation and tutorials. If you re unsure about how your interpreter should respond in a given situation, try a real Scheme interpreter. DrScheme should be installed on all Windows and Linux machines at IFI. Some free books on Scheme: http://www-mitpress.mit.edu/sicp/full-text/book/book.html http://t3x.org/sketchy/vol1/index.html http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme.html 5.1 Final Test As a final test of the interpreter, try to uncomment the line loading the file interpreter-tests.scm. This will make the interpreter run a few test programs at startup. Passing these tests is a good indication of a working interpreter. 10