431 lines
10 KiB
Common Lisp
431 lines
10 KiB
Common Lisp
(*
|
|
* A contribution from Anne Sheets (sheets@cory)
|
|
*
|
|
* Tests the arithmetic operations and various other things
|
|
*)
|
|
|
|
class A {
|
|
|
|
var : Int <- 0;
|
|
|
|
value() : Int { var };
|
|
|
|
set_var(num : Int) : SELF_TYPE {
|
|
{
|
|
var <- num;
|
|
self;
|
|
}
|
|
};
|
|
|
|
method1(num : Int) : SELF_TYPE { -- same
|
|
self
|
|
};
|
|
|
|
method2(num1 : Int, num2 : Int) : B { -- plus
|
|
(let x : Int in
|
|
{
|
|
x <- num1 + num2;
|
|
(new B).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
method3(num : Int) : C { -- negate
|
|
(let x : Int in
|
|
{
|
|
x <- ~num;
|
|
(new C).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
method4(num1 : Int, num2 : Int) : D { -- diff
|
|
if num2 < num1 then
|
|
(let x : Int in
|
|
{
|
|
x <- num1 - num2;
|
|
(new D).set_var(x);
|
|
}
|
|
)
|
|
else
|
|
(let x : Int in
|
|
{
|
|
x <- num2 - num1;
|
|
(new D).set_var(x);
|
|
}
|
|
)
|
|
fi
|
|
};
|
|
|
|
method5(num : Int) : E { -- factorial
|
|
(let x : Int <- 1 in
|
|
{
|
|
(let y : Int <- 1 in
|
|
while y <= num loop
|
|
{
|
|
x <- x * y;
|
|
y <- y + 1;
|
|
}
|
|
pool
|
|
);
|
|
(new E).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
};
|
|
|
|
class B inherits A { -- B is a number squared
|
|
|
|
method5(num : Int) : E { -- square
|
|
(let x : Int in
|
|
{
|
|
x <- num * num;
|
|
(new E).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
};
|
|
|
|
class C inherits B {
|
|
|
|
method6(num : Int) : A { -- negate
|
|
(let x : Int in
|
|
{
|
|
x <- ~num;
|
|
(new A).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
method5(num : Int) : E { -- cube
|
|
(let x : Int in
|
|
{
|
|
x <- num * num * num;
|
|
(new E).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
};
|
|
|
|
class D inherits B {
|
|
|
|
method7(num : Int) : Bool { -- divisible by 3
|
|
(let x : Int <- num in
|
|
if x < 0 then method7(~x) else
|
|
if 0 = x then true else
|
|
if 1 = x then false else
|
|
if 2 = x then false else
|
|
method7(x - 3)
|
|
fi fi fi fi
|
|
)
|
|
};
|
|
|
|
};
|
|
|
|
class E inherits D {
|
|
|
|
method6(num : Int) : A { -- division
|
|
(let x : Int in
|
|
{
|
|
x <- num / 8;
|
|
(new A).set_var(x);
|
|
}
|
|
)
|
|
};
|
|
|
|
};
|
|
|
|
(* The following code is from atoi.cl in ~cs164/examples *)
|
|
|
|
(*
|
|
The class A2I provides integer-to-string and string-to-integer
|
|
conversion routines. To use these routines, either inherit them
|
|
in the class where needed, have a dummy variable bound to
|
|
something of type A2I, or simpl write (new A2I).method(argument).
|
|
*)
|
|
|
|
|
|
(*
|
|
c2i Converts a 1-character string to an integer. Aborts
|
|
if the string is not "0" through "9"
|
|
*)
|
|
class A2I {
|
|
|
|
c2i(char : String) : Int {
|
|
if char = "0" then 0 else
|
|
if char = "1" then 1 else
|
|
if char = "2" then 2 else
|
|
if char = "3" then 3 else
|
|
if char = "4" then 4 else
|
|
if char = "5" then 5 else
|
|
if char = "6" then 6 else
|
|
if char = "7" then 7 else
|
|
if char = "8" then 8 else
|
|
if char = "9" then 9 else
|
|
{ abort(); 0; } (* the 0 is needed to satisfy the
|
|
typchecker *)
|
|
fi fi fi fi fi fi fi fi fi fi
|
|
};
|
|
|
|
(*
|
|
i2c is the inverse of c2i.
|
|
*)
|
|
i2c(i : Int) : String {
|
|
if i = 0 then "0" else
|
|
if i = 1 then "1" else
|
|
if i = 2 then "2" else
|
|
if i = 3 then "3" else
|
|
if i = 4 then "4" else
|
|
if i = 5 then "5" else
|
|
if i = 6 then "6" else
|
|
if i = 7 then "7" else
|
|
if i = 8 then "8" else
|
|
if i = 9 then "9" else
|
|
{ abort(); ""; } -- the "" is needed to satisfy the typchecker
|
|
fi fi fi fi fi fi fi fi fi fi
|
|
};
|
|
|
|
(*
|
|
a2i converts an ASCII string into an integer. The empty string
|
|
is converted to 0. Signed and unsigned strings are handled. The
|
|
method aborts if the string does not represent an integer. Very
|
|
long strings of digits produce strange answers because of arithmetic
|
|
overflow.
|
|
|
|
*)
|
|
a2i(s : String) : Int {
|
|
if s.length() = 0 then 0 else
|
|
if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else
|
|
if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else
|
|
a2i_aux(s)
|
|
fi fi fi
|
|
};
|
|
|
|
(* a2i_aux converts the usigned portion of the string. As a
|
|
programming example, this method is written iteratively. *)
|
|
|
|
|
|
a2i_aux(s : String) : Int {
|
|
(let int : Int <- 0 in
|
|
{
|
|
(let j : Int <- s.length() in
|
|
(let i : Int <- 0 in
|
|
while i < j loop
|
|
{
|
|
int <- int * 10 + c2i(s.substr(i,1));
|
|
i <- i + 1;
|
|
}
|
|
pool
|
|
)
|
|
);
|
|
int;
|
|
}
|
|
)
|
|
};
|
|
|
|
(* i2a converts an integer to a string. Positive and negative
|
|
numbers are handled correctly. *)
|
|
|
|
i2a(i : Int) : String {
|
|
if i = 0 then "0" else
|
|
if 0 < i then i2a_aux(i) else
|
|
"-".concat(i2a_aux(i * ~1))
|
|
fi fi
|
|
};
|
|
|
|
(* i2a_aux is an example using recursion. *)
|
|
|
|
i2a_aux(i : Int) : String {
|
|
if i = 0 then "" else
|
|
(let next : Int <- i / 10 in
|
|
i2a_aux(next).concat(i2c(i - next * 10))
|
|
)
|
|
fi
|
|
};
|
|
|
|
};
|
|
|
|
class Main inherits IO {
|
|
|
|
char : String;
|
|
avar : A;
|
|
a_var : A;
|
|
flag : Bool <- true;
|
|
|
|
|
|
menu() : String {
|
|
{
|
|
out_string("\n\tTo add a number to ");
|
|
print(avar);
|
|
out_string("...enter a:\n");
|
|
out_string("\tTo negate ");
|
|
print(avar);
|
|
out_string("...enter b:\n");
|
|
out_string("\tTo find the difference between ");
|
|
print(avar);
|
|
out_string("and another number...enter c:\n");
|
|
out_string("\tTo find the factorial of ");
|
|
print(avar);
|
|
out_string("...enter d:\n");
|
|
out_string("\tTo square ");
|
|
print(avar);
|
|
out_string("...enter e:\n");
|
|
out_string("\tTo cube ");
|
|
print(avar);
|
|
out_string("...enter f:\n");
|
|
out_string("\tTo find out if ");
|
|
print(avar);
|
|
out_string("is a multiple of 3...enter g:\n");
|
|
out_string("\tTo divide ");
|
|
print(avar);
|
|
out_string("by 8...enter h:\n");
|
|
out_string("\tTo get a new number...enter j:\n");
|
|
out_string("\tTo quit...enter q:\n\n");
|
|
in_string();
|
|
}
|
|
};
|
|
|
|
prompt() : String {
|
|
{
|
|
out_string("\n");
|
|
out_string("Please enter a number... ");
|
|
in_string();
|
|
}
|
|
};
|
|
|
|
get_int() : Int {
|
|
{
|
|
(let z : A2I <- new A2I in
|
|
(let s : String <- prompt() in
|
|
z.a2i(s)
|
|
)
|
|
);
|
|
}
|
|
};
|
|
|
|
is_even(num : Int) : Bool {
|
|
(let x : Int <- num in
|
|
if x < 0 then is_even(~x) else
|
|
if 0 = x then true else
|
|
if 1 = x then false else
|
|
is_even(x - 2)
|
|
fi fi fi
|
|
)
|
|
};
|
|
|
|
class_type(var : A) : SELF_TYPE {
|
|
case var of
|
|
a : A => out_string("Class type is now A\n");
|
|
b : B => out_string("Class type is now B\n");
|
|
c : C => out_string("Class type is now C\n");
|
|
d : D => out_string("Class type is now D\n");
|
|
e : E => out_string("Class type is now E\n");
|
|
o : Object => out_string("Oooops\n");
|
|
esac
|
|
};
|
|
|
|
print(var : A) : SELF_TYPE {
|
|
(let z : A2I <- new A2I in
|
|
{
|
|
out_string(z.i2a(var.value()));
|
|
out_string(" ");
|
|
}
|
|
)
|
|
};
|
|
|
|
main() : Object {
|
|
{
|
|
avar <- (new A);
|
|
while flag loop
|
|
{
|
|
-- avar <- (new A).set_var(get_int());
|
|
out_string("number ");
|
|
print(avar);
|
|
if is_even(avar.value()) then
|
|
out_string("is even!\n")
|
|
else
|
|
out_string("is odd!\n")
|
|
fi;
|
|
-- print(avar); -- prints out answer
|
|
class_type(avar);
|
|
char <- menu();
|
|
if char = "a" then -- add
|
|
{
|
|
a_var <- (new A).set_var(get_int());
|
|
avar <- (new B).method2(avar.value(), a_var.value());
|
|
} else
|
|
if char = "b" then -- negate
|
|
case avar of
|
|
c : C => avar <- c.method6(c.value());
|
|
a : A => avar <- a.method3(a.value());
|
|
o : Object => {
|
|
out_string("Oooops\n");
|
|
abort(); 0;
|
|
};
|
|
esac else
|
|
if char = "c" then -- diff
|
|
{
|
|
a_var <- (new A).set_var(get_int());
|
|
avar <- (new D).method4(avar.value(), a_var.value());
|
|
} else
|
|
if char = "d" then avar <- (new C)@A.method5(avar.value()) else
|
|
-- factorial
|
|
if char = "e" then avar <- (new C)@B.method5(avar.value()) else
|
|
-- square
|
|
if char = "f" then avar <- (new C)@C.method5(avar.value()) else
|
|
-- cube
|
|
if char = "g" then -- multiple of 3?
|
|
if ((new D).method7(avar.value()))
|
|
then -- avar <- (new A).method1(avar.value())
|
|
{
|
|
out_string("number ");
|
|
print(avar);
|
|
out_string("is divisible by 3.\n");
|
|
}
|
|
else -- avar <- (new A).set_var(0)
|
|
{
|
|
out_string("number ");
|
|
print(avar);
|
|
out_string("is not divisible by 3.\n");
|
|
}
|
|
fi else
|
|
if char = "h" then
|
|
(let x : A in
|
|
{
|
|
x <- (new E).method6(avar.value());
|
|
(let r : Int <- (avar.value() - (x.value() * 8)) in
|
|
{
|
|
out_string("number ");
|
|
print(avar);
|
|
out_string("is equal to ");
|
|
print(x);
|
|
out_string("times 8 with a remainder of ");
|
|
(let a : A2I <- new A2I in
|
|
{
|
|
out_string(a.i2a(r));
|
|
out_string("\n");
|
|
}
|
|
); -- end let a:
|
|
}
|
|
); -- end let r:
|
|
avar <- x;
|
|
}
|
|
) -- end let x:
|
|
else
|
|
if char = "j" then avar <- (new A)
|
|
else
|
|
if char = "q" then flag <- false
|
|
else
|
|
avar <- (new A).method1(avar.value()) -- divide/8
|
|
fi fi fi fi fi fi fi fi fi fi;
|
|
}
|
|
pool;
|
|
}
|
|
};
|
|
|
|
};
|
|
|