From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe)
Newsgroups: comp.lang.prolog
Subject: Re: Writing portable code.
Date: 29 Sep 92 03:50:34 GMT
Organization: Comp Sci, RMIT, Melbourne, Australia

In article <ALBERTO.92Sep28113506@karna.cs.umd.edu>, alberto@cs.umd.edu (Jose Alberto Fernandez R) writes:
> It would be nice if a facility like this would have been provided as
> part of the language. Then we wouldn't need to borrow tools from 'C'.

Nice if conditional compilation had been provided as part of Prolog?
But it doesn't need to be.

Suppose we use
    :- if(Condition).
    /* stuff */
    :- endif.
for conditional processing, and let them nest.

conditional_copy(InputFile, OutputFile) :-
	seeing(OldInput),
	telling(OldOutput),
	see(InputFile),
	tell(OutputFile),
	conditional_copy_loop(0, 0).
	told,
	tell(OldOutput),
	seen,
	see(OldInput).

conditional_copy_loop(Trues, Falses) :-
    /*  We are inside Falses false conditionals which
	are inside Trues true conditionals
    */
	read(Term),
	expand_term(Term, Expansion),
	conditional_copy_loop(Expansion, Trues, Falses).

conditional_copy_loop(end_of_file, T, F) :- !,
	StillOpen is T + F,
	(   StillOpen > 0 ->
	    format(user_error, '~N! ~w :- endifs missing.~n', [StillOpen])
	;   true
	).
conditional_copy_loop(:-(endif), T, F) :- !,
	(   F > 0 ->
	    F1 is F - 1,
	    conditional_copy_loop(T, F1)
	;   T > 0 ->
	    T1 is T - 1,
	    conditional_copy_loop(T1, 0)
	;   format(user_error, '~N! Unexpected :- endif.~n', []),
	    conditional_copy_loop(0,0)
	).
conditional_copy_loop(:-(if(Condition)), T, F) :-
	(   F =:= 0, condition_is_true(Condition) ->
	    T1 is T + 1,
	    conditional_copy_loop(T1, 0)
	;/* F > 0 or F = 0 and condition is false */
	    F1 is F + 1,
	    conditional_copy_loop(T, F1)
	).
conditional_copy_loop(:-(error(Msg)), T, F) :-
	(   F > 0 -> true
	;   format(user_error, '~N! ~w~n', [Msg])
	).
conditional_copy_loop(Other, T, F) :-
	(   F > 0 -> true
	;   portray_clause(Other)
	),
	conditional_copy_loop(T, F).


As written, this preprocessor copies from one file to another.
That can be a useful way to do it:  it lets you do the translation for
one system in another, more powerful system.
If your Prolog supports term_expansion/2, it is very easy to plug this
conditional processor into that, so no special built-in code is needed.
If your Prolog does not support term_expansion/2, it should.
Lisp without macros is only half a Lisp, as Scheme programmers know.

There are several problems with using the C pre-processor to do this job.
The first is that the C pre-processor is a *C* pre-processor, and it uses
C syntax, not Prolog syntax.  For example, it does not understand "%"
comments.  It may well report syntax errors for things that are valid
Prolog:  'FLIGHT' is not portable C.  It may get things wrong:
	0x
is perfectly valid Prolog, in the presence of a postfix operator
declaration for x, but it isn't valid C.  It may generate output that is
not valid Prolog (but you can read the ANSI C standard for yourself).

The second major problem with using the C pre-processor is that it may not
exist.  An ANSI C compiler may build the pre-processor in (and some do).
I've used a Classic C compiler which did not have a separate preprocessor
and gave you no access to the preprocessed output.

The C pre-processor may not be available because the person using your
Prolog code may not _have_ a C compiler.  (Quintus had customers using
VMS who did not have VAX C.)

And of course the C pre-processor is rather restricted in what it can do.
Writing the pre-processor in Prolog gives you something rather better
suited to Prolog.

For example, I have an
	environment/1
predicate (check the Quintus library) which I have adapted to every
Prolog that I use.  If I define
	condition_is_true(X) :- call(X).
then I can write code like

	:- if(environment(dialect(quintus))).
	float_to_integer(F, I) :- I is integer(F).
	:- endif.
	:- if(environment(dialect(esl))).
	float_to_integer(F, I) :- I is fix(F).
	:- endif.
	:- if((environment(arity(functor(N))), N < 20)).
	:- error('Functor arity bound too small.').
	:- endif.

I can also use that table at run-time to do things like

	write_error_message(M) :-
		telling(Old),
		environment(stream(error(Stream))),
		tell(Stream),
		write(Msg), nl,
		tell(Old).

-- 
RMIT policy requires the use of Gender Inclusive Language in all publications
and in all information conveyed to students, staff, and potential job
applicants.  Lapses into English are the sole responsibility of the author.
The Constitution of Australia does _not_ guarantee Freedom of Speech.
Newsgroups: comp.lang.prolog