CS143-Lab/examples/arith.cl
2023-03-16 15:55:37 +00:00

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;
}
};
};