LPAREN (a left parenthesis),
RPAREN (a right parenthesis), and IDENTIFIER
(a sequence of letters):
exp ::= cast | call | LPAREN exp RPAREN | IDENTIFIER cast ::= LPAREN type RPAREN exp call ::= function LPAREN argument RPAREN function ::= exp argument ::= exp type ::= IDENTIFIER
Prove the syntactic ambiguity of the this grammar by finding a string that has more than one parse tree. Draw the parse trees.
(x)(y) .
It can be parsed as:
y to type
x, or
x with argument
y
datatype shape =
Rect
| Square
| Circle
| Intersect of (shape * shape)
A shape is either a rectangle, a square, a circle, or
created by intersecting two other shapes. For example, one can declare
the following four shapes:
val s1 = Rect val s2 = Circle val s3 = Intersect(s1,s2) val s4 = Intersect(s2,s3)Write an ML function
countC that counts the number of
circles used in creating a shape:
- countC(s1); val it = 0 : int - countC(s2); val it = 1 : int - countC(s3); val it = 1 : int - countC(s4); val it = 2 : int
fun countC Rect = 0 | countC Square = 0 | countC Circle = 1 | countC (Intersect(s1,s2)) = countC(s1) + countC(s2)
C library assert.h can be used to check
invariants at run-time. Here is an example program:
#include "assert.h"
main () {
int x = 3;
int y = 5;
assert (x > 0 && y < 10);
x = x+y;
assert (x < 0);
}
When compiled and executed, this program prints:
Assertion failed: x < 0, file testassert.c, line 8 Abortwhich indicates that the first assertion succeeded and that the second assertion failed.
A programmer developing a new fast multiplication algorithm carefully intrumented the code with assertions that would guarantee the correctness of the code:
int fastmul (int a0, int b0) {
int result = 0;
int a = a0;
int b = b0;
assert(result == a0*b0 - a*b);
while (a >= 1) {
assert(result == a0*b0 - a*b);
if (a % 2 == 0) {
result = 2 * result;
a = a / 2;
}
else {
result = result + b;
a = a - 1;
}
}
assert(result == a0*b0 - a*b && a == 0);
return result;
}
Answer the following questions.
x and y such that all
assertions succeed when executing the call fastmul(x,y).
Solution x = 0, y = 7
m and n such
that at least one assertion fails when executing the call
fastmul(m,n).
Solution x = 5, y = 7
Solution
int fastmul (int a0, int b0) {
int result = 0;
int a = a0;
int b = b0;
assert(result == a0*b0 - a*b);
while (a >= 1) {
assert(result == a0*b0 - a*b);
if (a % 2 == 0) {
b = b * 2; /** CHANGED THIS LINE **/
a = a / 2;
}
else {
result = result + b;
a = a - 1;
}
}
assert(result == a0*b0 - a*b && a == 0);
return result;
}
datatype BOp = PLUS | DIV | EQ
datatype Expression =
Number of int
| True | False
| Binary of Expression * BOp * Expression
datatype ExpType = Integer | Boolean
exception TypeError
fun typecheck (Number(i)) = Integer
| typecheck (True) = Boolean
| typecheck (False) = Boolean
| typecheck (Binary(e1,bop,e2)) =
let val t1 = typecheck(e1)
val t2 = typecheck(e2)
in case (t1,bop,t2) of
(Integer,PLUS,Integer) => Integer
| (Integer,DIV,Integer) => Integer
| (_,EQ,_) => if t1=t2 then Boolean else raise TypeError
| _ => raise TypeError
end
Answer the following questions:
Solution Binary(Number(1),PLUS,True)
Solution Binary(Number(1),DIV,Number(0))
datatype declaration of Expression by adding the
following two lines:
| Define of string * Expression * Expression | Variable of stringThe intention is that a
Define gives a name to a subexpression
that can be reused later, for example,
Define("x", Number(3), Binary(Variable "x", PLUS, Variable "x"))
Extend the typechecker to handle the additional two cases. Write the
complete code for
datatype Expression =
Number of int
| True | False
| Binary of Expression * BOp * Expression
| Define of string * Expression * Expression
| Variable of string
fun lookup ([],_) = raise TypeError
| lookup ((s,t)::env, key) = if s=key then t else lookup(env,key)
fun typecheck (Number(i),_) = Integer
| typecheck (True,_) = Boolean
| typecheck (False,_) = Boolean
| typecheck (Binary(e1,bop,e2),env) =
let val t1 = typecheck(e1,env)
val t2 = typecheck(e2,env)
in case (t1,bop,t2) of
(Integer,PLUS,Integer) => Integer
| (Integer,DIV,Integer) => Integer
| (t1,EQ,t2) => if t1=t2 then Boolean else raise TypeError
| _ => raise TypeError
end
| typecheck (Define(s,e1,e2),env) =
let val t1 = typecheck (e1,env)
in typecheck (e2,((s,t1)::env))
end
| typecheck (Variable(s),env) = lookup(env,s)
#includeLooking at the macro#define count(N) { int i; for(i=1; i<=N; i++) { printf("%d\n", i); } } void main () { int i; for(i=0; i < 3; i++) { count(i); } }
count(N), it appears that this macro
prints all the numbers from 1 to N inclusive. The main program calls
this macro three times as shown. What does the program print?
Solution Infinite loop printing
1 2 3 4 5 ...
If we were to change the definition of count from a macro to
the following function, what would the program print?
void count(int N) {
int i;
for(i=1; i<=N; i++) {
printf("%d\n", i);
}
}
Solution
1 1 2
println statement produce?
class A {
int x = 3;
int f (int x) { return x+x; }
}
class B {
int x = 4;
int f (C c) {
c.x = 100;
c = new C();
return x;
}
}
class C {
int x = 5;
}
class Main {
public static void main (String[] args) {
int x = 6;
A a = new A();
B b = new B();
C c = new C();
System.out.println(a.f(x)); // ..............................
System.out.println(b.f(c)); // ..............................
System.out.println(c.x); // ..............................
}
}
12 4 100
sabry@cs.uoregon.edu