home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1990
/
11
/
m_floyd.asc
< prev
next >
Wrap
Text File
|
1990-10-12
|
24KB
|
819 lines
_ROLL YOUR OWN OBJECT-ORIENTED LANGUAGE_
by Michael Floyd
[LISTING ONE]
/* File : OOP.PRO -- Include file that adds inheritance mechanism
and message passing facility. This file also declares the
object-oriented predicates msg(), method(), has(), and is_a().
Objects are implemented using a technique known as frames;
the inheritance mechanism is based on the article "Suitable for
Framing" by Michael Floyd (Turbo Technix, April/May '87).
Michael Floyd -- DDJ -- 8/28/90 -- CIS: [76703,4057] or MCI Mail: MFLOYD
*/
DOMAINS
object = object(string,slots) % not actually used in examples
objects = object*
slot = slot(string,value)
slots = slot*
value = int(integer) ; ints(integers) ;
real_(real) ; reals(reals) ;
str(string) ; strs(strings) ;
object(string,slots,parents) ; objects(objects)
parents = string*
integers = integer*
reals = real*
strings = string*
% --- OOP preds to be used by the programmer ---
DATABASE
has(string,slots) % storage for instance vars
is_a(string,string) % hierarchy relationships
PREDICATES
msg(string,string) % send a message to an object
method(string, string) % define a method
% --- Internal Predicates not called ditrectly by the programmer ---
inherit(string,slot) % inheritance mechanism
description(string,slot) % search for matching clauses
member(slot,slots) % look for object in a list
CLAUSES
/* Inheritance Mechanism */
inherit(Object,Value):-
description(Object,Value),!.
inherit(Object,Value):-
is_a(Object,Object1),
inherit(Object1,Value),
description(Object1,_).
description(Object,Value):-
has(Object,Description),
member(Value,Description).
description(Object,slot(method,str(Value))):-
method(Object,Value).
/* Simple message processor */
msg(Object,Message):-
inherit(Object,slot(method,str(Message))).
/* Support Clauses */
member(X,[X|_]):-!. % Find specified member in a list
member(X,[_|L]):-member(X,L).
[LISTING TWO]
/* File: FIGURES.PRO -- Object Prolog example that models FIGURES example in
Turbo C++ and Turbo Pascal documentation
Michael Floyd -- DDJ -- 8/28/90
*/
include "bgi.pro"
include "OOP.PRO"
domains
key = escape; up_arrow; down_arrow; left_arrow; right_arrow; other
database - SHAPES
anyShape(string)
PREDICATES % Support predicates
horiz(integer, integer, string)
vert(integer, integer, integer)
readkey(integer, integer, integer)
key_code(key, integer, integer, integer)
key_code2(key, integer, integer, integer)
repeat
main
CLAUSES
/* Methods */
/* point is an example of an Abstract object. Note that variables passed
through the database must be explicitly called by the child
method (i.e. variables are not inherited). */
method(point, init):-
assert(has(point,[slot(x_coord,int(150)),
slot(y_coord,int(150))])).
method(point, done):-
retractall(has(point,_)).
method(point,show):-!,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
putpixel(X,Y,blue).
method(point,hide):-!,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
putpixel(X,Y,black).
/* Example of a virtual method */
method(point,moveTo):-!,
anyShape(Object),
msg(Object,hide),
retract(has(point,[slot(x_coord,int(DeltaX)),
slot(y_coord,int(DeltaY))])),
msg(Object,show).
method(point,drag):-
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
anyShape(Shape),!,
msg(Shape,show),
repeat,
readkey(Key, DeltaX, DeltaY),
assertz(has(point,[slot(x_coord,int(DeltaX)),
slot(y_coord,int(DeltaY))])),
msg(point,moveTo),
Key = 27.
/* Circle Methods */
method(circle, init):-!,
method(point, init),
assert(anyShape(circle)).
method(circle, done):-!,
retract(anyShape(circle)),
method(point, done).
method(circle, show):-!,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
setcolor(white),
circle(X,Y,50).
method(circle, hide):-!,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
setcolor(black),
circle(X,Y,50).
method(circle, drag):-
msg(circle, hide),
is_a(circle, Ancestor),
msg(Ancestor, drag),
msg(circle, show).
/* arc Methods */
method(arc, init):-!,
assert(anyShape(arc)),
assert(has(point,[slot(x_coord,int(150)),
slot(y_coord,int(150))])),
assert(has(arc,[slot(radius,int(50)),
slot(startAngle,int(25)),
slot(endAngle,int(90))])).
method(arc, done):-
retract(anyShape(arc)),!,
retractall(has(arc,_)),
method(point, init).
method(arc, show):-
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
has(arc,[slot(radius,int(Radius)),
slot(startAngle,int(Start)),
slot(endAngle,int(End))]),!,
setcolor(white),
arc(X, Y, Start, End, Radius).
method(arc, hide):-
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
has(arc,[slot(radius,int(Radius)),
slot(startAngle,int(Start)),
slot(endAngle,int(End))]),!,
setcolor(black),
arc(X, Y, Start, End, Radius).
method(arc,drag):-
msg(arc, hide),
is_a(arc,Ancestor),!,
msg(Ancestor,drag),
msg(arc, show).
/* rectangle Methods */
method(rectangle,init):-
has(rectangle,[slot(length,int(L)),
slot(width,int(W))]),!.
method(rectangle,init):-!,
write("Enter Length of rectangle: "),
readint(L),nl,
write("Enter Width of rectangle: "),
readint(W),nl,
assert(has(rectangle,[slot(length,int(L)),
slot(width,int(W))])).
method(rectangle,done):-
retract(has(rectangle,[slot(length,int(L)),
slot(width,int(W))])),!.
method(rectangle,draw):-!,
has(rectangle,[slot(length,int(L)),
slot(width,int(W))]),
write("Z"),
horiz(1,L,"D"),
write("?"),nl,
vert(1,W,L),
write("@"),
horiz(1,L,"D"),
write("Y").
method(rectangle,draw):-
write("Cannot draw rectangle"),nl.
/* Support Methods */
horiz(I,L,Chr):-
I <= L,!,
TempI = I + 1,
write(Chr),
horiz(TempI,L,Chr).
horiz(I,L,Chr):-!.
vert(I,W,L):-
I <= W,!,
TempI = I + 1,
write("3"),
horiz(1,L," "),
write("3"),nl,
vert(TempI,W,L).
vert(I,W,L):-!.
/* Ancestor/Child relationships - should be stored in consult() file */
is_a(circle,point).
is_a(arc,point).
is_a(triangle,shape).
is_a(rectangle,shape).
is_a(solid_rectangle,rectangle).
/* Generic clause to read cursor keys - used by the Drag method */
readkey(Val, NewX, NewY) :-
readchar(T),
char_int(T, Val),
key_code(Key, Val, NewX, NewY).
key_code(escape, 27, 0, 0) :- !.
key_code(Key, 0, NewX, NewY) :- !,
readchar(T),
char_int(T, Val),
key_code2(Key, Val, NewX, NewY).
key_code2(up_arrow, 72, NewX, NewY) :- !,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
NewX = X,
NewY = Y - 5.
key_code2(left_arrow, 75, NewX, NewY):- !,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
NewX = X - 5,
NewY = Y.
key_code2(right_arrow, 77, NewX, NewY) :- !,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
NewX = X + 5,
NewY = Y.
key_code2(down_arrow, 80, NewX, NewY) :- !,
has(point,[slot(x_coord,int(X)),
slot(y_coord,int(Y))]),
NewX = X,
NewY = Y + 5.
key_code2(other, _,0,0).
/* Supports the repeat/fail loop */
repeat.
repeat:- repeat.
main:-
nl,
initialize, % init BGI graphics
makewindow(1,7,0,"",0,0,25,80),
msg(circle, init), % create and manipulate a circle
msg(circle, show),
msg(circle, drag),
msg(circle, done),
clearwindow,
msg(arc, init), % create and manipulate an arc
msg(arc, show),
msg(arc, drag),
msg(arc, done),
closegraph, % return to text mode
makewindow(2,2,3,"",0,0,25,80),
msg(rectangle, init), % create a rectangle in text mode
msg(rectangle, draw),
msg(rectangle, done).
goal
main.
[LISTING THREE]
/* File: BGI.PRO -- Minimum required to detect graphics hardware an initialize
system in graphics mode using BGI. BGI.PRE is included with PDC Prolog.
Michael Floyd -- DDJ -- 8/28/90
*/
include "D:\\prolog\\include\\BGI.PRE"
CONSTANTS
bgi_Path = "D:\\prolog\\bgi"
PREDICATES
Initialize
CLAUSES
Initialize:-
DetectGraph(G_Driver, G_Mode),
InitGraph(G_Driver,G_Mode, _, _, bgi_Path),!.
[LISTING FOUR]
include "bgi.pro"
include "support.pro"
database - figures
anyShape(string)
point = object
int XCoord YCoord
method(init) if XCoord = 150, YCoord = 150.
method(done) if retract(has(point,_)).
method(show) if putpixel(XCoord,YCoord,blue).
method(hide) if putpixel(XCoord,YCoord,black).
method(moveTo) if
anyShape(Object),
msg(Object, hide),
retract(has(point,_)),
msg(Object, show).
method(drag) if
anyShape(Shape),
msg(Shape,show),
repeat,
readkey(Key, DeltaX, DeltaY),
XCoord = DeltaX,
YCoord = DeltaY,
msg(point,moveTo),
Key = 27.
end.
circle = object(point)
int XCoord YCoord
method(init) if
XCoord = 200, YCoord = 200,
assert(anyShape(circle)).
method(done) if
retract(anyShape(circle)),
msg(point,done).
method(show) if
setcolor(white),
circle(XCoord, YCoord, 50).
method(hide) if
setcolor(black),
circle(XCoord, YCoord, 50).
method(drag) if
msg(circle,hide),
is_a(circle, Ancestor),
msg(Ancestor,drag),
msg(circle,show).
end.
arc = object(point)
int XCoord YCoord Radius StartAngle EndAngle
method(init) if
Radius = 50, StartAngle = 25, EndAngle = 90,
msg(point, init).
method(done) if
retract(anyShape(arc)),
retractall(has(arc,_)),
msg(point, done).
method(show) if
setcolor(white),
arc(XCoord,YCoord,StartAngle,EndAngle,Radius).
method(hide) if
setcolor(black),
arc(XCoord,YCoord,StartAngle,EndAngle,Radius).
method(drag) if
msg(arc,hide),
is_a(arc,Ancestor),
msg(Ancestor,drag),
msg(arc,show).
end.
[LISTING FIVE]
/* File: PARSER.PRO -- Implements parser to translate ODL to Object Prolog
code. Top-down parser; simulates parse tree through predicate calls.
Michael Floyd -- DDJ -- 8/28/90
*/
include "lex.pro"
DOMAINS
file = infile; outfile; tmpfile
PREDICATES
main
repeat
gen(tokl)
scan
scan_object(tokl,string)
findAncestor(tokl)
init_vars
scan_methods(string)
getMethEnd(string,string)
write_includes
generate_code
generate_methods
generate_ancestor(string)
generate_vars
fixVar(tokl)
insert_isa(tokl)
bindvars(tokl,tokl)
addVarRef(tokl)
assert_temp(strings,tokl)
construct_has(tokl)
empty(tokl)
isvar(tokl,tokl)
is_op(tok)
value(tok, integer)
search_ch(CHAR,STRING,INTEGER,INTEGER)
process(string)
read(string)
datatype(string)
headbody(tokl,tokl,tokl)
search_msg(tokl,tokl,tokl)
constVar(string,tok)
writeSlotVars
write_seperator(tokl)
write_comma
append(tokl,tokl,tokl)
CLAUSES
repeat.
repeat:- repeat.
/**** Parser ****/
scan:-
readln(ObjectStr),
ObjectStr <> "",
tokl(ObjectStr,ObjList),
scan_object(ObjList,Object),
init_vars,
scan_methods(Object),!,
generate_code.
scan:- scan.
scan_object([H|List],S):-
member(object,List),
str_tok(S,H),
assert(objectname(S)),
findAncestor(List).
scan_object(List,_):-
openappend(tmpfile,"headers.$$$"),
writedevice(tmpfile),
gen(List),nl,
writedevice(screen),
closefile(tmpfile),trace(off),
fail.
findAncestor(List):-
member(lpar,List),
insert_isa(List).
findancestor(_).
insert_isa([H|List]):-
str_tok(S,H),
S <> "(",
insert_isa(List).
insert_isa([H1,H2|List]):-
str_tok(Ancestor,H2),
assert(ancestor(Ancestor)).
init_vars:-
readln(VarStr),
process(VarStr).
process(VarStr):-
fronttoken(VarStr,Token, RestStr),
datatype(Token),
tokl(VarStr,VarList),!. % tokenize/init variables
process(VarStr):-
assert(unread(VarStr)).
datatype(int). % datatypes supported
datatype(real).
constVar(int,int(_)). % convert tok to string
constVar(real,real_(_)).
read(Str):-
retract(unread(Str)),!.
read(Str):-
readln(Str).
scan_methods(MethodId):-
readln(FirstLn),
getMethEnd(FirstLn,Method),
search_ch('(',Method,0,N), % Find lpar and insert MethodId
N1 = N+1, % and add comma
fronttoken(MComma,MethodId,","),
frontstr(N1,Method,Str,OUT1),!,
fronttoken(Method1,MComma,Out1),
fronttoken(Method2,Str,Method1),
tokl(Method2,MList), % Now Tokenize the method
not(member(end,MList)), % Check for End statement
assert(methods(MList)), % Store method list
scan_methods(MethodId). % Look for more methods
scan_methods(_):- !.
getMethEnd(Line1,ReturnLn):-
search_ch('.',Line1,0,N),
N <> 0,!,
ReturnLn = Line1.
getMethEnd(Line1,ReturnLn):-
readln(Line2),
fronttoken(AppendLn,Line1,Line2),
getMethEnd(AppendLn,ReturnLn).
/**** Entry point into the code generator ****/
generate_code:-
objectname(Object),
generate_ancestor(Object),
openappend(tmpfile,"methods.$$$"),
writedevice(tmpfile),
generate_methods,
generate_vars,
vars(VarList),!,
openappend(tmpfile,"has.$$$"),
writedevice(tmpfile),
write("has(",Object,",",VarList),
write(")."),nl,
writedevice(screen),
closefile(tmpfile),
retract(objectname(Object)).
generate_vars:-
findall(Var,var(Var),VarList), % retrieve vars
retractall(var(_)), % cleanup database
fixVar(VarList),
findall(X,var(X),Slots), % retrieve new vars
retractall(var(_)), % cleanup database
assert(vars(Slots)). % store vars as list of slots
generate_vars:- !.
fixVar([]):- !.
fixVar([slot(UpToken,Const)|Rest]):-
upper_lower(UpToken,Token),
assert(var(slot(Token,Const))),
fixVar(Rest).
generate_ancestor(Object):-
openappend(tmpfile,"isa.$$$"), % open temp file for is_a
writedevice(tmpfile), % stdout to tmpfile
objectname(Obj), % get current object id
retract(ancestor(Parent)), % get parent in hierarchy
write("is_a(",Obj,",",Parent,")."), % write is_a clause
nl,
writedevice(screen), % stdout to screen
closefile(tmpfile). % close temp file
generate_ancestor(_):- % always succeed
writedevice(screen), % stdout to screen
closefile(tmpfile). % close temp file
generate_methods:-
retract(methods(Method)),!,
headBody(Method,Head,Body),
bindvars(Body,NewBody),
gen(Head),
write(":-"), nl,
addVarRef(NewBody),
gen(NewBody),nl,
generate_methods.
generate_methods:-
writedevice(screen),
closefile(tmpfile).
/* Binding of variable names in for has() lookups */
addVarRef(Body):-
findall(Variable, var(slot(Variable,_)), VList),
findall(X, var(slot(_,X)), XList),
assert_temp(VList, XList),
construct_has(Body).
addVarRef(Body).
assert_temp([],[]):- !.
assert_temp([V|VList],[X|XList]):-
constVar(Type,X),
assert(tempvar(V)),
assert(temptype(Type)),
assert_temp(VList,XList).
construct_has(Body):-
objectname(Object),
write(" has(",Object,",","["),
writeSlotVars,
write(")"),
write_seperator(Body),nl.
write_seperator([]):-
write(".").
write_seperator(_):-
write(",").
writeSlotVars:-
retract(tempVar(Var)),
retract(temptype(Type)),
upper_lower(Var,VarId),
write("slot(",VarId,", ",Type,"(",Var,"))"),
write_comma,
writeSlotVars.
writeSlotVars:- !,
write("]").
write_comma:-
tempvar(_),
write(",").
write_comma:- !.
/* Append two lists */
append([], List, List).
append([H|List1], List2, [H|List3]):-
append(List1, List2, List3).
search_msg([H,H2|Body],[],Body):-
H = msg,
H2 = lpar.
search_msg([H|Method], [H|Head], Body):-
search_msg(Method,Head,Body).
search_ch(CH,STR,N,N):- % Search for char in string
frontchar(STR,CH,_),!. % and return its position
search_ch(CH,STR,N,N1):-
frontchar(STR,_,S1),
N2 = N + 1,
search_ch(CH,S1,N2,N1).
headbody([H|Body],[],Body):-
str_tok("if",H).
headBody([H|Method], [H|Head], Body):-
headBody(Method,Head,Body).
bindvars(Method,NewMethod):-
is_op(Op), % supports any operator
member(Op,Method), % defined by is_op()
isvar(Method,[H|RestMethod]), % locate variable in method
bindvars(RestMethod,NewMethod). % look for more vars
bindvars(NewMethod,NewMethod):- !. % return Method w/out vars
empty([]). % simple test for empty list
isvar([],[]):-!.
isvar([id(X),H2,H3|RestMethod],RestMethod):-
is_op(H2),
value(H3,Value),
objectname(ObjId),
retract(var(slot(X,_))),!, % add "var not decl." error here
assert(var(slot(X,H3))).
isvar([H|Method],NewMethod):-
isvar(Method,NewMethod).
is_op(equals).
is_op(plus).
value(int(X),X).
gen([]):- !.
gen([H|List]):-
str_tok(S,H),
write(S),
gen(List).
write_includes:-
write("include \"oop.pro\""),nl.
main:-
/**** Reads file (e.g, FIGURES.ODL) specified on command line. First order of
business is to add error handling for command line processsor. ****/
comline(Filename),
openread(infile, Filename),
readdevice(infile),
repeat,
scan,
eof(infile),
readdevice(keyboard),
openwrite(outfile,"newfig.pro"),
writedevice(outfile),
write_includes,nl,
file_str("headers.$$$",Headers),
write(Headers),nl,
write("clauses\n"),
file_str("methods.$$$",Methods),
write(Methods),nl,nl,
file_str("isa.$$$",Isa),
write(Isa),nl,nl,
file_str("has.$$$",Has),
write(Has),
writedevice(screen),
closefile(outfile),
closefile(infile),
deletefile("headers.$$$"),
deletefile("methods.$$$"),
deletefile("isa.$$$"),
deletefile("has.$$$"),
write("done").
goal
main.
[LISTING SIX]
/* File: LEX.PRO -- Implements scanner which tokenizes ODL. To modify, add
appropriate DOMAIN declarations and str_tok definitions.
Michael Floyd -- DDJ -- 8/28/90
*/
DOMAINS
tok = id(string);
int(integer); real_(real) ;
plus; minus;
mult; div;
lpar; rpar;
comma; colon;
semicolon; period;
object; method;
msg; end;
ancestor; var(string);
equals; if_;
slash; bslash;
slot(string,tok); dummy
tokl = tok*
strings = string*
DATABASE
nextTok(string) % Token lookahead
objectname(string) % current Object ID
vars(tokl) % variables list
methods(tokl) % methods list
var(tok) % individual var
ancestor(string) % tracks Object's ancestor
unread(string)
tempVar(string)
temptype(string)
PREDICATES
tokl(string, tokl) % entry point into the scanner
tokenize(string,tokl) % tokenize a string
str_tok(string, tok) % return individual token
member(tok, tokl) % verify member is in list
scan_next(string) % setup lookahead stack
clauses
str_tok("int",slot(Token,int(0))):-
retract(nextTok(Token)),!,
assert(var(slot(Token,int(0)))),
str_tok("int",_).
str_tok("int",slot(dummy,int(0))):- !,
assert(nextTok(dummy)).
str_tok("real",slot(Token,real_(0))):-
retract(nextTok(Token)),!,
assert(var(slot(Token,real_(0)))),
str_tok("real",_).
str_tok("real",slot(dummy,real_(0))):- !.
str_tok("(", lpar):- !.
str_tok(")", rpar):- !.
str_tok("=", equals):- !.
str_tok("+", plus):- !.
str_tok("-", minus):- !.
str_tok("*", mult):- !.
str_tok("/", div):- !.
str_tok("\"",bslash):- !.
str_tok(",", comma):- !.
str_tok(":", colon):- !.
str_tok(";", semicolon):- !.
str_tok(".", period):- !.
str_tok("if", if_):- !.
str_tok("object", object):- !.
str_tok("method", method):- !.
str_tok("msg", msg):- !.
str_tok("end", end):-!.
/* str_tok(Var, var(Var)):-
frontchar(Var,X,_),
X >= 'A', X <= 'Z'.*/
str_tok(ID, id(ID)):-
isname(ID),!.
str_tok(IntStr,int(Int)):-
str_int(Intstr,Int).
/* Entry point into the scanner */
tokl(Str, Tokl):-
fronttoken(Str, Token, RestStr),
scan_next(RestStr),
tokenize(Str,Tokl).
tokenize("",[]):- !, retractall(nexttok(_)).
tokenize(Str, [Tok|Tokl]):-
fronttoken(Str, Token, RestStr),
str_tok(Token, Tok),
tokenize(RestStr, Tokl).
scan_next("").
scan_next(RestStr):-
fronttoken(RestStr, NextToken, MoreStr),
assert(nexttok(NextToken)),
scan_next(MoreStr).
member(X,[X|_]):-!.
member(X,[_|L]):-member(X,L).