home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
prolog
/
library
/
diverses
/
calc.pro
< prev
next >
Wrap
Text File
|
1990-01-22
|
7KB
|
230 lines
% Simple calculator ver 1.2 to illustrate parsing using difference lists.
% Tokenizer is based on Turbo Prolog 2.0 User's Guide Chapter 13 Example 3.
% Parser based on Sterling and Shapiro, The Art of Prolog: "The most
% popular approach to parsing in Prolog is definite clause grammars
% or DCGs. DCGs are a generalization of context- free grammars that
% are executable, because they are a notational variant of a class of
% Prolog programs."
% A difference list represents a series of elements as the difference
% between two lists. Sterling and Shapiro use the notation S\S0 where
% S and S0 are lists. Since \ is not an operator, but merely a functor,
% this program uses the functor dl(S,S0) to mean the same thing. The
% advantage of using difference lists is that you avoid the overhead
% of appending lists during parsing.
% This calculator understands real numbers, +-*/ operators, most real
% functions such as sin, cos, etc, unary -, parentheses (). You can
% assign variables with =, and the variables pi and e are predefined.
% Run time errors are trapped so that things like 1/0, sqrt(-1), etc., won't
% crash the program.
% In the previous version of this program, the grammar clauses were non-
% deterministic, and some of the calculator's calculations would be done
% more than once during backtracking. In this version, everything except
% the repeat clause and the internal database are deterministic. Cuts have
% been placed at the earliest points possible, where subsequent failure
% would indicate a syntax error, and backtracking would be pointless.
% John W. Spalding 1/22/90
diagnostics
check_determ
database
symtab(real, symbol) % used to store calculator variables
domains
tok = numb(real); name(symbol); char(char)
toklist = tok*
dl = dl(toklist,toklist) % difference list
predicates
stmt(real, dl) % statement or null line to quit
stmt1(real, dl) % [ var = [var = ... ]] expr
expr(real, dl) % expr: term expr1
expr1(real, real, dl) % expr1: <nothing> | +- expr1
term(real, dl) % term: factor term1
term1(real, real, dl) % term1: <nothing> | */ term1
factor(real, dl) % factor: number|(expr)|-factor|fn(arg)|var
addop(char, dl) % tests for +- operator
mulop(char, dl) % tests for */ operator
unop(char, dl) % tests for unary operators
delim(char, dl) % tests for other delimiters
applyop(real, char, real) % perform unary operations
applyop(real, real, char, real) % perform binary operations
applyfn(real, symbol, real) % invoke a function
scanner(string, toklist) % tokenize a line of input
maketok(string, tok) % determine type and builds token
run % process one line of input
nondeterm repeat % repeat forever
trapfn(integer) % recover from runtime errors
clauses
%
% statement is [ var = [ var = ... ]] expr
%
stmt(0, dl([],[])) :- % quit on null expression.
!,
exit.
stmt(Value, S) :-
stmt1(Value, S).
stmt1(Value, dl([name(Var), char('=') | S], S0)) :-
!,
stmt1(Value, dl(S, S0)),
retractall(symtab(_, Var)),
assert(symtab(Value, Var)).
stmt1(Value, S) :-
expr(Value, S),
!.
%
% expression is a term followed by expr1
%
expr(Value, dl(S,S0)) :-
term(Temp, dl(S, S1)),
expr1(Value, Temp, dl(S1, S0)).
%
% expr1 is zero or more of instances of +- term
%
expr1(Value, A, dl(S, S0)) :-
addop(C, dl(S, S1)),
!,
term(B, dl(S1, S2)),
applyop(Temp, A, C, B),
expr1(Value, Temp, dl(S2, S0)).
expr1(Value, Value, dl(S, S)).
%
% term is factor followed by term1
%
term(Value, dl(S,S0)) :-
factor(Temp, dl(S, S1)),
term1(Value, Temp, dl(S1, S0)).
%
% term1 is zero or more instances of */ factor
%
term1(Value, A, dl(S, S0)) :-
mulop(C, dl(S, S1)),
!,
factor(B, dl(S1, S2)),
applyop(Temp, A, C, B),
term1(Value, Temp, dl(S2, S0)).
term1(Value, Value, dl(S, S)).
%
% factor is number | (expression) | unary-operator factor | fn(arg) | variable
%
factor(Value, dl([numb(Value) | S],S)) :-
!.
factor(Value, dl([char('(') | S], S0)) :-
!,
expr(Value, dl(S, S1)),
delim(')', dl(S1, S0)).
factor(Value, dl(S, S0)) :-
unop(C, dl(S, S1)),
!,
factor(Temp, dl(S1, S0)),
applyop(Value, C, Temp).
factor(Value, dl([name(Fn), char('(') | S], S0)) :-
expr(Argument, dl(S, S1)),
delim(')', dl(S1, S0)),
!,
applyfn(Value,Fn, Argument).
factor(Value, dl([name(Var) | S], S)) :-
symtab(Value, Var),
!.
%
% Determine type of operator.
%
unop(C, dl([char(C)|S], S)) :- % unary operators
C = '-'.
addop(C, dl([char(C)|S], S)) :- % +- operators
C = '+', !;
C = '-'.
mulop(C, dl([char(C)|S], S)) :- % */ operators
C = '*', !;
C = '/'.
delim(C, dl([char(C)|S], S)). % test for specific character.
%
% Perform a specified operation.
%
applyop(R, '-', A) :- R = - A.
applyop(R, A, '+', B) :- R = A + B.
applyop(R, A, '-', B) :- R = A - B.
applyop(R, A, '*', B) :- R = A * B.
applyop(R, A, '/', B) :- R = A / B.
%
% Invoke a specified function.
%
applyfn(R, sin, A) :- R = sin(A).
applyfn(R, cos, A) :- R = cos(A).
applyfn(R, tan, A) :- R = tan(A).
applyfn(R, sqrt, A) :- R = sqrt(A).
applyfn(R, log, A) :- R = log(A).
applyfn(R, ln, A) :- R = ln(A).
applyfn(R, exp, A) :- R = exp(A).
applyfn(R, arctan, A) :- R = arctan(A).
%
% Convert a string to a list of tokens.
%
scanner("", []) :- !.
scanner(Str, [Tok|Rest]) :-
fronttoken(Str, Sym, Str1), maketok(Sym, Tok), scanner(Str1, Rest).
%
% Determine the functor for a token.
%
maketok(S, numb(N)) :- str_real(S, N), !.
maketok(S, name(S)) :- isname(S), !.
maketok(S, char(C)) :- str_char(S, C).
%
% Repeat forever.
%
repeat.
repeat :- repeat.
%
% Read and process one line of input.
%
run :-
write("? "),
readln(Text),
scanner(Text,T_List),
stmt(Answer, dl(T_list,[])),
!,
writef("= %\n", Answer).
run :-
write("* Syntax error."), nl.
%
% Recover from run-time errors.
%
trapfn(0) :-
!,
removewindow,
exit.
trapfn(X) :-
writef("* Runtime error %d\n", X).
%
% Assert built-in constants e and pi, then
% process lines of input.
%
goal
PI = arctan(1.0) * 4,
assert(symtab(PI, pi)),
E = exp(1.0),
assert(symtab(E, e)),
makewindow(1, 7, 7, "Turbo Prolog Calculator 1.2", 0, 40, 25, 40),
writef("Enter expressions,\ncarriage return quits.\n\n"),
repeat,
trap(run, Errno, trapfn(Errno)),
fail.
%
% End.
%