6.3 Source Structure
The compiler normally reads files from beginning to end, but the
file end can also be simulated with a clause
end_of_file.
When reading from a terminal/console, the end of the input can be
marked by CTRL-D (in Unix-like systems) or CTRL-Z+RETURN on Windows.
When reading program source, the compiler distinguishes
clauses, directives and file queries.
Directives are terms with main functor
:-/1
while file queries have the main functor
?-/1. Everything else is a program clause (see Appendix A)
The differences between a directive and a file query are as follows:
-
File queries are general goals, and are executed when the program
is loaded, i.e. when compiling with the load-option set to all,
or when loading a compiled file. When compiling without loading,
they are ignored.
- Directives can be general goals, in which case they are executed
while the program is being compiled, and also when a compiled
program is loaded.
- Some directives are not goals, but are interpreted by the compiler
(or other source processing tool), e.g. module-directives or
pragmas. These should not be combined with general goals in
the same directive.
Directives and file queries should succeed and should only have a single
solution. No results are printed by the system, failure leads to a warning,
and an error condition will cause compilation to abort.
6.3.1 Clauses and Predicates
All other input terms are interpreted as clauses to be compiled.
A sequence of consecutive clauses whose heads have the same
functor is interpreted as one predicate. Normally, all clauses for
one predicate should be consecutive in the source. If this is not the
case, the compiler issues a warning and ignores the new clauses.
To change this behaviour, a
discontiguous/1
declaration must be used. The clauses are then collected and compiled
as a whole once the end of the source unit (file or module) has been reached.
To add clauses for a predicate incrementally though several independent
compiler invocations is only possible by declaring the corresponding
predicate as dynamic/1,
see Chapter 11.
6.3.2 Compilation and Modules
In the absence of module-directives
(module/1,
module/3)
within the file, the
file content is compiled into the module from which compile/1,2 itself
was called. This context module may be modified using the @/2 notation,
i.e. compile(File,Options)@Module. Existing static predicates will
be redefined, and clauses for dynamic predicates appended to the
existing ones (unless the 'load' option requests otherwise).
If the compiled file contains module directives (module/1,3), these
specify to which module(s) the subsequent code belongs. Module directives
are effective from the point where they occur until the next module
directive, or until the end of file. If a module directive refers
to a module that already exists, this module is erased and redefined
(unless the 'load' option requests otherwise).
It is generally recommended to follow the one file - one module
convention, and to make the base name of the file identical to the
module name. In rare cases, it may make sense to have an auxiliary
module in the same file as the main module. This is allowed, and
every new module directive terminates the previous module.
To spread the code for one module over several files, use a top-level
file containing the module directive plus one or more include-directives
(section 6.4.3) for the component files.
6.3.3 Incrementality
When it encounters a
module/1/
module/3 directive
the compiler first erases previous contents of this module,
if there was any, before starting to compile predicates
into it. This means that in order to incrementally add predicates
to a module, the module directive cannot be used
because the previous contents of the module would be destroyed.
Instead, the construct compile(File)@Module must be used.