CSE au Final Exam Sample Solution

Similar documents
CSE 413 Final Exam. December 13, 2012

CSE 413 Final Exam Spring 2011 Sample Solution. Strings of alternating 0 s and 1 s that begin and end with the same character, either 0 or 1.

CSE 413 Final Exam. June 7, 2011

CSE 401 Midterm Exam 11/5/10

CSE 401 Midterm Exam Sample Solution 2/11/15

CSE 401 Midterm Exam Sample Solution 11/4/11

This book is licensed under a Creative Commons Attribution 3.0 License

A Simple Syntax-Directed Translator

Examples of attributes: values of evaluated subtrees, type information, source file coordinates,

Where We Are. CMSC 330: Organization of Programming Languages. This Lecture. Programming Languages. Motivation for Grammars

CSE P 501 Exam 11/17/05 Sample Solution

1 Lexical Considerations

2.2 Syntax Definition

Principles of Programming Languages COMP251: Syntax and Grammars

IPCoreL. Phillip Duane Douglas, Jr. 11/3/2010

CSE 401/M501 18au Midterm Exam 11/2/18. Name ID #

Part 5 Program Analysis Principles and Techniques

CSE 582 Autumn 2002 Exam 11/26/02

CSE P 501 Exam 12/1/11

Lexical analysis. Syntactical analysis. Semantical analysis. Intermediate code generation. Optimization. Code generation. Target specific optimization

CSE P 501 Exam Sample Solution 12/1/11

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages

CMSC 330: Organization of Programming Languages. Architecture of Compilers, Interpreters

MIDTERM EXAMINATION - CS130 - Spring 2003

Architecture of Compilers, Interpreters. CMSC 330: Organization of Programming Languages. Front End Scanner and Parser. Implementing the Front End

G Programming Languages - Fall 2012

Compiler Construction

LESSON 1. A C program is constructed as a sequence of characters. Among the characters that can be used in a program are:

CMSC 330: Organization of Programming Languages. Context Free Grammars

Chapter 3: Describing Syntax and Semantics. Introduction Formal methods of describing syntax (BNF)

Structure of a compiler. More detailed overview of compiler front end. Today we ll take a quick look at typical parts of a compiler.

CSE 401 Final Exam. March 14, 2017 Happy π Day! (3/14) This exam is closed book, closed notes, closed electronics, closed neighbors, open mind,...

More Assigned Reading and Exercises on Syntax (for Exam 2)

CS164: Midterm I. Fall 2003

CSE 3302 Programming Languages Lecture 2: Syntax

9/21/17. Outline. Expression Evaluation and Control Flow. Arithmetic Expressions. Operators. Operators. Notation & Placement

EECS 6083 Intro to Parsing Context Free Grammars

Lexical Considerations

Compiler Design Concepts. Syntax Analysis

Stating the obvious, people and computers do not speak the same language.

Compiler Construction

SMURF Language Reference Manual Serial MUsic Represented as Functions

Syntactic Analysis. The Big Picture Again. Grammar. ICS312 Machine-Level and Systems Programming

Optimizing Finite Automata

Introduction to Lexical Analysis

Parsing. Note by Baris Aktemur: Our slides are adapted from Cooper and Torczon s slides that they prepared for COMP 412 at Rice.

Briefly describe the purpose of the lexical and syntax analysis phases in a compiler.

The SPL Programming Language Reference Manual

DEMO A Language for Practice Implementation Comp 506, Spring 2018

CS412/413. Introduction to Compilers Tim Teitelbaum. Lecture 2: Lexical Analysis 23 Jan 08

A simple syntax-directed

Syntactic Analysis. CS345H: Programming Languages. Lecture 3: Lexical Analysis. Outline. Lexical Analysis. What is a Token? Tokens

Chapter 6 Control Flow. June 9, 2015

CMSC 330: Organization of Programming Languages

A programming language requires two major definitions A simple one pass compiler

EDAN65: Compilers, Lecture 04 Grammar transformations: Eliminating ambiguities, adapting to LL parsing. Görel Hedin Revised:

CMSC 330: Organization of Programming Languages. Context Free Grammars

Lexical Analysis. Lecture 3-4

The PCAT Programming Language Reference Manual

Assignment 5. Introduction

Typescript on LLVM Language Reference Manual

ADTS, GRAMMARS, PARSING, TREE TRAVERSALS. Regrades 10/6/15. Prelim 1. Prelim 1. Expression trees. Pointers to material

ITEC2620 Introduction to Data Structures

Defining Program Syntax. Chapter Two Modern Programming Languages, 2nd ed. 1

CPS 506 Comparative Programming Languages. Syntax Specification

Lexical Analysis. Chapter 2

B The SLLGEN Parsing System

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

Programming Languages Third Edition. Chapter 9 Control I Expressions and Statements

Chapter 3: CONTEXT-FREE GRAMMARS AND PARSING Part 1

Introduction to Parsing. Lecture 5

Postfix Notation is a notation in which the operator follows its operands in the expression (e.g ).

19 Much that I bound, I could not free; Much that I freed returned to me. Lee Wilson Dodd

UMBC CMSC 331 Final Exam

LECTURE 17. Expressions and Assignment

An introduction introduction to functional functional programming programming using usin Haskell

CSE 401 Final Exam. December 16, 2010

Iteration. Side effects

Lecture 4: Stack Applications CS2504/CS4092 Algorithms and Linear Data Structures. Parentheses and Mathematical Expressions

Group A Assignment 3(2)

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

Jim Lambers ENERGY 211 / CME 211 Autumn Quarter Programming Project 4

Introduction to Lexical Analysis

CSE 214 Computer Science II Stack

CS415 Compilers. Syntax Analysis. These slides are based on slides copyrighted by Keith Cooper, Ken Kennedy & Linda Torczon at Rice University

Special Section: Building Your Own Compiler

Lecture Chapter 6 Recursion as a Problem Solving Technique

CSE P 501 Exam 8/5/04

Related Course Objec6ves

Left to right design 1

ADTS, GRAMMARS, PARSING, TREE TRAVERSALS

3.5 Practical Issues PRACTICAL ISSUES Error Recovery

Lexical Considerations

Chapter 3. Describing Syntax and Semantics

Formal Languages and Automata Theory, SS Project (due Week 14)

CSE 582 Autumn 2002 Exam Sample Solution

Properties of Regular Expressions and Finite Automata

In this chapter you ll learn:

Programming for Engineers Iteration

Transcription:

CSE 413 12au Final Exam Sample Solution Question 1. (10 points) Regular expressions I. Describe the set of strings generated by each of the following regular expressions. For full credit, give a description of the sets like all sets of strings made up of a s, b s, and c s with 4 a s and at least as many b s as a s. Don t just transcribe the expressions from regular expression notation into English. (a) (ab)*(bc)* 0 or more ab strings followed by 0 or more bc strings. (b) ((a b)+ c)* Empty string or strings of a s, b s, and c s where there is at least one a or b preceding every c, and ing with a c. Question 2. (12 points) Regular expressions II. Write a regular expression or set of regular expressions that generate the following sets of strings. Fine print: You may use basic regular expressions (sequences rs, choice r s, and repetition r* and parentheses for subexpressions). You may also use + (one or more) and? (zero or one), and character classes like [ax-z] and [^abc], but you may not use additional regular expression operators that might be found in various programming languages and software tools. You also may use named abbreviations like vowels = [aeiou] if these help. (a) All non-empty strings of 0 s and 1 s such that the number of 1 s is even if there are any 1 s in the string. (There are no other restrictions on the positions of the 1 s in the string other than the total number of 1 s needs to be even.). Many possibilities, of course. One is: 0+ (0*10*10*)+ (b) Ruby identifiers. A Ruby identifier is a sequence of letters, digits, and underscores. An ordinary identifier may not begin with a digit. Identifiers may be preceded by $, @, or @@ to indicate global, instance, or class variables. The character following $, @, or @@ may not be a digit. An identifier may also with one of the characters?,!, or =. ($ @?@)? [a-za-z_][a-za-z0-9_]* (?! =)? CSE 413 Final Exam, December 13, 2012 Sample Solution Page 1 of 9

Question 3. (6 points) The C family of languages (including Java) has prefix and binary + and - operators, as well as increment and decrement operators ++ and -- that can appear either before or after an expression or sub-expression. The languages also include the other usual kinds of tokens, including identifiers, reserved words, and numbers. How would a scanner for a language like Java divide the following input into tokens? Draw a box around each set of characters that make up a token. You should assume that these characters are adjacent to each other. We have added some space to make it easier to draw boxes, and the first box is drawn for you. (Remember that we re only asking about how the scanner would divide this sequence of characters into tokens, not whether they make any sense as part of a C or Java program.) 1 2 + a + + + = = 4 2 t h i n g s 17-1 + f i f ; Question 4. (8 points) Give a context-free grammar that generates all strings of a s and b s that are not empty and are palindromes that is, the string reads the same backwards as forwards. A few strings in this set are a, b, aa, bb, aaa, bbb, aba, bab, aaaa, abba, etc. S ::= a b aa bb a S a b S b (The most common errors on this question were grammars that generated only strings with an even or odd number of characters, or that could generate an empty string.) CSE 413 Final Exam, December 13, 2012 Sample Solution Page 2 of 9

Question 5. (12 points) Consider the following grammar expr ::= a a subs subs ::= [ expr ] [ expr ] subs (a) (4 points) What are the terminals and non-terminals of this grammar? Non-terminals: expr subs Terminals: a [ ] (b) (5 points) Draw the parse tree for a[a][a] expr subs expr subs expr a [ a ] [ a ] (c) (3 points) Describe in English the set of strings generated by this grammar. In programming language terms, the identifier a followed by 0 or more subscript expressions in brackets, each of which is a nested instance of the same kind of expression. CSE 413 Final Exam, December 13, 2012 Sample Solution Page 3 of 9

Question 6. (10 points) In most of the languages desced from C, the syntax for function calls uses parentheses around the argument list, while array subscripts are indicated with brackets around each individual subscript. In some other languages like Fortran parentheses are used for both function calls and array subscripts, and subscripts for multiple-dimension arrays are given in a single list of expressions inside a single pair of parentheses. For instance, the C statement ans=b[i][j]*sin(theta) would be written as ans=b(i,j)*sin(theta) in Fortran. Here is part of an expression grammar for Fortran that includes function calls and array references: exp ::= term exp + term exp - term term ::= factor term * factor term / factor factor ::= id number ( exp ) funcall arrayref funcall ::= id ( explist ) id ( ) arrayref ::= id ( explist ) explist ::= exp explist, exp (a) (7 points) Show that this grammar is ambiguous. This can be done with either parse trees or derivations. The key is to show that the string id(id) has more than one possible derivation because of the syntactic overlap between funcall and arrayref. Here are two possible derivations (trees are left as an exercise for those not trying to type the answer): exp => term => factor => funcall => id (explist) => id(exp) => id(term) => id(factor) => id(id) exp => term => factor => arrayref => id (explist) => id(exp) => id(term) => id(factor) => id(id) (b) (3 points) A compiler for Fortran has to be able to analyze and understand programs in spite of this ambiguity. Suggest one way that this might be done (and the solution might involve other parts of the compiler, not just the parser). There are a couple of reasonable solutions, both of which involve using type information to resolve the ambiguity. - While parsing, if type information is available it can be used to decide if id( is the beginning of a function call or array reference by looking up the type of id. - We can rewrite the grammar to combine arrayref and funcall into a single non-terminal that generates id(explist), and let later parts of the compiler sort out the details once type information is available. CSE 413 Final Exam, December 13, 2012 Sample Solution Page 4 of 9

Question 7. (14 points) The local library would like your help to write a Ruby program to print information about overdue books. The input to the program is a simple text file. The first line is the current date in the format yyyymmdd, where yyyy is the year, mm is the month, and dd is the date. For example, today s date, Dec. 13, 2012, would be written 20121213. The rest of the file contains information about checked-out books. There are three lines in the file for each book giving the book title, the borrower s name, and the due date. Here s an example with three books, two of which are overdue (due before the date given at the beginning of the input): 20121213 50 Shades of Ruby A. Turing 19361112 Naughty and Nice S. Clause 20121225 Bored of the Rings P. Jackson 20121128 Write a Ruby program that reads data from standard input in this format and prints the following: For each overdue book, print the due date, borrower s name, and book title on a single line, in that order with a comma between the name and title. After reading all of the input, print a list of names of the borrowers who have one or more overdue books. The list may be in any order. The name of each borrower in the list should be printed only once even if they have several overdue books, and each name should be on a separate line. Here is the output for the above sample input (the order of the last two lines could also be reversed): 19361112 A. Turing, 50 Shades of Ruby 20121128 P. Jackson, Bored of the Rings A. Turing P. Jackson For full credit you should use Ruby iterators like each to process the contents of any containers like arrays or hashes. Recall that if h is a hash, you can iterate through its key/value pairs with h.each { key, value... } Hint: The date format was chosen so that dates could be compared as strings without having to convert them to numbers. But you do not have to do it that way if you don t want. Write your code on the next page. If you find it helpful, you can remove this page from the exam for reference while you are working. CSE 413 Final Exam, December 13, 2012 Sample Solution Page 5 of 9

Question 7. (cont.) Write your code here: Here is one straightforward solution: date = gets.chomp names = { } while title = gets.chomp borrower = gets.chomp duedate = gets.chomp if duedate < date puts duedate + " " + borrower + ", " + title names[borrower] = true names.each { who, ignore puts who } CSE 413 Final Exam, December 13, 2012 Sample Solution Page 6 of 9

Question 8. (18 points) The programming languages we ve seen this quarter write arithmetic expressions in two quite different ways. Racket uses prefix notation, where each operator appears first followed by its operands. Ruby uses the more traditional infix notation, where binary operators are written between their operands. For example, the infix expression (2+3)*(9-6) is written in prefix notation as (* (+ 2 3) (- 9 6)). There is another notation for arithmetic expressions called postfix notation, where each operator follows its operands, i.e., the infix expression exp1 op exp2 is written in postfix as exp1 exp2 op. For example, the above expression would be written in postfix as 2 3 + 9 6 - *. Interestingly enough, postfix expressions do not require parentheses to indicate either associativity or precedence. Expressions are evaluated from left to right, and when an operator (+, *, etc.) is encountered, the two operands immediately to its left are combined using the operator, and the result replaces all three. For this problem write a Ruby parser to translate an infix expression to postfix. The parser should read input tokens from a scanner, as in our project, and print the postfix version of the expression it should not evaluate it. Here is the input expression grammar. exp ::= term exp + term exp - term term ::= factor term * factor term / factor factor ::= id number ( exp ) Here are some more examples of infix to postfix translations. (Remember that the rule is that exp1 op exp2 is translated to exp1 exp2 op, even when exp1 or exp2 are themselves complex expressions.) Infix Postfix Comment 2+3+4 2 3 + 4 + Same as (2+3)+4 2+(3+4) 2 3 4 + + (a+b)*c a b + c * a*(b+c) a b c + * (5-y)*(x+3) 5 y - x 3 + * You should assume the following as you write your solution: There is a method next_token that returns a new Token object with the next input token each time it is called. There is a global variable current_token that contains the first Token in the expression when your parser procedure for exp is first called. If t is a Token object, t.kind returns the token kind, which is either ID, Number, or one of the terminal symbols "+", "-", "*", "/", "(", or ")". If t.kind returns ID or Number, then t.value returns the actual identifier or number. There are no -of-file or -of-line tokens. The parser should stop once it has processed a complete expression (i.e., printed the postfix version of a single expression). Hint: All that is required is to print out the tokens in the correct final order. Write your answer on the next page(s). You may detach this page for reference if you wish. CSE 413 Final Exam, December 13, 2012 Sample Solution Page 7 of 9

Question 8. (cont.) Write your Ruby code for the infix-to-postfix parser/translator here. # invariant: @current_token is the first token of the construct to be # processed when each method is called # print expr ::= term expr+term expr-term in postfix def expr term while @current_token.kind == "+" or @current_token.kind == "-" op = @current_token.kind @current_token = @scan.next_token term print op, " " # print term ::= factor term * factor term / factor in postfix def term factor while @current_token.kind == "*" or @current_token.kind == "/" op = @current_token.kind @current_token = @scan.next_token factor print op, " " # print factor ::= id number ( expr ) in postfix def factor if @current_token.kind == "ID" or @current_token.kind == "Number" print @current_token.value, " " @current_token = @scan.next_token else # assume @current_token.kind == "(" if not id or number @current_token = @scan.next_token # skip "(" expr @current_token = @scan.next_token # skip ")" Notes: Since the problem did not give complete details about how method next_token and variable current_token were declared, we were not strict about whether those were treated as instance variables, or whether next_token was an explicit member function of some object. What mattered was whether the intent was clear. Similarly, we also ignored most details of whitespace and newlines in output while grading. The important thing was whether the code printed the correct tokens in the correct order. CSE 413 Final Exam, December 13, 2012 Sample Solution Page 8 of 9

A couple of short questions to wrap up. Please keep your answers brief and to the point (and legible!!). Your readers thank you. Question 9. (6 points) Java has interfaces as well as classes, and a class can implement multiple interfaces. Neither Ruby nor C++ have interfaces, but for quite different reasons. (a) Why are there no Java-style interfaces in Ruby? Give a technical reason why interfaces would not be appropriate and/or needed in this language. Java interfaces only define types that are used during static type checking. Since Ruby uses dynamic typing, it doesn t make sense to specify static types for classes or the methods and constants in them. (b) Why are there no Java-style interfaces in C++? Again, give a technical reason why interfaces would not be appropriate and/or needed in this language. They would be redundant. C++ (as well as Java) allows the programmer to declare completely abstract classes with no method implementations. Since C++ supports multiple inheritance, a class can ext one or more fully abstract classes to create a class that implements multiple types, which provides the same capabilities as using interfaces in Java. Question 10. (4 points) One of the classic strategies for automatic memory management is reference counting. Yet reference counting is not used as the normal strategy for reclaiming memory in languages like Java, Ruby, and Racket, all of which use automatic garbage collectors. What is the main technical reason that reference counting cannot be used if we want to reclaim all unused memory? The primary technical limitation is that pure reference counting cannot reclaim circular data structures. If a data structure contains cycles, all of the nodes in the cycle will have non-zero reference counts even if there are no other outside references to the data. Reference counting will not discover that the data is unused and could be reclaimed because of the non-zero reference counts. Best wishes for the holidays and the New Year!! CSE 413 Final Exam, December 13, 2012 Sample Solution Page 9 of 9