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

382 lines
7.5 KiB
Common Lisp

(*
* Cool program reading descriptions of weighted directed graphs
* from stdin. It builds up a graph objects with a list of vertices
* and a list of edges. Every vertice has a list of outgoing edges.
*
* INPUT FORMAT
* Every line has the form vertice successor*
* Where vertice is an int, and successor is vertice,weight
*
* An empty line or EOF terminates the input.
*
* The list of vertices and the edge list is printed out by the Main
* class.
*
* TEST
* Once compiled, the file g1.graph can be fed to the program.
* The output should look like this:
nautilus.CS.Berkeley.EDU 53# spim -file graph.s <g1.graph
SPIM Version 5.4 of Jan. 17, 1994
Copyright 1990-1994 by James R. Larus (larus@cs.wisc.edu).
All Rights Reserved.
See the file README a full copyright notice.
Loaded: /home/n/cs164/lib/trap.handler
5 (5,5)5 (5,4)4 (5,3)3 (5,2)2 (5,1)1
4 (4,5)100 (4,3)55
3 (3,2)10
2 (2,1)150 (2,3)200
1 (1,2)100
(5,5)5 (5,4)4 (5,3)3 (5,2)2 (5,1)1 (4,5)100 (4,3)55 (3,2)10 (2,1)150 (2,3)200 (1,2)100
COOL program successfully executed
*)
class Graph {
vertices : VList <- new VList;
edges : EList <- new EList;
add_vertice(v : Vertice) : Object { {
edges <- v.outgoing().append(edges);
vertices <- vertices.cons(v);
} };
print_E() : Object { edges.print() };
print_V() : Object { vertices.print() };
};
class Vertice inherits IO {
num : Int;
out : EList <- new EList;
outgoing() : EList { out };
number() : Int { num };
init(n : Int) : SELF_TYPE {
{
num <- n;
self;
}
};
add_out(s : Edge) : SELF_TYPE {
{
out <- out.cons(s);
self;
}
};
print() : Object {
{
out_int(num);
out.print();
}
};
};
class Edge inherits IO {
from : Int;
to : Int;
weight : Int;
init(f : Int, t : Int, w : Int) : SELF_TYPE {
{
from <- f;
to <- t;
weight <- w;
self;
}
};
print() : Object {
{
out_string(" (");
out_int(from);
out_string(",");
out_int(to);
out_string(")");
out_int(weight);
}
};
};
class EList inherits IO {
-- Define operations on empty lists of Edges.
car : Edge;
isNil() : Bool { true };
head() : Edge { { abort(); car; } };
tail() : EList { { abort(); self; } };
-- When we cons and element onto the empty list we get a non-empty
-- list. The (new Cons) expression creates a new list cell of class
-- Cons, which is initialized by a dispatch to init().
-- The result of init() is an element of class Cons, but it
-- conforms to the return type List, because Cons is a subclass of
-- List.
cons(e : Edge) : EList {
(new ECons).init(e, self)
};
append(l : EList) : EList {
if self.isNil() then l
else tail().append(l).cons(head())
fi
};
print() : Object {
out_string("\n")
};
};
(*
* Cons inherits all operations from List. We can reuse only the cons
* method though, because adding an element to the front of an emtpy
* list is the same as adding it to the front of a non empty
* list. All other methods have to be redefined, since the behaviour
* for them is different from the empty list.
*
* Cons needs an extra attribute to hold the rest of the list.
*
* The init() method is used by the cons() method to initialize the
* cell.
*)
class ECons inherits EList {
cdr : EList; -- The rest of the list
isNil() : Bool { false };
head() : Edge { car };
tail() : EList { cdr };
init(e : Edge, rest : EList) : EList {
{
car <- e;
cdr <- rest;
self;
}
};
print() : Object {
{
car.print();
cdr.print();
}
};
};
class VList inherits IO {
-- Define operations on empty lists of vertices.
car : Vertice;
isNil() : Bool { true };
head() : Vertice { { abort(); car; } };
tail() : VList { { abort(); self; } };
-- When we cons and element onto the empty list we get a non-empty
-- list. The (new Cons) expression creates a new list cell of class
-- ECons, which is initialized by a dispatch to init().
-- The result of init() is an element of class Cons, but it
-- conforms to the return type List, because Cons is a subclass of
-- List.
cons(v : Vertice) : VList {
(new VCons).init(v, self)
};
print() : Object { out_string("\n") };
};
class VCons inherits VList {
cdr : VList; -- The rest of the list
isNil() : Bool { false };
head() : Vertice { car };
tail() : VList { cdr };
init(v : Vertice, rest : VList) : VList {
{
car <- v;
cdr <- rest;
self;
}
};
print() : Object {
{
car.print();
cdr.print();
}
};
};
class Parse inherits IO {
boolop : BoolOp <- new BoolOp;
-- Reads the input and parses the fields
read_input() : Graph {
(let g : Graph <- new Graph in {
(let line : String <- in_string() in
while (boolop.and(not line="\n", not line="")) loop {
-- out_string(line);
-- out_string("\n");
g.add_vertice(parse_line(line));
line <- in_string();
} pool
);
g;
} )
};
parse_line(s : String) : Vertice {
(let v : Vertice <- (new Vertice).init(a2i(s)) in {
while (not rest.length() = 0) loop {
-- out_string(rest);
-- out_string("\n");
(let succ : Int <- a2i(rest) in (let
weight : Int <- a2i(rest)
in
v.add_out(new Edge.init(v.number(),
succ,
weight))
) );
} pool;
v;
}
)
};
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
};
rest : String;
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(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.
The conversion stops at a space or comma.
As a side effect, r is set to the remaining string (without the comma).
*)
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
(let c : String <- s.substr(i,1) in
if (c = " ") then
{
rest <- s.substr(i+1,s.length()-i-1);
i <- j;
}
else if (c = ",") then
{
rest <- s.substr(i+1, s.length()-i-1);
i <- j;
}
else
{
int <- int * 10 + c2i(s.substr(i,1));
i <- i + 1;
if i=j then rest <- "" else "" fi;
}
fi fi
)
pool
)
);
int;
}
)
};
};
class Main inherits Parse {
g : Graph <- read_input();
main() : Object {
{
g.print_V();
g.print_E();
}
};
};
class BoolOp {
and(b1 : Bool, b2 : Bool) : Bool {
if b1 then b2 else false fi
};
or(b1 : Bool, b2 : Bool) : Bool {
if b1 then true else b2 fi
};
};