






Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Material Type: Exam; Class: Progrmg Languages & Compilers; Subject: Computer Science; University: University of Illinois - Urbana-Champaign; Term: Unknown 1989;
Typology: Exams
1 / 12
This page cannot be seen from the preview
Don't miss anything!







(a) let alwaysfour x = 4
val alwaysfour : 'a -> int
(b) let add x y = x + y
val add : int -> int -> int
(c) let concat x y = x ^ y
val concat : string -> string -> string
(d) let addmult x y = (x + y, x * y)
val addmult : int -> int -> int * int
(e) let rec f x = if x=[] then [] else hd x @ f (tl x)
val f : 'a list list -> 'a list
(f) let rec copy x = if x=[] then [] else hd x :: copy (tl x)
val copy : 'a list -> 'a list
Define the mutually recursive functions preorder : ‘a tree -> ‘a list and preorder_list : (‘a tree) list -> ‘a list such that preorder t gives the pre- order traversal of t, and preorder_list appends the pre-order traversals of its component trees together. Your functions should be mutually recursive. You may use @ or append.
E.g. preorder t1 = [1;2;3;4;5;6;7]
let rec preorder (Node(x, ts)) = x::preorder_list ts
and preorder_list lst = match lst with [] -> [] | t::ts -> preorder t @ preorder_list ts
type token = PLUS | MINUS | INT of int
where these represent, respectively, the sequences “+”, “-“, and any string of one or more characters '0' - '9'. (You will want to use the function int_of_string: string → int.)
rule tokenize = parse ‘+’ { PLUS } | ‘-‘ { MINUS } | [‘0’-‘9’]+ as i { INT (int_of_string i) }
E → E. id |! E | E [ E ] | id
a) Give a sentence that has two distinct parse trees. Show the parse trees.
! a. b (or !a[b], as well as others)
b) Explain how you might disambiguate the grammar using ocamlyacc precedence and associativity declarations. You are free to choose the precedence order and associativity of operators, but you must say what declarations you would use and what effect they would have. Assume the following declaration:
%token DOT IDENT BANG LBRACK RBRACK
%left DOT %nonassoc BANG %nonassoc LBRACK
These declarations give precedence to BANG over DOT, so the above sentence would be parsed as the tree on the right. It also gives precedence to LBRACK, which has an ambiguity as noted above.
Expression → "do" Stmt "while" "(" Expression ")" | Stmt ";" Expression | Ident
Assume the token type is
type token = DO | WHILE | LPAREN | RPAREN | SCOLON | IDENT of string
the abstract syntax for the Expression non-terminal is
type exp = DoWhile of stmt * exp | Sequence of stmt * exp | Id of string
and you are provided with the parseStmt function of the following type.
parseStmt: token list -> stmt * token list
Implement the parseExp: token list -> exp * token list function. Ignore error cases. Also, assume that DO and IDENT are not in FIRST(Stmt).
let rec parseExp toks = match toks with DO::rest -> ( match parseStmt rest with (st, WHILE::LPAREN::rest2) -> match parseExp rest2 with (e, RPAREN::etc) -> (DoWhile(st, e), etc) ) | IDENT s::rest -> (Id s, rest) | _ -> ( match parseStmt toks with (st, SCOLON::rest) -> match parseExp rest with (e, etc) -> (Sequence(st, e), etc) )
(where NEG, ZERO, and POS are new keywords). It would execute S0, S1, or S2, depending upon the value of e, and then jump to the end of the CIF statement (like a regular IF). Furthermore, any of the three statements can contain a break statement, which exits from the CIF statement. Give a compilation scheme for CIF. [CIF (e) { NEG S0 ZERO S1 POS S2 }] =
let (I, t) = [e] L0, L1, L2, L3, L4 = fresh labels in I t1 = t < 0 CJUMP t1, L0, L L0: [S0] (^) L JUMP L L1: t1 = t == 0 CJUMP t1, L2, L L2: [S1] (^) L JUMP L L3: [S2] (^) L L4:
while (cond) { … break; … }
and
while (cond) { … continue;
is equivalent to
L: while (cond) { … break L; … }
is equivalent to
while (cond) { L: { … break L; … } }
… } To generate code for such a language, you need to handle two new kinds of statements, labeled statements and break-to-label. For various reasons, we cannot assume that the labels that appear in source programs are the same as the labels in IR code, so we still have to generate new labels when generating code. Define a scheme
[ S ]T = instruction list
where T is a table mapping source-level labels to IR labels. You can use the following operations: add: table -> source-label -> IR-label -> table get: table -> source-label -> IR-label genlabel: unit -> IR-label.
Define [L: S] (^) T and [break L] (^) T
[L: S] (^) T = let L0 = genlabel() in let newT = add T L L in [S]newT L0:
[break L] (^) T = let L0 = get T L in JUMP L