up | next | Tom Wetmore | ttw@shore.net | LifeLines
The LifeLines programming subsystem lets you produce reports in any style or layout. You may generate files in troff, Postscript, TeX, SGML or any other ASCII-based format, for further text processing and printing.
You access the report generator by choosing the r
command from
the main menu.
You may also use the programming subsystem to create query and other processing
programs that write their results directly upon the screen.
For example, there is a LifeLines program that computes the relationship
between any two persons in a database.
LifeLines programs are written in the LifeLines programming language and stored in normal files. When you request LifeLines to run a program, LifeLines asks you the name of the program file, asks you where you want the output written, and then runs the program. For example, say you want LifeLines to generate an ahnentafel report that looks like:
1. Thomas Trask WETMORE IV b. 18 December 1949, New London, Connecticut 2. Thomas Trask WETMORE III b. 15 October 1925, New London, Connecticut 3. Joan Marie HANCOCK b. 6 June 1928, New London, Connecticut 4. Thomas Trask WETMORE Jr b. 5 May 1896, New London, Connecticut d. 8 November 1970, New London, Connecticut 5. Vivian Genevieve BROWN b. 5 April 1896, Mondovi, Wisconsin 6. Richard James HANCOCK b. 18 August 1904, New London, Connecticut d. 24 December 1976, Waterford, Connecticut 7. Muriel Armstrong SMITH b. 28 October 1905, New Haven, Connecticut 8. Thomas Trask WETMORE Sr b. 13 March 1866, St. Mary's Bay, Nova Scotia d. 17 February 1947, New London, Connecticut 9. Margaret Ellen KANEEN b. 27 October 1859, Liverpool, England d. 10 May 1900, New London, Connecticut ...
Here is a LifeLines program that generates this report:
proc main () { getindi(indi) list(ilist) list(alist) enqueue(ilist, indi) enqueue(alist, 1) while(indi, dequeue(ilist)) { set(ahnen, dequeue(alist)) d(ahnen) ". " name(indi) "\n" if (e, birth(indi)) { " b. " long(e) "\n" } if (e, death(indi)) { " d. " long(e) "\n" } if (par, father(indi)) { enqueue(ilist, par) enqueue(alist, mul(2,ahnen)) } if (par,mother(indi)) { enqueue(ilist, par) enqueue(alist, add(1,mul(2,ahnen))) } } }
Say this program is in a file named ahnen
.
When you choose the r
option from the main menu, LifeLines asks:
What is the name of the report program?
|
You enter ahnen. Since the program generates a report, LifeLines asks where to write that report:
What is the name of the output file?
|
You enter a file name, say my.ahnen
.
LifeLines reads the program ahnen
, executes it, and writes the output to
my.ahnen
.
LifeLines will report on any syntax or run-time errors found while trying to run the program.
A LifeLines program is made up of procedures and functions; every
program must contain at least one procedure named main
.
The main procedure runs first; it may call other
procedures, functions and built-in functions.
In the ahnentafel example there is only one procedure.
A procedure body is a sequence of statements. In the example program the first five statements are:
getindi(indi) list(ilist) list(alist) enqueue(ilist, indi) enqueue(alist, 1)
The first statement calls the getindi
(get individual) built-in
function, which causes LifeLines to ask you to identify a person using the
zip browse style of identification:
Identify person for interpreted report
|
After you identify a person, he or she is assigned to the variable indi
.
The next two statements declare two list variables, ilist
and alist
.
Lists hold sequences of things; there are operations for placing things on lists,
taking things off, and iterating through the list elements.
In this example program, ilist
holds a list of ancestors, in ahnentafel order,
who have not yet been reported on, and alist
holds their
respective ahnentafel numbers.
The next two statements call the enqueue
function, adding the first
members to both lists.
The person identified by the getindi
function is made the first member of
ilist
, and the number one, the first person's ahnentafel number,
is made the first member of alist
.
The rest of the program is:
while(indi, dequeue(ilist)) { set(ahnen, dequeue(alist)) d(ahnen) ". " name(indi) "\n" if (e, birth(indi)) { " b. " long(e) "\n" } if (e, death(indi)) { " d. " long(e) "\n" } if (par, father(indi)) { enqueue(ilist, par) enqueue(alist, mul(2,ahnen)) } if (par, mother(indi)) { enqueue(ilist, par) enqueue(alist, add(1,mul(2,ahnen))) } }
This is a loop that iteratively removes persons and their ahnentafel numbers from the two lists, and then prints their names and birth and death information. If the persons have parents in the database, their parents and their parents' ahnentafel numbers are enqueued at the ends of the lists. The loop iterates until the lists are empty.
The loop is a while
loop statement. The line:
while(indi, dequeue(ilist)) {
removes (via dequeue
) a person from ilist
, and assigns the person to variable indi
.
As long as there are persons on ilist
, another iteration of the loop follows.
The statement:
set(ahnen, dequeue(alist))
is an assignment statement.
The second argument is evaluated; its value is assigned to the first argument, which must be a
variable.
Here the next number in alist
is dequeued and assigned to variable
ahnen
.
This is the ahnentafel number of the person just dequeued from ilist
.
The line:
d(ahnen) ". " name(indi) "\n"
contains four expression statements; when expressions are used as
statements, their values, if any, are treated as strings and written directly to the report output file.
The d
function converts its integer argument to a numeric string.
The ". " is a literal (constant) string value.
The name
function returns the default form of a person's name.
The "\n" is another literal string representing the newline character.
The next two lines:
if(e, birth(indi)) { " b. " long(e) "\n" } if(e, death(indi)) { " d. " long(e) "\n" }
write out basic birth and death information about a person.
These lines are if
statements.
The second argument in the conditional is evaluated and assigned to the first
argument, which must be a variable.
The first if
statement calls the birth
function, returning the first
birth event in a person's record.
If the event exists it is assigned to variable e
, and the body (the items
between the curly brackets) of the if
statement is executed.
The body consists of three expression statements: a literal, a call to the long
and another literal.
long
takes an event and returns the values of the first DATE
and
PLAC
lines in the event.
Finally in the program is:
if (par, father(indi)) { enqueue(ilist,par) enqueue(alist,mul(2,ahnen)) } if (par,mother(indi)) { enqueue(ilist,par) enqueue(alist,add(1,mul(2,ahnen))) }
These lines add the father and mother of the current person, if either
or both are in the database, to ilist
.
They also compute and add the parents' ahnentafel numbers to alist
.
A father's ahnentafel number is twice that of his child.
A mother's ahnentafel number is twice that of her child plus one.
These values are computed with the mul
and add
functions.
up | next | Tom Wetmore | ttw@shore.net | LifeLines
1/1/00