Category : Files from Magazines
Archive   : AIJUN87.ZIP
Filename : DB3.PRO

Output of file : DB3.PRO contained in archive : AIJUN87.ZIP
/* a small front-end for dBASE III (tm)
This is written in Arity Prolog(tm), but it should work with any full
Edinburgh syntax Prolog which supports Definite Clause Grammars. You may
need to add a definition for integer if your Prolog doesn't provide it.

To run, enter parse. Then enter your command, closing it with a period and
a carriage return. When you're all done, enter
You'll need to consult the definition for read_word_list before this will work:
one can be found in */

/* This is the front end of the parser, complicated slightly so it
can tell you something besides "no" if the parse fails, and so it will
run in a loop. */

parse :-
read_word_list(List), % like read_in by Clocksin and Mellish

process([quit]) :-
nl, write('All done for now.'), nl.
process(List) :-
make_query(List, Query), % the actual syntactic translation
nl, report_query(Query), % beautified output
parseloop. % recursive call to keep it going

make_query(List, Final_query) :-
query(Query, List, []), !,
post_process(Query, Final_query). % this performs a special transformation
make_query(List, nil). % if no parse was found

report_query(nil) :-
write('Sorry, that was too tough for me.'),
report_query(List) :-
write('The generated query is :'), nl, write('. '),
write_list(List). % write a list as individual words

%-------- The grammar rules. --------

% "show me everyone who sold more than 2 grand"
query(Query) -->
scope(Scope), [who],
{assemble([Command, Scope, Condition], Query)}.
% "who made as little as 3000 dollars?"
query(Query) -->
{append([display, all], Condition, Query)}.
% "show me the next 13 items"
query(Query) -->
{append(Command, Scope, Query)}.
% "how many salespeople worked in Idaho"
query(Query) -->
[how, many],
{append([count], Condition, Query)}.

command([display]) --> command_word.
command([display]) --> command_word, [me].
command([display]) --> command_word, [for, me].
command([print]) --> [print].
command([print]) --> [print, out].
command([print]) --> [print, for, me].
command([print]) --> [give, me, a, printout, of].
command_word --> [show].
command_word --> [give].
command_word --> [list].
command_word --> [display].
command_word --> [tell].

scope([1]) --> [the, next], item_word.
scope([1]) --> [this], item_word.
scope([record, Num]) --> item_word, number(Num).
scope([all]) --> [everyone].
scope([all]) --> [every], item_word.
scope([all]) --> [all,of,the], item_word.
scope([all]) --> [all], item_word.
scope([next, Num]) --> [the, next], number(Num), item_word.
scope([next, Num]) --> number(Num), [more], item_word.
scope([rest]) --> [the, rest, of, the], item_word.
scope([rest]) --> [the, rest].
scope([rest]) --> [everyone, else].
scope([rest]) --> [every, other], item_word.
scope(nil) --> [].

number(Num) --> [Num],{integer(Num)}.
number(Num) --> [X, grand], {integer(X), Num is X * 1000}.

predicate(Pred) --> verb(Object),
quantity(Quantity, Object),
{append([for], Quantity, Pred)}.
predicate([for, Object, =, '"', Location, '"']) --> locative_verb(Object),
[in, Location],
% for simplicity, we accept anything as a state here: in a real example, you
% would want an actual test to make sure

item_word --> data_word.
item_word --> person_word.
item_word --> [ones].
item_word --> [one].

data_word --> [records].
data_word --> [record].
data_word --> [data].
data_word --> [items].
data_word --> [item].
person_word --> [people].
person_word --> [person].
person_word --> [salespeople].
person_word --> [salesperson].

verb(sales) --> [sold].
verb(commission) --> [made].
locative_verb(territory) --> [worked].
locative_verb(territory) --> [works].

% there is some redundancy here since we need to pass the verb Object down to
% any Boolean combinations
quantity(Q, Object) --> operator(Op), number(Num), boolean(Bop),
quantity(Q2, Object),
{append([Object, Op, Num, Bop], Q2, Q)}.
quantity([Object, Op, Num], Object) --> operator(Op), number(Num), qualifier.
quantity([Object, =, Num], Object) --> number(Num), qualifier.

operator(>) --> [over].
operator(>) --> [more, than].
operator(>) --> [at, least].
operator(>) --> [as, little, as].
operator(<) --> [under].
operator(<) --> [less, than].
operator(<) --> [at, most].
operator(<) --> [as, much, as].
operator(=) --> [exactly].
operator(=) --> [precisely].

boolean('.and.') --> [and].
boolean('.and.') --> [but].
boolean('.or.') --> [or].

qualifier --> [].
qualifier --> [dollars].
qualifier --> [dollars, worth].

% post_process is an ad hoc transformation pass: it is simply designed
% to take queries like
% print next 3 for sales > 2000
% and change them to
% display next 3 for sales > 2000 to print
% Handling one case this way is much easier than building it into the
% grammar in a principled fashion.
post_process([print|Tail], New_list) :-
post_process([display|Tail], [to, print], New_list).
post_process(List, New_list) :-
post_process(List, [], New_list).
post_process([], Tail, Tail).
post_process([Head|Tail], Trailer, [Head|New_list]) :-
post_process(Tail, Trailer, New_list).

% this takes a list of arbitrarily many sub-lists and make it into
% a "flattened" list (gets rid of the second level of brackets, throws out
% nils)
assemble([], []).
assemble([nil|Tail], List) :-
assemble(Tail, List).
assemble([Head|Tail], List) :-
assemble(Tail, L1),
append(Head, L1, List).

% this is to write a list as a regular sentence (individual words)
write_list([]) :- nl, nl.
write_list([Head, '"'|Tail]) :- % special cases to handle quotes
!, write(Head), write('"'), % no space before a quote
write_list(['"'|Tail]) :-
!, write('"'), % don't output a space after quote
write_list([Head|Tail]) :-
write(Head), write(' '),

% this really ought to be built in, since you always use it
append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).

  3 Responses to “Category : Files from Magazines
Archive   : AIJUN87.ZIP
Filename : DB3.PRO

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: