========================================================
(C)1993,1994 Institute for New Generation Computer Technology
(Read COPYRIGHT for detailed information.)
========================================================

Using KLIC
==========
December 2, 1993
Last revision: January 10, 1994
Takashi Chikayama (ICOT)

1. KL1 Language

Here, a very informal and rough description of the KL1 language is
given.  More detailed and accurate specification are planned to be
supplied in future releases.

1.1 Basic Mechanism

The following is a KL1 program example.

	Example 1: qsort

	:- module qsort.

	sort(X, Y) :- sort(X, Y, []).

	sort([], Y, Z) :- Y = Z.
	sort([P|X], Y, Z) :-
		partition(P, X, X1, X2),
		sort(X1, Y, [P|Y1]),
		sort(X2, Y1, Z).

	partition(_, [], S, L) :-
		S = [],
		L = [].
	partition(P, [W|X], S, L) :- W =< P |
		S = [W|S1],
		partition(P, X, S1, L).
	partition(P, [W|X], S, L) :- W >= P |
		L = [W|L1],
		partition(P, X, S, L1).

The first line, ":- module qsort" declares that this program module
will be called "qsort".  The module mechanism will be discussed more
in detail below.

Execution of a KL1 program is a (possibly parallel) repetitive
reduction of given goals using program clauses.  Each "clause" has the
following form.

	predicate_name(Argument pattern ...) :- Guard | Body.

When a goal is to be reduced, clauses for the predicate of the goal
will be inspected.  For clauses with matching argument pattern, their
guard parts are tested.  All the clauses with matching argument
pattern and satisfied guard conditions are candidates to be used in
the reduction.  Only one of them, arbitrarily chosen, will be used and
the original goal will be replaced by the goals in the body of the
clause chosen.

If no guard condition tests are required, the guard part along with
the vertical bar can be omitted.

1.2 Predicates

Predicates of KL1 corresponds to functions of C or Lisp.  Unlike C or
Lisp, predicates are identified not only by there names but also with
their number of arguments.  In the above example, two predicates with
the name "sort", with 2 and 3 arguments, are defined.  To identify
predicates with the same name but different arity, we use a notation
such as "Predicate/Arity".  In the above example, two predicates
"sort/2" and "sort/3" are defined.

1.3 Module

As mentioned above, the first line of KL1 program, ":- module qsort"
in the above example, declares that this program module will be called
"qsort".  Module declarations should be given at the top of programs.
A module consists of the "clauses" following it, up to the next module
declaration or the end of the file.

Goals is associated with a predicate.  A predicate for a goal can be
specified merely by its name if it is defined in the same module.
Otherwise, when a predicate is in a different module, it can be
designated by the syntax "Module:Predicate".  For example, a module
named "main" that uses the module "qsort" might be defined as follows.

	Example 2: main module for qsort

	:- module main.

	main :-
		X = [9,2,8,3,6,7,4,1,5],
		builtin:print(X),
		qsort:sort(X, Y),
		builtin:print(Y).

Here, the body goal "qsort:sort(X, Y)" is associated with the
predicate "sort/2" of the module "qsort".

1.4 Priority Specification

Goals have execution priority associated with them.  Execution
priority is specified by a positive integer value.  Goals with larger
priority values are usually executed early than goals with smaller
priority values.  However, priority specifications are no more than
scheduling hints and actual implementation may not strictly obey it.

Body goals can have execution priority specification in one of the
following formats.

	GOAL@priority(AbsPrio)
	GOAL@lower_priority
	GOAL@lower_priority(RelPrio)

Here, AbsPrio and RelPrio should be a non-negative integer constant or
a variable which should be instantiated to a non-negative integer
later.

With the absolute priority specification, the goal with the
specification will have the priority value specified.  With the
relative priority specification, the goal will have priority less than
the current priority by the specified value.  The specification
"GOAL@lower_priority" has the same effect as "GOAL@lower_priority(1)".
Goals without any priority specification will have the same priority
value as their parent.

When a negative priority value is specified, it is interpreted as
zero.

1.5 Initial Goal

All KLIC programs starts from the initial goal "main:main", i.e., the
predicate "main" with no arguments defined in the module "main".

The initial goal has the maximum priority possible in the
implementation.


2. Built-in Predicates

Some predicates are built in to the system.

There are two kinds of built-in predicates: those which can be used in
the guard part and those which can be used in the body part.

2.1 Guard Built-in Predicates

The comparison predicates, such as "W =< P" in the exmaple 1, are
typical guard built-in predicates.  The following is the list of guard
built-in predicates available with the current system.

 wait(X)
	Waits until instantiation of X.
 list(X)
	Tests whether X is a list.
 atom(X)
	Tests whether X is an atom.
 integer(X)
	Tests whether X is an integer.
 atomic(X)
	Tests whether X is atomic, i.e., an atom or an integer.
 functor(X,F,A)
	X is a functor with the princiapl functor F and arity A.
	This predicate can be used for testing that X has principal
	functor F and/or arity A, or for knowing its princiapl functor
	and/or arity.  It cannot be used to create a new functor.
	The principal functor of atomic data, strings and vectors are
	themselves and their arities are zero.
 arg(K,X,A)
	The Kth argument of X is A.  Arguments are numbered from 1.
 X > Y
 X >= Y
 X =:= Y
 X =< Y
 X < Y
	Performs arithmetical comparison of two integer arguments.
	Each sides of the comparison can be an arithmetical expression
	using the following operators.

		+	addition (unary and binary)
		-	subtraction (unary and binary)
		*	multiplication
		/	integer division
		mod	modulo
		\	complement (unary)
		/\	bit-wise logical AND
		\/	bit-wise logical OR
		xor	bit-wise exclusive OR
 V := X
	Computes the value of the expression X, and unifies it with V.
	The same set of arithmetical operators as in comparison
	predicates can be used.
 vector(X)
	Tests whether X is a vector.
 vector(X,L)
	Tests whether X is a vector and, if so, returns its length in L.
 string(X)
	Tests whether X is a string.
 string(X,L)
	Tests whether X is a string and, if so, returns its length in
	L.
 string(X,L,W)
	Tests whether X is a string and, if so, returns its length in
	L and its element bit width in W.  Currently, only 8-bit
	strings are provided.
 current_priority(P)
	Returns the priority value of the reduced goal to P.

Note: Unlike in some Prolog systems, arithmetical expressions are
macros expanded into more primitive builtin predicates such as "add"
or "subtract" at compilation time.  It is not allowed to dynamically
decide which expression to evaluate at runtime.

2.2 Body Built-in Predicates

The body built-in predicates are considered to be defined in the
module "builtin".  In the above example 2, "builtin:print(X)" is an
instance of a goal that is associated with such a built-in predicate
(the notation with the module name "builtin" will be changed in future
releases and the module name "builtin" will become optional).  The
following is the list of body built-in predicates available with the
current system.

 V := X
	Computes the value of the expression X, and unifes it with V.
	The same operators as in comparison predicates can be used.
 builtin:print(X)
	Prints the value of X to stdout stream.
	Note: This predicate does _not_ wait for instantiation of X.
	Better interface is described in the file "io".
 new_functor(F,P,A)
	Creates a new functor with its principal functor being P and
	its arity being A and returns it as F.
 arg(K,F,A)
	The Kth argument of F is A.  Arguments are numbered from 1.
 set_arg(K,F,E,NF)
	Makes a copy of a functor F with its argument K replaced with
	E and returns it as NF.
 new_vector(V,L)
	A new vector with L elements is created and returned as V.
	The newly created vector is filled with integer 0.
 vector_element(V,K,E)
	The K'th element of a vector V is returned to E.
 set_vector_element(V,K,NE,NV)
	A new vector which is the same as V except that the K'th
	element is replaced with NE is created and returned as NV.
 set_vector_element(V,K,E,NE,NV)
	The K'th element of a vector V is returned to E, and a new
	vector which is the same as V except that the K'th element is
	replaced with NE is created and returned as NV.
 new_string(S,L,W)
	A new string with L elements of W bits is created and returned
	as S.  Currently, only 8 is valid for W.  The newly created
	string is filled with integer 0.
 string_element(S,K,E)
	The K'th element of a string S is returned to E.
 set_string_element(S,K,NE,NS)
	A new string which is the same as S except that the K'th
	element is replaced with NE is created and returned as NS.

The following body built-in predicates are for preliminary system
testing and measurement.  They are currently available but they might
be omitted in future releases.

 builtin:readint(X)
	Reads an integer value X from stdin stream.
 builtin:print(X)
	Prints out X to stdout stream, whether or not X has become
	fully ground (without variables in it) or not.  Sometimes
	useful for debugging.
 builtin:start_measure.
	Starts measurement of resource usage, such as CPU time,
	number of GC, etc.  What can be measured depends on the
	operating system used.
 builtin:report_measure(X)
	Prints the result of resource usage measurement to stdout
	stream.  It also unifies X with the CPU time used since the
	start_message predicate is called.


3. Running KLIC

Read INSTALL for information on installation of the KLIC system.

3.1 Compilation

After proper installation, compilation of the KL1 programs into C and
then to executable can be effected by simply running "klic" with an
argument which is the name of the KL1 program source file with the
trailing ".kl1".  For example, to compile "XXX.kl1", type in:

	% klic XXX.kl1

The compilation result will be found in "a.out".  If you want the
compilation result to be named "YYY", do the following.

	% klic -o YYY XXX.kl1

If your program is divided into several files, say "XXX.kl1",
"YYY.kl1" and "ZZZ.kl1", you can compile and link them together by the
following.

	% klic XXX.kl1 YYY.kl1 ZZZ.kl1

It is also possible to separately compile several KL1 source files and
link them afterwards.  To avoid linkage errors, you have to stop
before linkage by giving the "-c" flag, as follows.

	% klic -c XXX.kl1
	% klic -c YYY.kl1
	% klic -c ZZZ.kl1

Finally, you have to link all of them together by the following.

	% klic XXX.o YYY.o ZZZ.o

Details of compilation flags are described below.

3.2 Running Compiled Code

You can simply run the compiled excutable.  The predicate "main" with
no arguments in the module "main" will be the initial goal to be
executed.

Following options are available on running the compiled executable.

    -h SIZE
	Specifies heap size in words.  As copying garbage collection
	is used, memory size actually used for heap will be twice this
	size.  The size can be specified directly (such as "2097152")
	or with a postfix "k" or "m" (as "2048k" or "2m") to specify
	units of 2^10 or 2^20 words.  The default heap size is
	determined by the macro HEAPSIZE, which is 24k in the original
	distribution.  The length of one word is the same as the
	length of the type "long int" in C, that depends on the
	hardware and the C compiler you use.

    -g
	Specifies that time required for garbage collection is to be
	measured.  As garbage collection will not take long for small
	heap sizes, the measurement overhead can be more than that.
	Thus, by default, garbage collection timing is disabled.

When all the ready goals have been executed, the program will stop.
If there remain any goals awaiting for input data, the number of such
goals is reported.  This is usually a program bug.

3.3 Tracing

KLIC system provides a stepping tracer.  See the file "tracer" in this
directory for details.

3.4 Compilation Flags

    -c
	Stop after generating relocatable object and don't link the
	program.
    -C
	Stop after translation into C.
    -d
	Don't try any compilation (dry run).  Implies "-v".
    -Ddatabase_manager
	Specifies alternative database manager program.
    -g
	Debug flag passed to the C compiler.
    -Idirectory
	Specifies alternative include directory for C compilation.
    -Kklic_compiler
	Specifies alternative KL1 to C translator.
    -llibrary
	Specifies additional library for linking.
    -Ldirectory
	Specifies additional directory to be searched for "-l".
    -ofile
	Specifies the name of executable file.
    -O
    -Olevel
	Specifies optimization level.  When non-zero optimization
	level is specified, some additional optimization flags may be
	also passed to the C compiler.  Such Additional optimization
	flags are system dependent and determined on KLIC system
	installation procedure.
    -R
	Specifies recompilation regardless of file dates.
    -S
	Stop after generating assembly code output.
    -t
	Link with tracing runtime library.
    -v
	Verbose run.  All the commands executed through the compielr
	driver will be output to standard error.
    -xdirectory
	Use database file "klic.db" in the specified directory and
	also place "atom.c" and "funct.c" and their corresponding
	objects in the same directory.  This flag is useful when
	programs to be linked together are distributed to multiple
	directories.
    -Xdirectory
	When the database file "klic.db" does not exist, initiate it
	from the database initiation file "klicdb.init" under the
	specified directory.  It defaults to the default library
	directory.


4. Diagnostics

Currently minimal diagnostics are provided by the compiler.

The KL1 to C compiler may output warning messages for redundant
clauses.  A clause is considered redundant when the head and guard
conditions of some other clause is a subset of the condition of the
clause.  In such cases, the following message will be output.

	In MODULE:PREDICATE/ARITY: Redundant clause
	In MODULE:PREDICATE/ARITY: Clause deleted

In actual such messages, MODULE, PREDICATE and ARITY are replaced by
actual module name, predicate name and arity of the problematic
clause.

Undefined predicates are reported by C compiler and linker.
For example, assume that you compile the following program.

	:- module main.
	mian :- foo.

The C compiler will report errors in a way such as follows.

  test.c: In function `module_main':
  test.c:33: label `foo_0_ext_interrupt' used but not defined
  test.c:32: label `foo_0_loop' used but not defined

The undefined labels `foo_0_...' correspond to the fact that predicate
foo/0, meant to be defined in the same module, was not defined.

The message will be different when a predicate of an external module
is left undefined.  For the program:

	:- module main.
	main :- foo:bar.

	:- module foo.
	baz.

the linker will report that predicate bar/0 is not defined in the
module foo by reporting the following.

 ld: Undefined symbol 
    _predicate_foo_xbar_0 

The module name "foo", the predicate name "bar" and its arity "0" are
all encoded into one identifier.  Underline charcters are used to
deliminate them.  In addition, the character 'x' is placed before the
predicate name.

Any non-alphanumeric characters in module or predicate names are
encoded into an underline ('_') followed by two hexadecimal digits of
the ASCII character code.  Underlines themselves in names are doubled.
Thus, if the undefined predicate in the module foo is named '+_-' with
two arguments, it will be reported as the following.

 ld: Undefined symbol 
    _predicate_foo_x_2B__2D_2 

The same error will be reported when the module foo was not defined at
all.


5. Bugs

- Requires a Prolog system to compile KL1 programs.
  The compiler will be written in KL1 itself and its translation in C
  will become available with future releases.

- Compilation-time error diagnosis is quite poor.

- The provided set of built-in predicates is incomplete.

- The current tracer is only for sequential processing.

- Performance analysis tools are not provided.

- When execution completes with suspended goals, only the number of
  such goals is reported.

- Failures are reported but normal executables would not report which
  goal failed.  Use traced executables for knowing failed goals.

- There sure are many more.

Please report bugs and comments to the following address.

	klic-bugs@icot.or.jp

Releases of new versions including bug fixes will be announced to the
following mailing list.

	klic-users@icot.or.jp

This same mailing list may also be used to exchange information among
users.

Subscription to this mailing list should be sent to the following.

	klic-requests@icot.or.jp
