Previous Up Next

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:

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 12.

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 or 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.


Previous Up Next