/* File:      flrparser.P  -- The Flora Parser
**
** Author(s): Guizhen Yang
**
** Contact:   flora-users@lists.sourceforge.net
**
** Copyright (C) The Research Foundation of SUNY, 1999-2001
**
** FLORA-2 is free software; you can redistribute it and/or modify it under the
** terms of the GNU Library General Public License as published by the Free
** Software Foundation; either version 2 of the License, or (at your option)
** any later version.
**
** FLORA-2 is distributed in the hope that it will be useful, but WITHOUT ANY
** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
** more details.
**
** You should have received a copy of the GNU Library General Public License
** along with FLORA-2; if not, write to the Free Software Foundation,
** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
**
*/


:- compiler_options([xpp_on]).

#define CANOTERM	canoterm
#define CANOLIST	canolist
#define CANOBRACE	canobrace

#define FLINS		flins
#define FLDEL		fldel
#define FLREF           flref
#define FLCLS           flcls

%% @flora(...)
#define FLORASYSMOD	        florasysmod
%% @prolog(), @prolog(...)
#define PROLOGMODULE	        prologmodule
%% @prologall(), @prologall(...)
#define PROLOGALLMODULE         prologallmodule
#define FLORAUSERMOD	        florausermod
#define FLORARULEWORKSPACE	floraruleworkspace

#define ALLOW_VARIABLES         allow_variables
#define DISALLOW_VARIABLES      disallow_variables

%% If the module specification is for a dynamic rule (eg. foo in
%% insertrule{(...)@foo}), the module information is just discarded when
%% module specification is not allowed.  No NO_WORKSPACE errors reported.
#define WS_FROM_DYNRULE         dynrule
#define WS_FROM_BODY            body
#define WITH_MODULE             with_module
#define WITHOUT_MODULE          without_module

#include "flora_errors.flh"
#include "flora_terms.flh"

#define PARSER_CONTEXT	        parsecontext

:- dynamic FLORA_SYMBOL('parser_flag')(_).
:- dynamic PARSER_CONTEXT(_).

initialize_work :-
	clear_context(_).


/****************************************************************************
                           AN INFORMAL BNF GRAMMAR

%% To avoid confusion between some language elements and meta-syntax
%% (e.g., parentheses and brackets are part of BNF and also of the language
%% being described), we enclose some symbols in single quotes to make it
%% clear that they are part of the language syntax, not of the grammar.
%% However, FLORA these symbols can be used with or without the quotes.


Rule := Head (':-' Body)? .

Query := '?-' Body.

Directive := ':-' ExportDirective | OperatorDirective | SetSemanticsDirective
	             | IgnoreDependencyCheckDirective | PrologDirective

Head := HeadLiteral
Head := Head (',' | 'and') Head

HeadLiteral := BinaryRelationship | ObjectSpecification | Term

Body := BodyLiteral
Body := BodyConjunt | BodyDisjunct | BodyNegative | ControlFlowStatement
Body := Body '@' ModuleName
Body := BodyConstraint

ModuleName := 'prolog()' | 'prolog(' atom ')' | atom | 'flora(' atom ') '

BodyConjuct  := Body (',' | 'and') Body
BodyDisjunct := Body (';' | 'or') Body
BodyNegative := ('not' | '\+') Body
BodyConstraint := '{' CLPR-style constraint '}'

ControlFlowStatement  := IfThenElse | UnlessDo
                          | WhileDo | WhileLoop
			  | DoUntil | LoopUntil
IfThenElse := 'if' Body 'then' Body  ('else' Body)?  | Body '<-' Body
UnlessDo   := 'unless' Body 'do' Body
WhileDo    := 'while' Body 'do' Body
WhileLoop  := 'while' Body 'loop' Body
DoUntil    := 'do' Body 'until' Body
LoopUntil  := 'loop' Body 'until' Body

BodyLiteral := BinaryRelationship | ObjectSpecification | Term
                | DBUpdate | Refresh | NewoidOp | Builtin | Loading
                | CatchExpr | ThrowExpr

Builtin := ArithmeticComparison, Unification, MetaUnification, etc.

Loading := '[' LoadingCommand (',' LoadingCommand)* ']'
LoadingCommand := filename ('>>' atom)

BinaryRelationship := PathExpression ':' PathExpression
BinaryRelationship := PathExpression '::' PathExpression

ObjectSpecification := PathExpression '[' SpecBody ']'

SpecBody := 'not' MethodSpecification
SpecBody := SpecBody ',' SpecBody
SpecBody := SpecBody ';' SpecBody

MethodSpecification :=  ('#' | '*')? Term
MethodSpecification :=  PathExpression ValueReferenceConnective PathExpression

ValueReferenceConnective :=  '->' | '->>' | '*->' | '*->>' |
				    '=>' | '=>>' | '*=>' | '*=>>' |
                                        '+>' | '*+>' | '->->' | '*->->'

PathExpression := atom | number | string | variable | specialOidToken
PathExpression := Term | List | ReifiedFormula
PathExpression := PathExpression  PathExpressionConnective PathExpression
PathExpression := BinaryRelationship
PathExpression := ObjectSpecification
PathExpression := Aggregate

PathExpressionConnective :=  '.' | '..' | '!' | '!!'

specialOidToken :=  anonymousOid | numberedOid | thisModuleName

ReifiedFormula := ${ (Body | '(' Rule ')')+ }

%% No quotes are allowed in the following special tokens!
%% No space alowed between _# and integer
%% anonymousOid & numberedOid can occur only in rule head
%% or in reified formulas
anonymousOid   := '_#'
%% No space between _# and integer
numberedOid    := '_#'integer
thisModuleName := '_@'

List := '[' PathExpression (',' PathExpression)* ('|' PathExpression)? ']'

Term := Functor '(' Arguments ')'

Term := '#' Functor '(' Arguments ')'

Functor := PathExpression

Arguments := PathExpression (',' PathExpression)*

Aggregate := AggregateOperator '{' TargetVariable (GroupingVariables)? '|' Body '}'
AggregateOperator := 'max' | 'min' | 'avg' | 'sum' | 'collectset' | 'collectbag'
%% Note: only one TargetVariable is permitted.
%% It must be a variable, not a term. If you need to aggregate over terms,
%% as for example, in collectset/collectbag, use the following idiom:
%%      S = collectset{ V | ... , V=Term }
TargetVariable := variable
GroupingVariables := '[' variable, (',' variable)* ']'

DBUpdate := DBOp '{' UpdateList ('|' Body)? '}'
DBOp := 'insert' | 'insertall' | 'delete' | 'deleteall' | 'erase' | 'eraseall'
UpdateList := HeadLiteral ('@' atom)?
UpdateList := UpdateList (',' | 'and') UpdateList
Refresh := 'refresh{' UpdateList '}'

RuleUpdate := RuleOp '{' RuleList '}'
RuleOp := 'insertrule' | 'insertrule_a' | 'insertrule_z' |
               'deleterule' | 'deleterule_a' | 'deleterule_z'
RuleList := Rule | '(' Rule ')'  ( (',' | 'and')  '(' Rule ')' )*

NewoidOp := 'newoid{' Variable '}'

CatchExpr := 'catch{' Body, Term, Body '}'
ThrowExpr := 'throw{' Term '}'
****************************************************************************/


/****************************************************************************
  canonical_form(+ComposerTerm,-CanoniTerm)
  canonical_form(+ComposerTerm,-CanoniTerm,-PrimaryIndex)
  translates a structure constructed by the composer into an intermediate
  canonical form. That is to make the functor/arguments syntax compatible
  with the operator syntax.

  CANOTERM(CANOTERM,		% can be any CANOTERM
	   Arity,		% is known at compile time
	   ParenthesisType,	% can be '(', '[', or '{'
	   ListOfArguments,	% are CANOTERMs separated by ',' at top level
	   FunctorIndex,	% primary index of the functor (error message)
	   ParenthesisIndex	% index of the parenthesis (error message)
          )

  CANOLIST(ListOfElements,	% are CANOTERMs separated by ',' at top level
	   Tail,		% is separated by '|'
	   NumberOfElements,	% separated by ',' at the top level excluding tail
	   ParenthesisIndex	% index of the bracket '[' (error message)
           BarIndex		% index of the bar '|' if any
          )

  CANOBRACE(ListOfElements,	% are CANOTERMs separated by ',' at top level
	    NumberOfElements,	% number of terms between {...}
	    ParenthesisIndex	% index of the brace '{' (error message)
           )

  OBJECT(PrimitiveType,	% primary type as returned by the composer
	 Index		% index (error message)
        )

  Primitive Types:
    IDENTIFIER
    VARIABLE
    NUMBER
    QUOTED_ATOM
    ASCII_STRING
    SYMBOL_TOKEN
    SPECIAL_TOKEN
****************************************************************************/
canonical_form(ComposerTerm,CanoniTerm) :-
	canonical_form(ComposerTerm,CanoniTerm,_Index).

%% This is to handle arguments enclosed by brackets.
canonical_form(INFIX(S,Left,Right,Index),CanoniTerm,Index) :-
	%% Need to break associativity of these F-logic path operators.
	%% For example, a.b[f->g] is sent in like (a).(b[f->g]).
	%% But the real semantics should be ((a).(b))[f->g].
	is_pathop(S),
	!,
	%% Separate the arguments of the right operator.
	functor_and_arguments(Right,RightFunct,Args),
	canonical_form(Left,LL,_Ileft),
	canonical_form(RightFunct,RR,Iright),
	arrange_arguments(Args,S,Index,LL,RR,Iright,CanoniTerm).

canonical_form(INFIX(S,Left,Right,Index),CanoniTerm,Index) :-
	!,
	Funct=OBJECT(QUOTED_ATOM(S),Index),
	CanoniTerm=CANOTERM(Funct,2,FL_PARENTHESIS,[LL,RR],Index,NO_INDEX),
	canonical_form(Left,LL,_Ileft),
	canonical_form(Right,RR,_Iright).

canonical_form(PREFIX(S,O,Index),CanoniTerm,Index) :-
	!,
	Funct=OBJECT(QUOTED_ATOM(S),Index),
	%% Ambiguity arises when a prefix operator is written as a functor.
	%% E.g., table(p,2). In such a case, it is transformed to a term.
	( O=ARGUMENT(FL_PARENTHESIS,A,I1,_I2) ->
	    CanoniTerm=CANOTERM(Funct,N,FL_PARENTHESIS,Args,Index,I1),
	    comma_separated_list(A,Args,N)
	;
	  CanoniTerm=CANOTERM(Funct,1,FL_PARENTHESIS,[OO],Index,NO_INDEX),
	  canonical_form(O,OO,_I)
        ).

canonical_form(SUFFIX(S,O,Index),CanoniTerm,Index) :-
	!,
	Funct=OBJECT(QUOTED_ATOM(S),Index),
	CanoniTerm=CANOTERM(Funct,1,FL_PARENTHESIS,[OO],Index,NO_INDEX),
	canonical_form(O,OO,_I).

canonical_form(FUNCTION(Funct,Arg),CanoniTerm,Index) :-
	!,
	canonical_form(Funct,F,Index),
	( Arg = ARGUMENT(B,A,I1,_I2) ->
	    CanoniTerm=CANOTERM(F,N,B,AList,Index,I1),
	    ( B == FL_BRACKET ->
		N=1,
		AList=[T],
		canonical_form(A,T,_I)
	    ;
	      comma_separated_list(A,AList,N)
	    )
	; 
	  Arg=ARGUMENT(B,I1,_I2) ->
	  CanoniTerm=CANOTERM(F,0,B,[],Index,I1)
	).

%% Peel off pairs of `(' and `)'.
canonical_form(ARGUMENT(FL_PARENTHESIS,Arg,_I1,_I2),A,Index) :-
	!,
	canonical_form(Arg,A,Index).

canonical_form(ARGUMENT(FL_BRACKET,Arg,I1,_I2),CANOLIST(AList,T,N,I1,Ib),I1) :-
	!,
	%% a list
	( Arg = INFIX(FL_BAR,Left,Right,Ib) ->
	    comma_separated_list(Left,AList,N),
	    canonical_form(Right,T,_Ir)
	;
	  T=[],
	  Ib=NO_INDEX,
	  comma_separated_list(Arg,AList,N)
        ).

canonical_form(ARGUMENT(FL_BRACKET,I1,_I2),CANOLIST([],[],0,I1,NO_INDEX),I1) :- !.

canonical_form(ARGUMENT(FL_BRACE,Arg,I1,_I2),CANOBRACE(AList,N,I1),I1) :-
	!,
	comma_separated_list(Arg,AList,N).

canonical_form(ARGUMENT(FL_BRACE,I1,_I2),CANOBRACE([],0,I1),I1) :- !.

canonical_form(OBJECT(T,I),OBJECT(T,I),I) :- !.


/****************************************************************************
  comma_separated_list(+ComposerTerm,-ListOfCommaSeparatedArguments,-Arity)

  This procedure produces a list of comma separated terms. Note
  that `,' is defined as right associative. Only the top level commas
  are considered as separating the list.
****************************************************************************/
comma_separated_list(INFIX(FL_COMMA,Left,Right,_I),[LL|RList],N) :-
	!,
	canonical_form(Left,LL,_Ileft),
	comma_separated_list(Right,RList,M),
	N is M+1.

comma_separated_list(ComposerTerm,[CanoniTerm],1) :-
	!,
	canonical_form(ComposerTerm,CanoniTerm,_Index).


/****************************************************************************
  functor_and_arguments(+ComposerTerm,-Functor,-ArgumentsList)

  Flatten HiLog terms like this: F(A,B)(C,D,E) into F and [(A,B),(C,D,E)].
  Each argument is separated out as a single entity. Another example is
  F(a,b)[f->g], which is broken into F and [(a,b), [f->g]].
****************************************************************************/
functor_and_arguments(FUNCTION(Funct,Arg),F,AList) :-
	!,
	functor_and_arguments(Funct,F,L),
	append(L,[Arg],AList).

functor_and_arguments(T,T,[]).


/****************************************************************************
  arrange_arguments(+Args,+Sym,+IndSym,+Left,+Right,+IndRight,-CanoniTerm)

  Args is a list of arguments, e.g., [(a,b), [f->g]].
  Sym is the infix operator and IndSym is its index number.
  Left is the left operand.
  Right is the right operand and IndRight is its index.

  Need to break associativity of these F-logic path operators. For
  example, a.b[f->g] is sent in like (a).(b[f->g]).  But the real
  semantics should be ((a).(b))[f->g]. Note that a.b[f->g] from the top
  level will call:
  arrange_arguments([[f->g]],'.',some_index,a,b,some_index,CanoniTerm).
  When this procedure returns, CanoniTerm should be ((a).(b))[f->g].
****************************************************************************/
arrange_arguments([],S,Index,Left,Right,_Iright,CanoniTerm) :-
	!,
	Funct=OBJECT(QUOTED_ATOM(S),Index),
	CanoniTerm=CANOTERM(Funct,2,FL_PARENTHESIS,[Left,Right],Index,NO_INDEX).

arrange_arguments([A|L],S,Index,Left,Right,_Iright,CanoniTerm) :-
	%% [f->g] is a special case. Note that a.b[f->g] should be read
	%% as (a.b)[f->g].
	( A = ARGUMENT(FL_BRACKET,Arg,I1,_I2) ->
	    canonical_form(Arg,ArgTerm,_Ia),
	    N=1,
	    ArgList=[ArgTerm]
	;
	  A=ARGUMENT(FL_BRACKET,I1,_I2),
	  N=0,
	  ArgList=[]
        ),
	!,
	Funct=OBJECT(QUOTED_ATOM(S),Index),
	FunctTerm=CANOTERM(Funct,2,FL_PARENTHESIS,[Left,Right],Index,NO_INDEX),
	T=CANOTERM(FunctTerm,N,FL_BRACKET,ArgList,Index,I1),
	arrange_arguments(L,T,Index,CanoniTerm).

arrange_arguments([A|L],S,Index,Left,Right,Iright,CanoniTerm) :-
	( A = ARGUMENT(B,Arg,I1,_I2) ->
	    comma_separated_list(Arg,ArgList,N)
	;
	  A=ARGUMENT(B,I1,_I2),
	  N=0,
	  ArgList=[]
        ),
	!,
	%% If the argument is not enclose by [...], then associate
	%% it with the right operand.
	RR=CANOTERM(Right,N,B,ArgList,Iright,I1),
	arrange_arguments(L,S,Index,Left,RR,Iright,CanoniTerm).


/****************************************************************************
  arrange_arguments(+Args,+CanoniTerm,+Index,-CanoniTerm)

  This procedure is called when the associativity of the path operator
  has been resolved.
****************************************************************************/
arrange_arguments([],CanoniTerm,_Index,CanoniTerm) :- !.

arrange_arguments([A|L],Funct,Index,CanoniTerm) :-
	( A = ARGUMENT(B,Arg,I1,_I2) ->
	    ( B == FL_BRACKET ->
		canonical_form(Arg,ArgTerm,_Ia),
		N=1,
		ArgList=[ArgTerm]
	    ;
 	      comma_separated_list(Arg,ArgList,N)
	    )
	;
	  A=ARGUMENT(B,I1,_I2),
	  N=0,
	  ArgList=[]
        ),
	!,
	T=CANOTERM(Funct,N,B,ArgList,Index,I1),
	arrange_arguments(L,T,Index,CanoniTerm).


/****************************************************************************
  is_pathop(+Operator)
****************************************************************************/
is_pathop(FL_ISA)       :- !.
is_pathop(FL_SUB)       :- !.
is_pathop(FL_FD)        :- !.
is_pathop(FL_MVD)	:- !.
is_pathop(FL_INHERIFD)  :- !.
is_pathop(FL_INHERIMVD) :- !.


/****************************************************************************
  utilities
****************************************************************************/
get_name(OBJECT(IDENTIFIER(Name),_I),Name)  :- !.
get_name(OBJECT(QUOTED_ATOM(Name),_I),Name) :- !.

get_flname_struct(OBJECT(IDENTIFIER(Name),I),FLATOM(Name,I))  :- !.
get_flname_struct(OBJECT(QUOTED_ATOM(Name),I),FLATOM(Name,I)) :- !.

get_atom(OBJECT(SYMBOL_TOKEN(Atom),_I),Atom) :- !.
get_atom(OBJECT(IDENTIFIER(Atom),_I),Atom)   :- !.
get_atom(OBJECT(QUOTED_ATOM(Atom),_I),Atom)  :- !.

change_atom_name_if_needed(OBJECT(SYMBOL_TOKEN(Atom1),I),
			   OBJECT(SYMBOL_TOKEN(Atom2),I)) :-
	nonvar(Atom1),
	atom_replacement_table(Atom1,Atom2),
	!.
change_atom_name_if_needed(OBJECT(IDENTIFIER(Atom1),I),
			   OBJECT(SYMBOL_TOKEN(Atom2),I)) :-
	nonvar(Atom1),
	atom_replacement_table(Atom1,Atom2),
	!.
change_atom_name_if_needed(OBJECT(QUOTED_ATOM(Atom1),I),
			   OBJECT(SYMBOL_TOKEN(Atom2),I)) :-
	nonvar(Atom1),
	atom_replacement_table(Atom1,Atom2),
	!.
change_atom_name_if_needed(X,X).

atom_replacement_table(FL_AND, FL_COMMA).
atom_replacement_table(FL_OR, FL_SEMICOLON).

get_integer(OBJECT(NUMBER(N),_I),N) :- integer(N).

get_index(CANOTERM(_F,_N,B,_L,Ifunct,Ibrace),Index) :-
	!,
	((B == FL_BRACKET; B == FL_BRACE) -> Index=Ibrace; Index=Ifunct).

get_index(CANOLIST(_L,_T,_N,Index,_Ib),Index) :- !.
get_index(CANOBRACE(_L,_N,Index),Index)      :- !.
get_index(OBJECT(_PrimitiveType,Index),Index) :- !.

get_index(FLATOM(_Name,Index),Index) :- !.

get_index(FLVAR(_Name,Index),Index) :- !.


get_spectoken(OBJECT(SPECIAL_TOKEN(Atom),_I),Atom) :- !.

/*************************************************************
	support for numbered anon oids
*************************************************************/
get_spectoken(OBJECT(SPECIAL_TOKEN(Atom,_Num),_I),Atom) :- !.


is_rule(CANOTERM(Funct,2,FL_PARENTHESIS,[Head,Body],_If,_Ip),Head,Body) :-
	get_name(Funct,FL_IMPLYOP).

is_directive(CANOTERM(Funct,1,FL_PARENTHESIS,[Directive],_If,_Ip),Directive) :-
	get_name(Funct,FL_IMPLYOP).

is_query(CANOTERM(Funct,1,FL_PARENTHESIS,[Query],_If,_Ip),Query) :-
	get_name(Funct,FL_QUERYOP).

%% Binary relationship, like : or ::
is_birelop(FL_ISA) :- !.
is_birelop(FL_SUB) :- !.

is_objrefop(A) :- is_fdobjrefop(A), !.
is_objrefop(A) :- is_mvdobjrefop(A), !.

is_fdobjrefop(FL_FD)       :- !.
is_fdobjrefop(FL_INHERIFD) :- !.

is_mvdobjrefop(FL_MVD)	     :- !.
is_mvdobjrefop(FL_INHERIMVD) :- !.

is_fdattspecop(FL_FDARROW)     :- !.
is_fdattspecop(FL_INFDARROW)   :- !.

%% Note: => and *=> are multivatued attribute specifications, because
%%       a[b=>{c,d}] and a[b*=>{c,d}] are legal (semantics is intersection)
is_mvdattspecop(FL_FDSIGARROW)  :- !.
is_mvdattspecop(FL_INFDSIGARR)  :- !.
is_mvdattspecop(FL_MVDSIGARROW) :- !.
is_mvdattspecop(FL_INMVDSIGARR) :- !.
is_mvdattspecop(FL_MVDARROW)   :- !.
is_mvdattspecop(FL_INMVDARROW) :- !.

is_export_spec(FL_FDARROW) :- !.
is_export_spec(FL_MVDARROW) :- !.

%% +>>, *+>>
is_incattspecop(FL_ALLINARROW)   :- !.
is_incattspecop(FL_INALLINARROW) :- !.

%% ->->, *->->
is_tolistattspecop(FL_TOLISTARROW)   :- !.
is_tolistattspecop(FL_INTOLISTARROW) :- !.

is_aggregtop(FL_MIN)        :- !.
is_aggregtop(FL_MAX)        :- !.
is_aggregtop(FL_SUM)        :- !.
is_aggregtop(FL_AVG)        :- !.
is_aggregtop(FL_COUNT)      :- !.
is_aggregtop(FL_COLLECTSET) :- !.
is_aggregtop(FL_COLLECTBAG) :- !.

is_notop(FL_NEG)	:- !.

is_tnotop(FL_TNOT)	:- !.
is_tnotop(FL_NOT)	:- !.

flrule_struct(Head,Body,FLRULE(Head,Body)).
flfact_struct(Head,FLFACT(Head)).
flquery_struct(Body,FLQUERY(Body)).
fldirective_struct(Direct,Index,FLDIRECTIVE(Direct,Index)).

flexport_wrap_term(WS,WSFrom,Term,Modules,UpdTag,Code) :-
	( var(UpdTag) ->
		Code = (WS,WSFrom,Term,Modules,FLEXPORT_READABLE)
	;
		Code = (WS,WSFrom,Term,Modules,FL_UPDATABLE)
	).
flexport_unwrap_term((WS,WSFrom,Term,Modules,Updtag),WS,WSFrom,Term,Modules,Updtag).

flexport_struct(Term,Modules,Updtag,FLEXPORT(Term,Modules,FLATOM(Updtag,_I))).
flexport_struct(DynamicModule,Term,Modules,Updtag,FLEXPORT(DynamicModule,Term,Modules,FLATOM(Updtag,_I))).
flexport_struct_list(TermList,FLEXPORT_LIST(TermList)).

fldynrule_struct(Head,Body,FLDYNRULE(Head,Body)).

%%flargumentsdirect_struct(F,N,Args,FLARGUMENTS(F,N,Args)).
%%flprlgdirect_struct(F,A,FLPROLOG(F,A)).
flopdef_struct(P,A,O,FLOPDEF(P,A,O)).
flindxdirect_struct(A,P,FLINDEX(A,P)).
flsemanticsdirect_struct(A,FLSEMANTICS(AList)) :-
	fllist_struct(A,[],NO_INDEX,AList).
flsetsemanticsdirect_struct(A,FLSETSEMANTICS(AList)) :-
	fllist_struct(A,[],NO_INDEX,AList).

flnewoidop_struct(Var,FLNEWOIDOP(Var)).

%% flora_compiler_options
flcmpoptdirect_struct(OptList,FLCMPOPT(OptList)).

%% ignore dependency checking on hilog predicates
flignoredepdirect_struct(PredList,FLIGNOREDEP(PredList)).

%% primitive structures with index for textual information
flobject_struct(OBJECT(IDENTIFIER(Atom),I),FLATOM(Atom,I))     :- !.
flobject_struct(OBJECT(QUOTED_ATOM(Atom),I),FLATOM(Atom,I))    :- !.
flobject_struct(OBJECT(SYMBOL_TOKEN(Atom),I),FLATOM(Atom,I))   :- !.
flobject_struct(OBJECT(VARIABLE(Name),I),FLVAR(Name,I))        :- !.
flobject_struct(OBJECT(NUMBER(Num),I),FLNUMBER(Num,I))         :- !.
flobject_struct(OBJECT(ASCII_STRING(Str),I),FLSTRING(Str,I))   :- !.
flobject_struct(OBJECT(SPECIAL_TOKEN(Atom),I),FLTOKEN(Atom,I)) :- !.

%%  support for numbered anon oids
flobject_struct(OBJECT(SPECIAL_TOKEN(Atom,Num),I),FLTOKEN(Atom,Num,I)) :- !.

is_flatom_struct(FLATOM(Atom,_I),Atom).
is_flnumber_struct(FLNUMBER(_Num,_I)).
is_flstring_struct(FLSTRING(_Str,_I)).

get_flvar_struct(OBJECT(VARIABLE(Name),I),FLVAR(Name,I)).
is_flvar_struct(FLVAR(_Name,_I)).
is_anonymous_flvar_struct(FLVAR(FL_UNDERSCORE,_I)).

fllist_struct(L,T,Index,FLLIST(L,T,Index)).
is_fllist_struct(FLLIST(_L,_T,_I)).

flcut_struct(Index,FLCUT(Index)).
%% primitive structures with index for textual information

%% Atoms that are passed down as literals when they appear in an object spec.
%% For instance, Obj[true], Obj[fail], Obj[!].
is_passthru_atom(FL_CUT).
is_passthru_atom(FL_TRUE).
is_passthru_atom(FL_FAIL).
%% The following are prolog predicates with no separate meaning in FLORA-2
is_passthru_pred(FL_UNIVEQ,2).
is_passthru_pred(FL_UNIVNOTEQ,2).
is_passthru_pred(FL_EQ,2).
is_passthru_pred(FL_NOTEQ,2).
is_passthru_pred(FL_ORDERLT,2).
is_passthru_pred(FL_ORDEREQLT,2).
is_passthru_pred(FL_ORDERGT,2).
is_passthru_pred(FL_ORDEREQGT,2).
is_passthru_pred(FL_IS,2).
is_passthru_pred(FL_MATHEQ,2).
is_passthru_pred(FL_MATHNOTEQ,2).
is_passthru_pred(FL_LT,2).
is_passthru_pred(FL_EQLT,2).
is_passthru_pred(FL_GT,2).
is_passthru_pred(FL_EQGT,2).

flpassthru_struct(Struct,FLPASSTRU(Struct)).
is_passthru_struct(FLPASSTRU(_Struct)).


flbirelate_struct(Subject,R,Object,FLBIRELATE(Subject,R,Object)).

flobjref_struct(Object,M,Attribute,FLOBJREF(Object,M,Attribute)).

%% Composes PARSED Funct with PARSED args to compose a parsed term
%% Use flobject_struct/2 to parse Funct
flterm_struct(Funct,Arity,Args,FLTERM(Funct,Arity,Args)).

flaggregt_struct(Op,Var,GroupVars,Conds,FLAGGREGATE(Op,Var,GroupVars,Conds)).
is_flaggregt_struct(FLAGGREGATE(_Op,_Var,_GroupVars,_Conds)).

flobjspec_struct(Object,Spec,FLOBJSPEC(Object,Spec)).

%% Spec represents the arrow type: ->, *->, ->, =>>, ...
flfdattspec_struct(Attribute,Spec,Value,FLFDATTSPEC(Attribute,Spec,Value)).
flmvdattspec_struct(Attribute,Spec,Value,FLMVDATTSPEC(Attribute,Spec,Value)).
flincattspec_struct(Attribute,Spec,Value,FLINCATTSPEC(Attribute,Spec,Value)).
fltolistattspec_struct(Attribute,Spec,Value,FLTOLISTATTSPEC(Attribute,Spec,Value)).

is_flattspec_struct(FLFDATTSPEC(_A,_S,_V))     :- !.
is_flattspec_struct(FLMVDATTSPEC(_A,_S,_V))    :- !.
is_flattspec_struct(FLINCATTSPEC(_A,_S,_V))    :- !.
is_flattspec_struct(FLTOLISTATTSPEC(_A,_S,_V)) :- !.

flmethspec_struct(Method,FLMETHSPEC(Method)).

flimethspec_struct(IMethod,FLIMETHSPEC(IMethod)).
is_flimethspec_struct(FLIMETHSPEC(_IMethod)).

fltranspec_struct(Tran,FLTRANSPEC(Tran)).
is_fltranspec_struct(FLTRANSPEC(_Tran)).

flobjeql_struct(O1,O2,FLOBJEQL(O1,O2)).

flconjunct_struct(Cond1,Cond2,FLCONJUNCT(Cond1,Cond2)).

fldisjunct_struct(Cond1,Cond2,FLDISJUNCT(Cond1,Cond2)).

flnot_struct(Goal,FLNOT(Goal)).

fltnot_struct(Goal,FLTNOT(Goal)).

flload_struct(List,FLLOAD(List)).

flconstraint_struct(Constr,FLCONSTRAINT(Constr)).

is_flworkspace_struct(FLWORKSPACE(_G,_N)).

%% Encoding these module specs: @mod @flora(mod) @prolog(mod) @prologall(mod)
flmodule_struct(IgnoreWSLit,_,_,IgnoreWSLit) :-
	ignore_workspace_literal(IgnoreWSLit),
	!.
flmodule_struct(Literal,WSName,FLORAUSERMOD,FLWORKSPACE(Literal,WSName)) :- !.
flmodule_struct(Literal,Module,FLORASYSMOD,FLFLORALIB(Literal,Module)). :- !.
flmodule_struct(Literal,FLORASYSMOD(Mod),FLORARULEWORKSPACE,FLRULEWORKSPACE(Literal,FLFLORALIB(Mod))) :- !.
flmodule_struct(Literal,WSName,FLORARULEWORKSPACE,FLRULEWORKSPACE(Literal,WSName)) :- !.
flmodule_struct(Goal,Name,PROLOGMODULE,FLPLIB(Goal,Name)). :- !.
flmodule_struct(Goal,Name,PROLOGALLMODULE,FLPLIBALL(Goal,Name)). :- !.

%% Encoding module specs of the form @prolog() and @prologall()
%% Takes a goal and protects it against hilog conversion
flplib_struct(Goal,FLPLIB(Goal)) :- !.
flpliball_struct(Goal,FLPLIBALL(Goal)) :- !.

%% Given module spec, get back module type and module name
get_module_from_spec(FLORAUSERMOD(Mod),FLORAUSERMOD,Mod) :- !.
get_module_from_spec(FLORASYSMOD(Mod),FLORASYSMOD,Mod) :- !.
get_module_from_spec(PROLOGMODULE(Mod),PROLOGMODULE,Mod) :- !.
get_module_from_spec(PROLOGMODULE,NULL) :- !.
get_module_from_spec(PROLOGALLMODULE(Mod),PROLOGALLMODULE,Mod) :- !.
get_module_from_spec(PROLOGALLMODULE,NULL) :- !.


is_flmodulespec_struct(FLWORKSPACE(_G,_N)) :- !.
is_flmodulespec_struct(FLPLIB(_G)) :- !.
is_flmodulespec_struct(FLPLIB(_G,_N)) :- !.
is_flmodulespec_struct(FLFLORALIB(_L,_M)) :- !.
is_flmodulespec_struct(FLPLIBALL(_G)) :- !.
is_flmodulespec_struct(FLPLIBALL(_G,_N)) :- !.

is_dbinsertop(FL_INSERT) :- !.
is_dbinsertop(FL_INSERTALL) :- !.

is_dbinsertop(FL_BTINSERT) :- !.
is_dbinsertop(FL_BTINSERTALL) :- !.

is_dbdeleteop(FL_DELETE) :- !.
is_dbdeleteop(FL_DELETEALL) :- !.
is_dbdeleteop(FL_ERASE) :- !.
is_dbdeleteop(FL_ERASEALL) :- !.

is_dbdeleteop(FL_BTDELETE) :- !.
is_dbdeleteop(FL_BTDELETEALL) :- !.
is_dbdeleteop(FL_BTERASE) :- !.
is_dbdeleteop(FL_BTERASEALL) :- !.

is_tablerefreshop(FL_REFRESH) :- !.
is_newmoduleop(FL_NEWMODULE) :- !.

is_catchop(FL_CATCH) :- !.
is_throwop(FL_THROW) :- !.
is_p2hop(FL_P2H) :- !.

is_newoidop(FL_NEWOIDOP) :- !.

is_ruleupdateop(FL_INSERTRULE) :- !.
is_ruleupdateop(FL_INSERTRULE_A) :- !.
is_ruleupdateop(FL_INSERTRULE_Z) :- !.
is_ruleupdateop(FL_DELETERULE_A) :- !.
is_ruleupdateop(FL_DELETERULE_Z) :- !.
is_ruleupdateop(FL_DELETERULE) :- !.

is_clauseop(FL_CLAUSE) :- !.

is_callermoduleop(FL_CALLERMODULE) :- !.

is_reifyop(FL_REIFYOP) :- !.

flrefresh_struct(List,FLREFRESH(List)).

flinsert_struct(Op,List,Cond,FLINSERT(Op,List,Cond)).
flinsert_struct(Op,List,FLINSERT(Op,List)).
fldelete_struct(Op,List,Cond,FLDELETE(Op,List,Cond)).
fldelete_struct(Op,List,FLDELETE(Op,List)).

flnewmodule_struct(Op,Mod,FLNEWMODULE(Op,Mod)).
flcallermodule_struct(Op,Var,FLCALLERMODULE(Op,Var)).
flupdaterule_struct(Op,RuleList,FLUPDATERULE(Op,RuleList)).

flclause_struct(Head,Body,FLCLAUSE(Head,Body)).
flclause_struct(Mode,Head,Body,FLCLAUSE(Mode,Head,Body)).

is_flcallermodule_struct(FLCALLERMODULE(_,_)).
is_flupdaterule_struct(FLUPDATERULE(_,_)).
is_flnewmodule_struct(FLNEWMODULE(_,_)).
is_flinsert_struct(FLINSERT(_,_)).
is_flinsert_struct(FLINSERT(_,_,_)).
is_fldelete_struct(FLDELETE(_,_)).
is_fldelete_struct(FLDELETE(_,_,_)).
is_flrefresh_struct(FLREFRESH(_)).
ignore_workspace_literal(Lit) :-
	(is_flcallermodule_struct(Lit)
	; is_flnewmodule_struct(Lit)
	; is_flupdaterule_struct(Lit)
	; is_flinsert_struct(Lit)
	; is_fldelete_struct(Lit)
	; is_flrefresh_struct(Lit)
	).

flifthenelse_struct(Cond,Then,Else,FLIFTHENELSE(Cond,Then,Else)).
flifthen_struct(Cond,Then,FLIFTHEN(Cond,Then)).

%% struct for meta ~
fluniveqform_struct(Left,Right,FLUNIVEQFORM(Left,Right)).
%% struct for =..
flmetauniv_struct(Left,Right,FLMETAUNIV(Left,Right)).
%% struct for ~..
flmetaunivform_struct(Left,Right,FLMETAUNIVFORM(Left,Right)).

%% struct for ${...}
flreify_struct(Formula,FLREIFYOP(Formula)).
is_flreify_struct(FLREIFYOP(_Formula)).

flcatch_struct(Goal,Error,Handler,FLCATCH(Goal,Error,Handler)).
flthrow_struct(Error,FLTHROW(Error)).
flp2h_struct(Prolog,Hilog,FLP2H(Prolog,Hilog)).

flcontrolconstruct_struct(Cond,Action,FLWHILEDO,FLWHILEDO(Cond,Action)).
flcontrolconstruct_struct(Cond,Action,FLWHILELOOP,FLWHILELOOP(Cond,Action)).
flcontrolconstruct_struct(Cond,Action,FLDOUNTIL,FLDOUNTIL(Cond,Action)).
flcontrolconstruct_struct(Cond,Action,FLLOOPUNTIL,FLLOOPUNTIL(Cond,Action)).
flcontrolconstruct_struct(Cond,Action,FLUNLESSDO,FLUNLESSDO(Cond,Action)).

%% Arg 1: parser's wrapper for control construct
%% Arg 2: top-level keyword of control construct
%% Arg 3: second keyword of construct
get_control_construct_definition(FLWHILEDO,FL_WHILE,FL_DO).
get_control_construct_definition(FLWHILELOOP,FL_WHILE,FL_LOOP).
get_control_construct_definition(FLDOUNTIL,FL_DO,FL_UNTIL).
get_control_construct_definition(FLLOOPUNTIL,FL_LOOP,FL_UNTIL).
get_control_construct_definition(FLUNLESSDO,FL_UNLESS,FL_DO).

%% Management of global parser context
clear_context(X) :- retractall(PARSER_CONTEXT(X)).
report_context(X) :- assert(PARSER_CONTEXT(X)).


/****************************************************************************
  parsing_error(+IndexOrTerm,+ErrorMessage,-Status)

  Note on handling the Status parameter in parsing predicates:
  If a call to a parsing predicate comes with non-empty Status,
  DO NOT call parsing_error/3, but rather pass the Status parameter 
  up to the caller.

  Status must ALWAYS be unbound
****************************************************************************/
parsing_error(Index,ErrorMessage,Status) :-
	integer(Index),
	!,
	Status=[error(Index,ErrorMessage)].

parsing_error(CanoniTerm,ErrorMessage,Status) :-
	get_index(CanoniTerm,I),
	Status=[error(I,ErrorMessage)].


/****************************************************************************
  flora_parse(+ComposerTerm,-Code,-Status)
  is the top level dispatcher.
****************************************************************************/
flora_parse(NULL,NULL,[]) :- !.

flora_parse(ComposerTerm,Code,Status) :-
	initialize_work,
	canonical_form(ComposerTerm,CanoniTerm),
	( is_rule(CanoniTerm,Head,Body) ->
	    flora_parse_rule(Head,Body,Code,Status)

	; is_directive(CanoniTerm,Directive) ->
	    flora_parse_directive(Directive,Code,Status)

	; is_query(CanoniTerm,Query) ->
	    flora_parse_query(Query,Code,Status)

	; %% flora_parse_fact must be the last one to call.
	  flora_parse_fact(CanoniTerm,Code,Status)
        ),
	!.

%% This rule is for debugging.
flora_parse(_ComposerTerm,_Code,[error(UNKNOWN_ERROR)]).


/****************************************************************************
  flora_parse_directive(+CanoniTerm,-Code,-Status)
  is the dispatcher for directives.
  Code: FLDIRECTIVE([directives+])

  Note: Textual information is not reserved for compiler directives.
****************************************************************************/
flora_parse_directive(CanoniTerm,Code,Status) :-
	CanoniTerm = CANOTERM(_Funct,_Arity,_,_L,If,_Ip),
	(
	flora_export_directive(CanoniTerm,_WS,WS_FROM_BODY,CodeList,Status)
	%%; flora_arguments_directive(CanoniTerm,CodeList,Status)
	; flora_operator_directive(CanoniTerm,CodeList,Status)
	; flora_index_directive(CanoniTerm,CodeList,Status)
	; flora_setsemantics_directive(CanoniTerm,CodeList,Status)
	; flora_cmpopt_directive(CanoniTerm,CodeList,Status)
	; flora_ignoredep_directive(CanoniTerm,CodeList,Status)
        ),
	fldirective_struct(CodeList,If,Code),
	!.

flora_parse_directive(CANOTERM(Funct,_N,_F,_Args,If,_Ip),_Code,Status) :-
	get_name(Funct,FL_AT),
	parsing_error(If,DISALLOWED_DIRECT,Status).

flora_parse_directive(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,UNKNOWN_DIRECT,Status).


/****************************************************************************
  flora_exec_directive(+CanoniTerm,+FloraModSpec,+WSFrom,-Code,-Status)
  Code: FLDIRECTIVE([directives])

  Note: This is to parse those executable directives either from a shell
        or inside a program. Normal directives only affect how a single
        program is translated. Executable directives affect the translation
        of all subsequent command entered from the shell.
****************************************************************************/
flora_exec_directive(CanoniTerm,FloraModSpec,WSFrom,Code,Status) :-
	CanoniTerm = CANOTERM(_Funct,_Arity,_,_L,If,_Ip),
	fldirective_struct(CodeList,If,Code),
	( 
	flora_exec_export_directive(CanoniTerm,FloraModSpec,WSFrom,CodeList,Status)
	%%; flora_arguments_directive(CanoniTerm,CodeList,Status)
	; flora_operator_directive(CanoniTerm,CodeList,Status)
	; flora_exec_index_directive(CanoniTerm,CodeList,Status)
	; flora_exec_setsemantics_directive(CanoniTerm,CodeList,Status)
	; flora_exec_semantics_directive(CanoniTerm,CodeList,Status)
	),
	!.


/****************************************************************************
  flora_comma_separated_list(+CanoniTerm,-CanoniTermList)
  Converts a comma-separated list into a normal list
****************************************************************************/
flora_comma_separated_list(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),[L|RList]) :-
	%% Comma as an operator is right associative.
	(get_atom(Funct,FL_COMMA) ; get_atom(Funct,FL_AND)),
	!,
	flora_comma_separated_list(R,RList).

flora_comma_separated_list(CanoniTerm,[CanoniTerm]) :- !.


/***************************************************************************
   flora_list_to_conjunct(+ListOfCanoniTerms,-ConjunctOfCanoniTerms,+If,+Ip)
   Converts list of terms into a comma-separated list
***************************************************************************/

flora_list_to_conjunct([H],H,_If,_Ip) :- !.
flora_list_to_conjunct([H|Tail],
		       CANOTERM(Funct,2,FL_PARENTHESIS,[H,TailConj],If,Ip),
		       If, Ip) :-
	Funct = OBJECT(QUOTED_ATOM(FL_COMMA),If),
	flora_list_to_conjunct(Tail,TailConj,If,Ip).


/******************** PARSING FOR EXPORT ********************************/

/************************************************************************
	The canonical term structure is something like this:
		canoterm(export, N, FL_PARENTHESIS, Args, _, _)
	N	-> Indicates the number of terms in the external module (modules exported too) list.
	Args	->[canoterm(>>, N', FL_PARENTHESIS, Args', _, _) | <ExportedModuleList = m2,m3... mn>]
	Args'	->[canoterm(Exported_Term), m1],

	Semantics:
	1.No external modules specified:
	  The particular perdicate has to be exported to all modules.

	2.None of the predicates of a module are exported:
	  The modules does not require any encapsulation.

	When N=1, the difference is the following:

	In the case where there is a module name, the argument Args:
		canoterm(>>, N', FL_PARENTHESIS, Args', _, _)
	and Args' contains the exported term & the first module name.

	In case there is no external module.
	1. there is no >>
	2. the third argument is FL_BRACKET
	3. the canonical term actually represents the exported term

	The exported term list is first regularized and converted to
	a form  = [(ws,term,modules,is_updatable), (ws,term,modules,is_updatable), ...].
	We then individually work with the members of the list, reporting
	any errors if they occur.

****************************************************************************/


/****************************************************************************
 flora_exec_export_directive(+CanoniTerm,+FloraModSpec,+WSFrom,-CodeList,-Status)
 Parsing for the executable directive case.
****************************************************************************/
%% Export for a dynamic module.
%% WS = dynamic module name, may or may not be specified.
flora_exec_export_directive(CanoniTerm,WS,WSFrom,CodeList,Status):-
	flora_export_directive(CanoniTerm,WS,WSFrom,CodeList,Status),
	(var(Status) ->
		Status = []
	;
		true
	).


/****************************************************************************
 flora_export_directive(+CanoniTerm,+WorkSpace,+WSFrom,-CodeList,-Status)
 The work-horse that does the parsing both in the executable and
 non-executable case.
****************************************************************************/
flora_export_directive(CANOTERM(Funct,_N,FL_PARENTHESIS,Args,_If,_Ip),WS,WSFrom,[Code],Status) :-
	%% check directive name.
	get_name(Funct,FL_EXPORT),
	%% parse the exported terms
	flora_regularize_export_spec(Args,WS,WSFrom,TermList),
	%% parse the list
	flora_export_parse_term_list(TermList,[],TermListCode,Status),
	flexport_struct_list(TermListCode,Code),
	!.

%% error case.
flora_export_directive(CANOTERM(Funct,_N,FL_PARENTHESIS,_Args,If,_Ip),_WS,_WSFrom,_Code,Status) :-
	%% check directive name.
	get_name(Funct,FL_EXPORT),
	!,
	parsing_error(If,ERROR_EXPORT,Status).


/****************************************************************************
 flora_regularize_export_spec(+ExportedTerms,+WorkSpace,+WSFrom,-CodeList,-Status)
 The work-horse that first regularises and then does the parsing both 
 in the executable and non-executable case.
****************************************************************************/
%% Export as an operator, multiple terms exported.
%% :-(export(','((term>>m1),m2,m3... ))
flora_regularize_export_spec([CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip)],WS,WSFrom,ListCode) :-
	(get_name(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
	!,
	%% convert a comma-separated list into a normal list
	flora_comma_separated_list(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),List),
	%% regularize to a list
	flora_export_compose_term_list(List,[],WS,WSFrom,_IsUpd,ListCode).

%% for all other cases.
%% :-(export( (term1),(term2),(term3) ))
%% One or many terms exported (may be enclosed by paranthesis).
%% typical canonical term = (export((term>>m1),m2,m3...mn))
flora_regularize_export_spec(Args,WS,WSFrom,ListCode) :-
	%% regularize to a list
	flora_export_compose_term_list(Args,[],WS,WSFrom,_IsUpd,ListCode),
	!.


/****************************************************************************
 flora_export_compose_term_list(+Args,+InitTermCode,+WorkSpace,+WSFrom,+IsUpdatable,-ExportCode)
 InitTermCode represents the list of terms processed till now.
 It is initally an empty list ([]) and gets populated progressively.
***************************************************************************/
%% single term exported
%% t1>>m1,m2,m3
flora_export_compose_term_list(Args,_InitTermCode,WS,WSFrom,IsUpd,[Code]) :-
	flora_export_check_single_term(Args),
	flora_export_compose_term(Args,WS,WSFrom,IsUpd,Code).

flora_export_compose_term_list([H|T],InitTermCode,WS,WSFrom,IsUpd,Code) :-
	%% The flora_export_compose_term expects the argument to be a list.
	%% That list may contain more than one members in the case where the 
	%% term is exported to more than one modules.
	flora_export_compose_term([H],WS,WSFrom,IsUpd,TermCode),
	%% The Code is usually a single term. However in cases 
	%% like (t1,t2) >> (m1,m2,m3), it is a list. In this case
	%% we need to explicitly append it to a list.
	%% When it is not a list, (t >> m1,m2...), then the append
	%% will fail and hence the second case.
	(	
	  %% If TermCode is a list - append
	  %% Happens when exported like (t1,t2) >> (m1,m2,m3)
	  append(TermCode,InitTermCode,List)

	;
	  %% in other cases where it is a simple term and not a list.
	  List = [TermCode|InitTermCode]
	),
	flora_export_compose_term_list(T,List,WS,WSFrom,IsUpd,Code).

flora_export_compose_term_list([],InitTermCode,_WS,_WSFrom,_IsUpd,Code) :- 
	Code = InitTermCode,
	!.

/****************************************************************************
 flora_export_compose_term(+ExportedTerm,+WorkSpace,+WSFrom,+IsUpdatable,-TermCode)
****************************************************************************/
%% with the updatable tag.
flora_export_compose_term([CANOTERM(Funct,_N,FL_PARENTHESIS,Args,_If,_Ip)],WS,WSFrom,_IsUpdatable,ExportCode) :-
	%% check whether the Funct is updatable
	get_name(Funct,FL_UPDATABLE),
	%% single or mutiple terms enclosed.
	(
	  flora_export_compose_term(Args,WS,WSFrom,FL_UPDATABLE,ExportCode),
	  !
	;
	  flora_export_compose_term_list(Args,[],WS,WSFrom,FL_UPDATABLE,ExportCode)
	).


/****************************************************************************
 One or many external modules (or terms) specified.
 ==================================================
 Term >> (Module(s))
 canoterm(RIGHTTO,_,FL_PARANTHESIS, [canoterm(Term),canoterm(ModuleList)],_,_)

 (Term1, Term2, ...) >> (Module(s))
 canoterm(RIGHTTO,N,FL_PARANTHESIS, [ canoterm(comma,_,FL_PARANTHESIS,[canoterm(Term1),canoterm(Term2)...],_,_),
				     canoterm(ModuleList)
				   ],_,_)

 Term >> Module(s)
 canoterm(RIGHTTO,_,FL_PARANTHESIS, [canoterm([Term,FirstModule]),OtherModuleList],_,_)
****************************************************************************/
flora_export_compose_term([CANOTERM(Funct,_N,FL_PARENTHESIS,[Term|FirstModule],_If,_Ip)|OtherModules],WS,WSFrom,IsUpdatable,Code) :- 
	get_name(Funct,FL_RIGHTTO),
	append(FirstModule,OtherModules,Modules),
	(
		%% may be a list of term instead of a sinlge term.
		%% (t1,t2) >> (m1,m2)
		flora_export_wrap_multiple_terms(WS,WSFrom,Term,Modules,IsUpdatable,Code)
	;	
		flexport_wrap_term(WS,WSFrom,Term,Modules,IsUpdatable,Code)
	),
	!.


/****************************************************************************
 First term in case when export is used as an operator.
 ==================================================
 Say the export statement is :- export (_[c1->_]>>m3,m4), _[b1(_,_)->_]>>m1.

 flora_comma_separated_list returns the exported list in the following form:
 [ canoterm(comma,_,FL_PARANTHESIS,[canoterm(FirstExportedTerm)],_,_),
   canoterm(SecondExportedTerm), ....]

 Thus for the first term, we need extract the canonical term by stripping the 
 comma. The predicate below does the same.
****************************************************************************/
flora_export_compose_term([CANOTERM(Funct,_N,FL_PARENTHESIS,Args,_If,_Ip)],WS,WSFrom,IsUpdatable,Code) :- 
	(get_name(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
	flora_export_compose_term(Args,WS,WSFrom,IsUpdatable,Code),
	!.

/****************************************************************************
 No modules specified (=exported to all modules).
 ================================================
 export(p(_,_)).
 export(_[a->_]).
 Term = canoterm(ExportedTerm)
****************************************************************************/
flora_export_compose_term([CANOTERM(Funct,N,PType,Args,If,Ip)],WS,WSFrom,IsUpdatable,Code) :- 
	flexport_wrap_term(WS,WSFrom,CANOTERM(Funct,N,PType,Args,If,Ip),[],IsUpdatable,Code),
	!.

%% simple atom exported, export(flora2).
flora_export_compose_term(Args,WS,WSFrom,IsUpdatable,Code) :- 
	get_name(Args,_Name),
	flexport_wrap_term(WS,WSFrom,Args,[],IsUpdatable,Code),
	!.

%% variable exported. export(F).
flora_export_compose_term([OBJECT(VARIABLE(Term),N)],WS,WSFrom,IsUpdatable,Code) :- 
	flexport_wrap_term(WS,WSFrom,OBJECT(VARIABLE(Term),N),[],IsUpdatable,Code),
	!.


/****************************************************************************
 flora_export_wrap_multiple_terms(+WorkSpace,+WSFrom,+Args,+InitTermCode,+Modules,+IsUpdatable,-Code)
 Transfroms (t1,t2) >> (m1,m2,m3) --> [(t1,(m1,m2,m3)) , (t2,(m1,m2,m3))]
***************************************************************************/
flora_export_wrap_multiple_terms(WS,WSFrom,CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),Modules,IsUpdatable,Code) :-
	(get_name(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
	%% convert a comma-separated list into a normal list
	flora_comma_separated_list(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),List),
	flora_export_wrap_termlist(List,[],WS,WSFrom,Modules,IsUpdatable,Code).


/****************************************************************************
 flora_export_wrap_termlist(+Args,+InitTermCode,+WorkSpace,+WSFrom,+Modules,+IsUpdatable,-Code)
***************************************************************************/
flora_export_wrap_termlist([H|T],InitTermCode,WS,WSFrom,Modules,IsUpdatable,Code) :-
	flexport_wrap_term(WS,WSFrom,H,Modules,IsUpdatable,HCode),
	flora_export_wrap_termlist(T,[HCode|InitTermCode],WS,WSFrom,Modules,IsUpdatable,Code).

flora_export_wrap_termlist([],InitTermCode,_WS,_WSFrom,_Modules,_IsUpd,Code) :- 
	Code = InitTermCode,
	!.
	

/****************************************************************************
 flora_export_parse_term_list(+TermList,+IntialTermCode,-TermListCode,-Status)
****************************************************************************/
flora_export_parse_term_list([H|T],InitialTerm,Code,Status) :-
	flora_export_parse_term(H,HCode,HStatus),
	( HStatus == [] ->
		flora_export_parse_term_list(T,[HCode|InitialTerm],Code,Status)
	;
		Status = HStatus
	).

flora_export_parse_term_list([],InitialTerm,Code,_Status) :-
	Code = InitialTerm,
	!.


/****************************************************************************
 flora_export_parse_term(+Term,-TermCode,-Status)
 Term = (WS,WSFrom,Term,Modules,IsUpd)
 TermCode = flrexport()
	The parsing of the exported term(s) takes place in two steps. 
 Initially, each exported term is normalized and wrapped in its 
 standard form. This list then gets parsed by unwrapping its members
 one-by-one.
****************************************************************************/
flora_export_parse_term(TermCode,ExportCode,Status) :-
	flexport_unwrap_term(TermCode,WS,WSFrom,Term,Modules,IsUpdatable),
	%% check for errors in the term exported
	flora_export_check_error(Term,Status),
	(var(Status) -> 
	    flora_export_check_module(Modules,Status)
	;
	    true
	),
	(var(Status) -> 
	    (
		flora_export_parse_body_term(Term,WS,WSFrom,TCode,StatusBody),
		flfact_struct(TCode,FactTermCode),
		%% the module(s)
		(StatusBody == [] ->
		    flora_export_parse_modules(Modules,ModuleCode,Status)
		;
		    Status = StatusBody
		),
		fllist_struct(ModuleCode,[],1,ModuleCodeList),
		flora_export_struct(WS,FactTermCode,ModuleCodeList,IsUpdatable,ExportCode)
	)
	;
	    true
	).


/****************************************************************************
 flora_export_parse_body_term(+Args,+WS,+WSFrom,-Code,-Status)
 Parses the predicate body by calling the appropriate flora_body predicate.
      The var(WS) checks whether the exported terms correspond to the module 
 other than the one which it is loaded currently. It is initialized through 
 the flora_exec_export_directive call. 
      When the same module exports the term, the variable WS will be 
 uninstantiated. Else, it may be an atom or a variable.
 ATOM: ?- (export foo)@bar.
 VARIABLE: ?- (export foo)@WS.
      In the latter case, the variable WS needs to be instantaited when the
 program is loaded else an error (Attempt to export from an invalid or 
 uninstantiated module/term.) will be reported.
****************************************************************************/
flora_export_parse_body_term(Term,WS,WSFrom,Code,Status) :-
	(var(WS) -> 
		flora_body(Term,Code,Status)
		;
		flora_body(Term,FLORAUSERMOD(WS),WSFrom,Code,Status)
	).


/****************************************************************************
 flora_export_parse_modules(+Args,-ModuleCode,-Status)
***************************************************************************/
%% term >> (m1,m2,m3...mn). Modules enclosed within paranthesis.
flora_export_parse_modules([CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip)],OtherModuleList,Status) :-
        (get_name(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
        !,
	flora_comma_separated_list(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),ModuleList),
	flora_pathexplist(ModuleList,OtherModuleList,Status).
	
%% general case, term>>m1,m2,m3...mn. Modules NOT enclosed within paranthesis.
flora_export_parse_modules(OtherModules,OtherModuleList,Status) :-
        %% the other module names 
	flora_pathexplist(OtherModules,OtherModuleList,Status).


/****************************************************************************
 flora_export_struct(+WorkSpace,+TermCode,+ModuleListCode,+IsUpdatable,-ExportCode)
**************************************************************************/
flora_export_struct(WS,TermCode,ModuleCodeList,IsUpdatable,ExportCode) :-
	(var(WS) -> 
		flexport_struct(TermCode,ModuleCodeList,IsUpdatable,ExportCode)
	;
		flexport_struct(WS,TermCode,ModuleCodeList,IsUpdatable,ExportCode)
	).


/**************** start of error handling for export ************************/


/****************************************************************************
 flora_export_check_single_term(+Term)
 %% whether only one term is exported.
 %% [Term,m1,m2...], term and the modules to which it is exported.
****************************************************************************/
%% module name is atom.
flora_export_check_single_term([CANOTERM(_Funct,_N,_FL,_Args,_If,_Ip),OBJECT(IDENTIFIER(_Atom),_)|_T]) :- !.
%% module is system module.
flora_export_check_single_term([CANOTERM(_Funct,_N,_FL,_Args,_If,_Ip),
				CANOTERM(OBJECT(IDENTIFIER(_ATOM),_),_N1,_FL1,_ARGS,_If1,_Ip1)|_T]) 
				:-!.
%% module name is variable.
flora_export_check_single_term([CANOTERM(_Funct,_N,_FL,_Args,_If,_Ip),OBJECT(VARIABLE(_Atom),_)|_T]) :- !.


/****************************************************************************
 flora_export_check_error(+Term,-Status)
****************************************************************************/
%% a simple atom exported.
flora_export_check_error(Atom,_Status) :-
        get_name(Atom,_Name),!.	

%% nontabled predicate, #p(_,_).
flora_export_check_error(CANOTERM(Funct,_N,FL_PARENTHESIS,[PredicateBody],_If,_Ip),Status) :-
	get_atom(Funct,FL_TRAN),
	flora_export_check_error(PredicateBody,Status),
	!.

%% tabled predicate case, p(_,_)
flora_export_check_error(CANOTERM(MethodName,_N,FL_PARENTHESIS,ArgList,_If,_Ip),Status) :-
	flora_export_check_method_name(MethodName,Status),
	(var(Status) -> 
		flora_export_check_attribute_list(ArgList,Status)
	; 
		true
	),
	!.
	
%% Object spec : ...[...]
flora_export_check_error(CANOTERM(ObjectID,_N,FL_BRACKET,[MethodBody],_If,_Ip),Status) :-
	flora_export_check_variable(ObjectID,Status),
	(var(Status) -> 
		flora_export_check_method(MethodBody,Status)
	;
		true
	),
	!.

%% Case when the term is a variable. Let it go through.
%% Term >> m1, m2
flora_export_check_error(OBJECT(VARIABLE(_Term),_),_Status).


/****************************************************************************
 flora_export_check_variable(+Term,-Status)
****************************************************************************/
flora_export_check_variable(Term,Status) :-
	( get_flvar_struct(Term,_VariableStruct)
	  ; flora_export_construct_error(Term,ERROR_EXPORT_ATOM,Status)
	).


/****************************************************************************
 flora_export_check_method(+Term,-Status)
****************************************************************************/
%% multiple predicates, separated by commas are exported to a set of modules.
flora_export_check_method([H|T],Status) :-
	flora_export_check_method(H,Status),
	(var(Status) -> 
		flora_export_check_method(T,Status)
	;
		true
	).

flora_export_check_method(CANOTERM(Funct,_N,FL_PARENTHESIS,[H|T],_If,_Ip),Status) :-
	(get_atom(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
	flora_export_check_method(H,Status),
	(var(Status) -> 
		flora_export_check_method(T,Status)
	;
		true
	),
	!.

flora_export_check_method([],_Status) :- !.

%% _[MethodName(AttrList) -> _]
%% _[MethodName(AttrList) => _]
flora_export_check_method(CANOTERM(MethodSpec,_N1,FL_PARENTHESIS,[CANOTERM(MethodName,_N2,FL_PARENTHESIS,AttributeList,_If2,_Ip2),ReturnVar],_If1,_Ip1),Status) :-
	flora_export_check_spec(MethodSpec,Status),
	(var(Status) ->
		flora_export_check_method_name(MethodName,Status)
	;
		true
	),
	(var(Status) ->
		flora_export_check_attribute_list(AttributeList,Status)
	;
		true
	),
	(var(Status) ->
		flora_export_check_variable(ReturnVar,Status)
	;
		true
	),
	!.

%% method with no attributes.
%% _[MethodName -> _]
%% _[MethodName => _]
flora_export_check_method(CANOTERM(MethodSpec,_N1,FL_PARENTHESIS,[MethodName,ReturnVar],_If1,_Ip1),Status) :-
	flora_export_check_spec(MethodSpec,Status),
	(var(Status) ->
		flora_export_check_method_name(MethodName,Status)
	;
		true
	),
	(var(Status) ->
		flora_export_check_variable(ReturnVar,Status)
	;
		true
	),
	!.

%%case with operator # in front.
flora_export_check_method(CANOTERM(Funct,_N,FL_PARENTHESIS,[MethodBody],_If,_Ip),Status) :-
	get_atom(Funct,FL_TRAN),
	flora_export_check_method(MethodBody,Status),
	!.

%% tabled Boolean method like _[p(_)]
flora_export_check_method(CANOTERM(MethodName,_N1,FL_PARENTHESIS,AttributeList,_If1,_Ip1),Status) :-
	flora_export_check_method_name(MethodName,Status),
	(var(Status) ->
		flora_export_check_attribute_list(AttributeList,Status)
	;
		true
	),
	!.

%% No arguments & return value (like [p]).
flora_export_check_method(Term,_Status) :-
	get_atom(Term,_Atom),
	!.

/****************************************************************************
 flora_export_check_method_name(+Term,-Status)
****************************************************************************/
%% exported terms like p(a,_)[...] are not allowed.
flora_export_check_method_name(CANOTERM(MethodName,_N1,FL_PARENTHESIS,AttributeList,_If1,_Ip1),Status) :-
	flora_export_check_method_name(MethodName,Status),
	(var(Status) ->
		flora_export_check_attribute_list(AttributeList,Status)
	;
		true
	),
	!.

%% only names with constant object ids like p, q allowed.
flora_export_check_method_name(Term,Status) :-
	( get_flname_struct(Term,_NameStruct)
	; flora_export_construct_error(Term,ERROR_EXPORT_ATOM,Status)
	).
					

/****************************************************************************
 flora_export_check_spec(+Term,-Status)
 The term exported may be one of the following types:
	p ->  _
	p ->> _
	p : q
	p :: q
 Thus this predicate checks whether the spec is allowed.
 is_birelop for (:,::), is_export_spec for (->,->>).
****************************************************************************/
flora_export_check_spec(Funct,_Status) :-
	get_atom(Funct,F),
	(
	  is_birelop(F)
	;
	  is_export_spec(F)
	),
	!.

%% error, in case the spec is not one of the above, signal an error.
flora_export_check_spec(OBJECT(QUOTED_ATOM(Name),I),Status) :-
	flora_export_construct_error(OBJECT(QUOTED_ATOM(Name),I),ERROR_EXPORT_SPEC,Status).


/****************************************************************************
 flora_export_check_attribute_list(+Term,-Status)
****************************************************************************/
flora_export_check_attribute_list([H|T],Status) :-
	( 
	  get_flvar_struct(H,_VariableStruct)
	; 
	  %% If H is not a var, then construct error
	  flora_export_construct_error(H,ERROR_EXPORT_ATOM,Status)
	),
	(var(Status) -> 
	    flora_export_check_attribute_list(T,Status)
	;
	    true
	).

flora_export_check_attribute_list([],_Status) :- !.


/****************************************************************************
 flora_export_check_module(+Term,-Status)
****************************************************************************/
%% comma separated values.
flora_export_check_module(CANOTERM(Funct,_N,FL_PARENTHESIS,[H|T],_If,_Ip),Status) :-
	(get_atom(Funct,FL_COMMA) ; get_name(Funct,FL_AND)),
	flora_export_check_module([H|T],Status),
	!.

%% a simple list
flora_export_check_module([H|T],Status) :-
	(
	  flora_export_check_module(H,Status), !
	;
	  flora_workspace(H,_HCode,StatusModule), !
	;
	  flora_export_construct_error(H,ERROR_EXPORT_MODULE,Status)
	),
	(StatusModule ==[] -> 
	    flora_export_check_module(T,Status) 
	;
	    Status = StatusModule
	),
	!.

flora_export_check_module(H,Status) :-
	flora_workspace(H,_HCode,StatusModule),
	(StatusModule == [] -> 
		true
	; 
		flora_export_construct_error(H,ERROR_EXPORT_MODULE,Status)
	),
	!.

flora_export_check_module([],_Status) :- !.


/****************************************************************************
 flora_export_construct_error(+Term,+ErrorMessage,-StatusError)
****************************************************************************/
flora_export_construct_error(Term,ErrMessage,Status) :- 
      get_index(Term,ErrNo),
      parsing_error(ErrNo,ErrMessage,Status).

/**************** end of error handling for export *************************/


/**************** end of parsing for export ********************************/



/****************************************************************************
  flora_operator_directive(CanoniTerm,CodeList,Status)
  flora_operator_definition(+Atom)
  operator_list(+Number,+Associativity,+OperatorList,-CodeList,-Status)
****************************************************************************/
flora_operator_directive(CANOTERM(Funct,3,FL_PARENTHESIS,L,_If,_Ip),CodeList,Status) :-
	get_name(Funct,FL_OP),
	L=[Number,Associativity,Operator],
	( get_integer(Number,Precedence), Precedence > 0 ->
	    ( get_name(Associativity,A), flora_operator_definition(A) ->
		( get_atom(Operator,Op) ->
		    ( flora_conflict_operator(Precedence,A,Op) ->
			parsing_error(Operator,NO_REDEFOP,Status)
		    ;
		      flopdef_struct(Precedence,A,Op,Code),
		      CodeList=[Code],
		      Status=[]
		    )

		;  Operator=CANOLIST(OpList,T,N,_I,Ib), N > 0 ->
		     ( T == [] ->
			 flora_operator_list(OpList,Precedence,A,CodeList,Status)
		     ;
		       parsing_error(Ib,NO_LISTTAIL,Status)
		     )
		;
		  parsing_error(Operator,ERROR_OPERATOR,Status)
	        )
	    ;
	      parsing_error(Associativity,ERROR_OPDEF,Status)
	    )
	;
	  parsing_error(Number,EXP_POSINTEGER,Status)
        ).


flora_operator_definition(xfx) :- !.
flora_operator_definition(yfx) :- !.
flora_operator_definition(xfy) :- !.
flora_operator_definition(fx)  :- !.
flora_operator_definition(fy)  :- !.
flora_operator_definition(yf)  :- !.
flora_operator_definition(xf)  :- !.


flora_operator_list([],_Number,_Associativity,[],[]) :- !.

flora_operator_list([T|L],Number,Associativity,[Code|CodeList],Status) :-
	!,
	( get_atom(T,Op) -> %% symbol tokens allowed as operators
	    ( flora_conflict_operator(Number,Associativity,Op) ->
		parsing_error(T,NO_REDEFOP,Status)
	    ;
		flopdef_struct(Number,Associativity,Op,Code),
		flora_operator_list(L,Number,Associativity,CodeList,Status)
	    )
	;
	  parsing_error(T,ERROR_OPERATOR,Status)
        ).


/****************************************************************************
  flora_index_directive(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_index_directive(CANOTERM(Funct,N,FL_PARENTHESIS,[L|_Rest],_If,_Ip),[Code],Status) :-
    get_name(Funct,FL_INDEX),
    ( N==1 ->
        ( minus_pair(L,Arity,Pos) ->
            Status=[],
            flindxdirect_struct(Arity,Pos,Code)
        ;
            parsing_error(L,ERROR_INDXDIREC,Status)
        )
    ;
        parsing_error(L,ERROR_INDXDIREC,Status)
    ).


minus_pair(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),A,Pos) :-
    get_name(Funct,FL_MINUS),
    ( get_integer(L,Arity),A=Arity,!;
      get_nontabled_arity(L,Arity),A=FL_TRAN(Arity)),
    get_integer(R,Pos),
    Pos>0,
    Arity>=Pos.

get_nontabled_arity(CANOTERM(Funct,1,FL_PARENTHESIS,[L],_If,_Ip),Arity) :-
    get_name(Funct,FL_TRAN),
    get_integer(L,Arity).

/****************************************************************************
  flora_exec_index_directive(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_exec_index_directive(CANOTERM(Funct,1,FL_PARENTHESIS,[L],_If,_Ip),[Code],Status) :-
    get_name(Funct,FL_INDEX),
    ( minus_var_pair(L,Arity,Pos) ->
        Status=[],
        flindxdirect_struct(Arity,Pos,Code)
    ;
        parsing_error(L,ERROR_INDXDIREC,Status)
    ).


flora_exec_index_directive(CANOTERM(Funct,_N,FL_PARENTHESIS,_T,_If,Ip),[_Code],Status) :-
    get_name(Funct,FL_INDEX),
    parsing_error(Ip,ERROR_INDXDIREC,Status).

minus_var_pair(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),NA,Pos) :-
    get_name(Funct,FL_MINUS),
    ( nontabled_arity(L,NL,FCode), !; NL=L),
    ( get_integer(NL,A) ->
	flobject_struct(NL,Arity),
        ( get_integer(R,P) ->
    	    P>0,
    	    A>=P,
	    flobject_struct(R,Pos)
	;
	    get_flvar_struct(R,Pos)
	)
    ;
	get_flvar_struct(NL,Arity),
        ( get_integer(R,P) ->
	    flobject_struct(R,Pos)
	;
	    get_flvar_struct(R,Pos)
	)
    ),
    ( nontabled_arity(L,NL,_) ->
	flterm_struct(FCode,1,[Arity],NA)
    ;
        NA=Arity
    ). 

nontabled_arity(CANOTERM(Funct,1,FL_PARENTHESIS,[L],_If,_Ip),L,FCode) :-
    flobject_struct(Funct,FCode),
    get_name(Funct,FL_TRAN).
    
/****************************************************************************
  flora_setsemantics_directive(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_setsemantics_directive(CANOTERM(Funct,_N,FL_BRACE,Args,_If,_Ip),[Code],Status) :-
	get_name(Funct,FL_SETSEMANTICS),
	!,
	parse_semantics_directive_args(DISALLOW_VARIABLES,Args,ArgsCode,Status),
	(Status == [] -> flsetsemanticsdirect_struct(ArgsCode,Code)
	;
	  true
	).


/****************************************************************************
  flora_exec_setsemantics_directive(+CanoniTerm,-CodeList,-Status)
****************************************************************************/

flora_exec_setsemantics_directive(CANOTERM(Funct,_N,FL_BRACE,Args,_If,_Ip),
			      [Code],Status) :-
	get_name(Funct,FL_SETSEMANTICS),
	!,
	parse_semantics_directive_args(DISALLOW_VARIABLES,Args,ArgsCode,Status),
	(Status=[] -> flsetsemanticsdirect_struct(ArgsCode,Code)
	;
	  true
	).

/****************************************************************************
  flora_exec_semantics_directive(+CanoniTerm,-CodeList,-Status)
  This is like setsemantics, but it is a query rather than command,
  so variables are allowed.
****************************************************************************/

flora_exec_semantics_directive(CANOTERM(Funct,_N,FL_BRACE,Args,_If,_Ip),
			      [Code],Status) :-
	get_name(Funct,FL_SEMANTICS),
	!,
	parse_semantics_directive_args(ALLOW_VARIABLES,Args,ArgsCode,Status),
	(Status=[] -> flsemanticsdirect_struct(ArgsCode,Code)
	;
	  true
	).


/****************************************************************************
  flora_cmpopt_directive(+CanoniTerm,-CodeList,-Status)
  Compiling the :- flora_compiler_options directive
****************************************************************************/
flora_cmpopt_directive(CANOTERM(Funct,1,FL_PARENTHESIS,[T],_If,_Ip),
			[Code],Status) :-
	get_name(Funct,FL_CMPOPT),
	( T=CANOLIST(List,[],_N,_I,_Ib) ->
	    flora_cmpoptlist(List,TCode,Status),
	    ( Status == [] ->
		flcmpoptdirect_struct(TCode,Code)
	    ;
		true
	    )
	;
	    parsing_error(T,EXP_OPTLIST,Status)
	).

flora_cmpoptlist([],[],[]) :- !.
flora_cmpoptlist([H|T],[HCode|TCode],Status) :-
	( get_atom(H,HCode) ->	
	    flora_cmpoptlist(T,TCode,Status)
	;
	    parsing_error(H,ERROR_CMPOPT,Status)
	).


/****************************************************************************
  flora_ignoredep_directive(+CanoniTerm,-CodeList,-Status)
  Compiling the :- ignore_depchk directive
****************************************************************************/
flora_ignoredep_directive(CANOTERM(Funct,1,FL_PARENTHESIS,[T],_If,_Ip),
			[Code],Status) :-
	get_name(Funct,FL_IGNOREDEP),
        ( flora_comma_separated_list(T,PreList) ->
            flora_parse_body_template_list(PreList,LCode,Status),
            flignoredepdirect_struct(LCode,Code)
	;
	    parsing_error(T,EXP_SPECLIST,Status)
	).


/****************************************************************************
  flora_parse_fact(+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_parse_fact(CanoniTerm,NULL,Status) :-
	%% Handle special markups for include files that are generated by gpp.
	flora_gpp_markup(CanoniTerm,Status),
	!.

flora_parse_fact(CanoniTerm,Code,Status) :-
	report_context(parsing_facts),
	flora_head(CanoniTerm,CodeList,Status),
	clear_context(parsing_facts),
	flfact_struct(CodeList,Code).


/****************************************************************************
  flora_parse_query(+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_parse_query(CanoniTerm,Code,Status) :-
	flora_body(CanoniTerm,Goal,Status),
	flquery_struct(Goal,Code).


/****************************************************************************
  flora_parse_rule(+Head,+Body,-Code,-Status)
****************************************************************************/
flora_parse_rule(Head,Body,Code,Status) :-
	flora_head(Head,HeadCodeList,S),
	( S == [] ->
	    flora_body(Body,BodyCode,Status),
	    flrule_struct(HeadCodeList,BodyCode,Code)
	;
	  Status=S
        ).


/****************************************************************************
  flora_gpp_markup(+CanoniTerm,+Status)
****************************************************************************/
flora_gpp_markup(CanoniTerm,[]) :-
	get_name(CanoniTerm,FLORA_GPP_MARKUP),
	%% This is just a delimeter for the purpose of fault tolerance.
	%% Skip it.
	!.

flora_gpp_markup(CANOTERM(Funct,3,FL_PARENTHESIS,[Arg1,Arg2,Arg3],_If,_Ip),Status) :-
	get_name(Funct,FLORA_GPP_MARKUP),
	!,
	( ( get_name(Arg3,'') ->
	      %% This is the top level file name. Reset line number.
	      flora_reset_charpos

	  ; get_name(Arg3,'1') ->
	      %% This is the beginning of a include file.
	      get_name(Arg2,FileName),
	      flora_begin_file(FileName)

	  ; get_name(Arg3,'2') ->
	      %% This is the end of a include file.
	      get_integer(Arg1,LineNumber),
	      flora_end_file(LineNumber)
	  ),
	  Status=[],
	  !
	;
	  Status=[error(ERROR_GPP)]
	).


/****************************************************************************
  flora_head(+CanoniTerm,-CodeList,-Status)

  This predicate is called to parse the head of a rule, which is a canonical
  term. Since only conjunction is allowed in a rule head, the result of parsing
  it is a list of intermidiate terms.

  Note: Module name is not allowed in rule head.
****************************************************************************/
flora_head(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),CodeList,Status) :-
	get_atom(Funct,F),
	( (F == FL_COMMA ; F==FL_AND) ->
	    flora_head(L,LCodeList,S),
	    ( S == [] ->
		flora_head(R,RCodeList,Status),
		( Status == [] ->
		    append(LCodeList,RCodeList,CodeList)
		;
		  true
		)
	    ;
	      Status=S
	    )

	; (F == FL_SEMICOLON ; F==FL_OR) -> % Disjunction is prohibited.
	    parsing_error(If,NO_DISJUNCTION,Status)

	; % Module name in rule head is prohibited.
	  F == FL_AT,
	  parsing_error(If,NO_WSINRULEHEAD,Status)
	),
	!.

flora_head(CANOTERM(Funct,1,FL_PARENTHESIS,[_G],If,_Ip),_CodeList,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!,
	parsing_error(If,NO_NEGATION,Status).

flora_head(CanoniTerm,[Code],Status) :-
	flora_head_literal(CanoniTerm,Code,Status).


/****************************************************************************
  flora_head_literal(+CanoniTerm,-HeadLiteral,-Status)

  parses a single literal in the head of a rule. Look for the grammar at
  the beginning to see what is allowed.
****************************************************************************/
flora_head_literal(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
	flora_head_pathexplist(Args,[LCode,RCode],Status),
	(Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true).

flora_head_literal(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	is_objrefop(F),
	!,
	parsing_error(If,ERROR_HDLITERAL,Status).

flora_head_literal(CANOTERM(Funct,N,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	flora_nodefp(F,N),
	!,
	parsing_error(If,NO_REDEFINITION,Status).

flora_head_literal(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_OBJEQL),
	!,
	%% equality definition fact/rule
	flora_head_pathexplist(Args,[LCode,RCode],Status),
	(Status == [] -> flobjeql_struct(LCode,RCode,Code); true).

flora_head_literal(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flora_head_term(Funct,N,Args,Code,Status).

flora_head_literal(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_head_objspec(Funct,N,Args,Code,Status).

flora_head_literal(CanoniTerm,Code,Status) :-
	get_atom(CanoniTerm,A),
	!,
	( flora_nodefp(A,0) ->
	    parsing_error(CanoniTerm,ERROR_HDLITERAL,Status)
	;
	  flobject_struct(CanoniTerm,Code),
	  Status=[]
        ).

flora_head_literal(CanoniTerm,_Code,Status) :-
	!,
	parsing_error(CanoniTerm,ERROR_HDLITERAL,Status).


/****************************************************************************
  flora_body(+CanoniTerm,-Goal,-Status)

  This predicate is called to parse the *entire* body of a rule. It takes a
  canonical term as input and parses it into an intermediate term to be
  compiled further. "CanoniTerm" can represent any logical formula of
  conjunction, disjunction, and negation. "Goal" is parsed accordingly. If
  success, "Status" is bound to [], or some warning message; otherwise, it
  is a list containing some error message.


  flora_body(+CanoniTerm,+WorkSpace,+WSFrom,-Goal,-Status)

  Note: Module name specification is distributive over negation, conjunction
        and disjunction in the rule body. It works like nesting of variable
        scope. Module name specification is also allowed in the position of
        predicate arguments, e.g., p(o[att -> val] @ ws).

        Moreover, module name specification is also distributive over
        if-then-else statement. For example, (if a then b else c)@mod has
        the same effect as (if a@mod then b@mod else c@mod).
****************************************************************************/
flora_body(CanoniTerm,Goal,Status) :-
	flora_body(CanoniTerm,NULL,WS_FROM_BODY,Goal,Status).


flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),WS,WSFrom,Code,Status) :-
	get_atom(Funct,F),
	(F == FL_COMMA; F == FL_SEMICOLON ; F==FL_AND ; F==FL_OR),
	!, % Module name is distributive over conjunction or disjunction.
	flora_body(L,WS,WSFrom,LCode,S),
	( S == [] ->
	    flora_body(R,WS,WSFrom,RCode,Status),
	    ( Status == [] ->
		( (F == FL_COMMA ; F==FL_AND) ->
		    flconjunct_struct(LCode,RCode,Code)
		;
		    fldisjunct_struct(LCode,RCode,Code)
	        )
	    ;
	      true
	    )
	;
	  Status=S
        ).

flora_body(CANOTERM(Funct,1,FL_PARENTHESIS,[G],_If,_Ip),WS,WSFrom,Code,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!, % Module name is distributive over negation.
	flora_body(G,WS,WSFrom,C,Status),
	( Status == [] ->
	    (is_notop(F) -> flnot_struct(C,Code); fltnot_struct(C,Code))
	;
	    true
        ).

flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),_WS,_WSFrom,Code,Status) :-
	get_atom(Funct,FL_AT),
	!, % nesting of module name scope
	%% The module name needs to be parsed early; otherwise, some
        %% incorrect syntax may be overridden by nested module specification.
	flora_workspace(R,RCode,S),
	(S == [] -> flora_body(L,RCode,WS_FROM_BODY,Code,Status); Status=S).

%% reify op ${...} that occurs as a formula
flora_body(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),_WS,_WSFrom,Code,Status) :-
	get_atom(Funct,Atom),
	is_reifyop(Atom),
	!,
	(N > 1
	-> flora_list_to_conjunct(Args, Conjunct, If, Ip),
	    flora_body(Conjunct,Code,Status)
	;
	    Args = [Arg],
	    flora_body(Arg,Code,Status)
	).

%% Literal is a rule and we are inside reification
flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,[Head,Body],If,Ip),WS,_WSFrom,Code,Status) :-
	get_name(Funct,FL_IMPLYOP),
	if_reifying,
	!,
	( WS==NULL
	->
	    flora_dynrule(CANOTERM(Funct,2,FL_PARENTHESIS,[Head,Body],If,Ip),
			  Code,Status)
	;
	    get_module_from_spec(WS,_Type,Module),
	    flora_wsdynrule(CANOTERM(Funct,2,FL_PARENTHESIS,[Head,Body],If,Ip),
			    Module,Code,Status)
	).

%% At this point, CanoniTerm is not a logical formula.
flora_body(CANOTERM(Funct,1,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status) :-
	get_name(Funct,FL_IF),
	!,
	%% Module name is distributive over if-then-else statement.
        flora_body_ifthenelse(CANOTERM(Funct,1,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status).

flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_WS,_WSFrom,_Code,Status) :-
	get_name(Funct,FL_THEN),
	!,
        parsing_error(If,ERROR_THENBODY,Status).

flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_WS,_WSFrom,_Code,Status) :-
	get_name(Funct,FL_ELSE),
	!,
        parsing_error(If,ERROR_ELSEBODY,Status).

%% Parse the a<-b form of if-then
flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,[IfPart,ThenPart],_If,_Ip),WS,WSFrom,Code,Status) :-
	get_name(Funct,FL_LEFTARROW),
	!,
	flora_leftarrow_implication(IfPart,ThenPart,WS,WSFrom,Code,Status).

%% Parse the ~ meta predicate
flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status) :-
	get_name(Funct,FL_UNIVEQFORM),
	!,
        flora_body_univeqform(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status).

%% Parse the =.. meta predicate
%% Workspace as in (A=..B)@foo is illegal.  But (A@foo =.. B) is fine.
flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status) :-
	get_name(Funct,FL_METAUNIV),
	!,
        flora_body_metauniv(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status).

%% Parse the ~.. meta predicate
%% Workspace as in (A~..B)@foo is illegal.  But (A@foo =.. B) is fine.
flora_body(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WSFrom,WS,Code,Status) :-
	get_name(Funct,FL_METAUNIVFORM),
	!,
        flora_body_metaunivform(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,Ip),WS,WSFrom,Code,Status).

%% Process the control constructs while-do/loop, loop/do-until, unless-do
flora_body(CANOTERM(TopWrapper,1,FL_PARENTHESIS,Args,_If,_Ip),WS,WSFrom,Code,Status) :-
	get_name(TopWrapper,TopName),
	get_control_construct_definition(_CtlWrapper,TopName,_InnerName),
	!,
	%% Args should be [CanonTerm]. If not, will issue a syntax error
	flora_body_controlconstruct(Args,WS,WSFrom,TopName,Code,Status).

%% If inner keyword of ctl construct occurs at the top level -- error
flora_body(CANOTERM(TopWrapper,2,_Paren,_Args,If,_Ip), _WS,_WSFrom,_Code,Status) :-
	get_name(TopWrapper,TopName),
	get_control_construct_definition(_,_,TopName),
	!,
	parsing_error(If,UNEXPECTED_CONTROL,Status).

%% At this point, CanoniTerm is neither a logical formula nor a 
%% if-then-else statement, nor some other special builtin 
%% (like while-loops or meta operators)
flora_body(CanoniTerm,NULL,_WSFrom,Code,Status) :-
	!,
	%% no module name
	flora_body_literal(CanoniTerm,Code,Status).

%% @prolog()
flora_body(CanoniTerm,PROLOGMODULE,_WSFrom,Code,Status) :-
	!,
	%% Prolog builtin
	flora_prlgterm(CanoniTerm,TCode,Status),
	(Status == [] -> flplib_struct(TCode,Code); true).

%% @prolog(...)
flora_body(CanoniTerm,PrologModuleSpec,_WSFrom,Code,Status) :-
	get_module_from_spec(PrologModuleSpec,PROLOGMODULE,Mod),
	!,
	%% Prolog module
	flora_prlgterm(CanoniTerm,TCode,Status),
	(Status == [] -> flmodule_struct(TCode,Mod,PROLOGMODULE,Code); true).

%% @prologall()
flora_body(CanoniTerm,PROLOGALLMODULE,_WSFrom,Code,Status) :-
	!,
	%% Prolog builtin
	flora_pure_term(CanoniTerm,TCode,Status1),
	( is_flvar_struct(TCode)
	-> parsing_error(CanoniTerm,ERROR_PRLGLIT,Status2), Status=Status2
	; Status1 == []
	-> flpliball_struct(TCode,Code), Status=Status1
	; Status=Status1
	).

%% @prologall(...)
flora_body(CanoniTerm,PrologModuleSpec,_WSFrom,Code,Status) :-
	get_module_from_spec(PrologModuleSpec,PROLOGALLMODULE,Mod),
	!,
	%% Prolog module
	flora_pure_term(CanoniTerm,TCode,Status1),
	( is_flvar_struct(TCode)
	-> parsing_error(CanoniTerm,ERROR_PRLGLIT,Status2), Status=Status2
	; Status1 == []
	-> flmodule_struct(TCode,Mod,PROLOGALLMODULE,Code), Status=Status1
	; Status=Status1
	).

%% @module or @flora(...)
flora_body(CanoniTerm,FloraModSpec,WSFrom,Code,Status) :-
	get_module_from_spec(FloraModSpec,ModuleType,Module),
	!,
	%% Flora user or system module
	(PARSER_CONTEXT(parsing_facts), is_flvar_struct(Module)
	-> 
	    %% Variables are not allowed in the module specs in the
	    %% reifications that occur in facts.
	    get_index(Module,Idx),
	    parsing_error(Idx,NO_WS_VAR,Status)
	;
	    flora_body_wsliteral(CanoniTerm,Module,WSFrom,WSFlag,TCode,Status),
	    (Status == [] ->
		( WSFlag == WITH_MODULE ->
	            flmodule_struct(TCode,Module,ModuleType,Code)
		;
		    Code = TCode
		)
	    ; true
	    )
	).

        
/****************************************************************************
  flora_workspace(+CanoniTerm,-WSCode,-Status)

  This predicate is called to parse the module name of a workspace specification.
  Three types of module names are allowed:
  (1) Prolog module, e.g., @prolog(basics), @prolog()
                           @prologall(basics), @prologall()
      WSCode=PROLOGMODULE(name), or PROLOGMODULE
      WSCode=PROLOGALLMODULE(name), or PROLOGALLMODULE
  (2) Flora system module, e.g., @flora(io), @flora(pp). Unlike prolog module,
      @flora() is not allowed.
      WSCode=FLORASYSMOD(name)
  (3) Flora user module, which could be either an atom or a variable.
      WSCode=FLORAUSERMOD(name), or FLORAUSERMOD(var)

  Note: Textual information is reserved for module names.
****************************************************************************/
%% Handle Flora user module specification. (@ M)
flora_workspace(CanoniTerm,FLORAUSERMOD(NVCode),[]) :-
	flora_name_or_normvar(CanoniTerm,NVCode),
	!.

%% Handle THIS MODULE specification, e.g., a[b->c]@ _@.
flora_workspace(CanoniTerm,FLORAUSERMOD(ThisModToken),[]) :-
	%% When _@ is specified as a module, we treat it
	%% syntactically as FLORAUSERMOD because it is an atom
	%% and not flora(...). However, this gets substituted with
	%% FLORA_THIS_MODULE_NAME, so at compile time we get the right
	%% module even if the current module was a system module
	get_spectoken(CanoniTerm,FL_THISMODULE),
	!,
	flobject_struct(CanoniTerm,ThisModToken).

%% Handle a Prolog module. (@ prolog())
flora_workspace(CANOTERM(Mod,0,FL_PARENTHESIS,[],_Ifu,_Ipa),PROLOGMODULE,[]) :-
	get_name(Mod,FL_PLIB),
	!.

flora_workspace(CANOTERM(Mod,1,FL_PARENTHESIS,[M],_Ifu,_Ipa),PROLOGMODULE(MCode),Status) :-
	%% Check if it is a Prolog module. (@prolog(xsbmod))
	get_name(Mod,FL_PLIB),
	!,
	(get_flname_struct(M,MCode) -> Status=[]
	;
	    parsing_error(M,ERROR_WSNAME,Status)).

%% @prologall() workspace
flora_workspace(CANOTERM(Mod,0,FL_PARENTHESIS,[],_Ifu,_Ipa),PROLOGALLMODULE,[]) :-
	get_name(Mod,FL_PLIBALL),
	!.

%% @prologall(module) workspace
flora_workspace(CANOTERM(Mod,1,FL_PARENTHESIS,[M],_Ifu,_Ipa),PROLOGALLMODULE(MCode),Status) :-
	get_name(Mod,FL_PLIBALL),
	!,
	(get_flname_struct(M,MCode) -> Status=[]
	;
	    parsing_error(M,ERROR_WSNAME,Status)
	).

flora_workspace(CANOTERM(Mod,1,FL_PARENTHESIS,[M],_Ifu,_Ipa),FLORASYSMOD(MCode),Status) :-
	%% Check if it is a Flora system module specification. (@flora(mod))
	get_name(Mod,FL_FLORALIB),
	!,
	( get_name(M,MAtom) ->
	    ( flora_system_module(MAtom) ->
		get_flname_struct(M,MCode),
		Status=[]
	    ;
	      parsing_error(M,UNREG_SYSMOD,Status)
	    )
	;
	  parsing_error(M,ERROR_WSNAME,Status)
	).


flora_workspace(CanoniTerm,_WSCode,Status) :-
	parsing_error(CanoniTerm,ERROR_WSNAME,Status).


/****************************************************************************
  flora_body_ifthenelse(+CanoniTerm,+Workspace,+WSFrom,-Code,-Status)

  parses an if-then-else statement. "Workspace" is the module name specified
  for the entire statement and should be distributed over the substatements
  inside.
****************************************************************************/
flora_body_ifthenelse(CanoniTerm,WS,WSFrom,Code,Status) :-
	flora_body_ifthenelse(CanoniTerm,WS,WSFrom,NK,_NT,Code,S),
        ( S \== [] ->
	    Status=S

	; NK == [] ->
	    Status=[]

	; NK = then(Index) ->
	    parsing_error(Index,UNEXPECTED_THEN,Status)

        ; NK = else(Index) ->
	    parsing_error(Index,UNEXPECTED_ELSE,Status)
	).


/****************************************************************************
  flora_body_ifthenelse(+CanoniTerm,+Workspace,+WSFrom,-NextKeyword,-NextTerm,-Code,-Status).

  Takes a canonical term (which represents a stream of tokens) and parses
  a normal statement at the beginning  of it. Moreover, it returns the next
  immediate keyword and the  residual canonical term (which represents the
  rest of the token stream).

  If NextKeyword is [], then NextTerm is []. Otherwise, NextKeyword is
  either then(Index) or else(Index) (here Index is the index number of the
  keyword that can be used to generate an error message).

  Status denotes success/failure when the beginning of the token stream
  is parsed.

  This procedure complements flora_body/5 and handles the distribution of
   module name over if-then-else statements.
****************************************************************************/
flora_body_ifthenelse(CANOTERM(Funct,1,FL_PARENTHESIS,[CTerm],If,_Ip),WS,
		      WSFrom,NextKeyword,NextTerm,Code,Status) :-
	get_name(Funct,FL_IF),
	!,
	flora_body_ifthenelse(CTerm,WS,WSFrom,NK1,NT1,CondStruct,S1),
	( S1 == [] ->
	    ( NK1 = then(_IThen) ->
		flora_body_ifthenelse(NT1,WS,WSFrom,NK2,NT2,ThenStruct,S2), 
		( S2 == [] ->
		    ( NK2 = else(_IElse) ->
			flifthenelse_struct(CondStruct,ThenStruct,ElseStruct,Code),
			flora_body_ifthenelse(NT2,WS,WSFrom,NextKeyword,NextTerm,ElseStruct,Status)
		    ;
		      flifthen_struct(CondStruct,ThenStruct,Code),
		      NextKeyword=NK2,
		      NextTerm=NT2,
		      Status=[]
		    )
		;
	          Status=S2
	        )

	    ; NK1 == [] ->
	        parsing_error(If,MISSING_THEN,Status)

	    ; NK1 = else(IElse) ->
	        parsing_error(IElse,MISSING_THEN,Status)
	    )
        ;
	  Status=S1
	).

flora_body_ifthenelse(CANOTERM(Funct,2,FL_PARENTHESIS,[STerm,NextTerm],If,_Ip),WS,
		      WSFrom,NextKeyword,NextTerm,Code,Status) :-
	( get_name(Funct,FL_THEN) ->
	    NextKeyword=then(If)

	; get_name(Funct,FL_ELSE) ->
	    NextKeyword=else(If)
	),
	!,
	flora_body(STerm,WS,WSFrom,Code,Status).

flora_body_ifthenelse(CanoniTerm,WS,WSFrom,[],[],Code,Status) :-
	flora_body(CanoniTerm,WS,WSFrom,Code,Status).


/*****************************************************************************
   flora_leftarrow_implication(+IfPart,+ThenPart,+WS,+WSFrom,-Code,-Status)
   If-then expressed using <-
*****************************************************************************/
flora_leftarrow_implication(IfPart,ThenPart,WS,WSFrom,Code,Status) :-
	flora_body(IfPart,WS,WSFrom,IfCode,Stat1),
	(Stat1==[]
	-> flora_body(ThenPart,WS,WSFrom,ThenCode,Status),
	    (Status==[]
	    ->
		flifthen_struct(IfCode,ThenCode,Code)
	    ; true
	    )
	;
	    Status = Stat1
	).



/****************************************************************************
  flora_body_univeqform(+CanoniTerm,+WS,+WSFrom,-Code,-Status)

  Parse the meta op ~
****************************************************************************/
flora_body_univeqform(CANOTERM(_Funct,2,FL_PARENTHESIS,Args,_If,_Ip),WS,WSFrom,Code,Status) :-
	protect_reification(flora_distribute_ws(Args,WS,WSFrom,[LCode,RCode],Status)),
	(Status == [] -> fluniveqform_struct(LCode,RCode,Code) ; true).


/****************************************************************************
  flora_body_metauniv(+CanoniTerm,+WS,+WSFrom,-Code,-Status)

  Parse the meta op =..
  (_=.. _)@floramodule, (_ =.. _)@prolog(mod) and (_ =.. _)@prologall(mod)
  are illegal, but
  (_ =.. _)@prolog() and (_ =.. _)@prologall() are legal.
****************************************************************************/
flora_body_metauniv(CANOTERM(_Funct,2,FL_PARENTHESIS,_Args,If,_Ip),WS,WS_FROM_BODY,_Code,Status) :-
	%% only @prolog() and @prologall() are allowed;
	%% they don't match get_module_from_spec/3
	get_module_from_spec(WS,_,_),
	!,
	parsing_error(If,NO_WORKSPACE,Status).

%% If (_ =.. _)@prolog() or (_ =.. _)@prologall(), then use Prolog =..
flora_body_metauniv(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),WS,_WSFrom,Code,Status) :-
	(WS == PROLOGMODULE; WS == PROLOGALLMODULE),
	!,
	Args = [LCode,RCode],
	(WS == PROLOGMODULE
	-> ( flora_prlgterm(LCode,LCodeParsed,S1),
	       (S1 == [] -> flora_pathexp(RCode,RCodeParsed,Status)
	       %% failed to parse the first term
	       ; Status=S1
	       )
	   )
	;  %% PROLOGALLMODULE
	    ( flora_pure_term(LCode,LCodeParsed,S1),
		(S1 == [] -> flora_pure_term(RCode,RCodeParsed,Status)
		%% failed to parse the first term
		; Status=S1
		)
	    )
	),
	%% put together parsed terms using =.. (=Funct)
	(Status == [] ->
	    %% FCode is parsed functor code
	    flobject_struct(Funct,FCode),
	    flterm_struct(FCode,2,[LCodeParsed,RCodeParsed],Code1),
	    %% protect predicate code against hilog conversion
	    ( WS == PROLOGMODULE
	     -> flplib_struct(Code1,Code)
	      %% WS == PROLOGALLMODULE
	     ;  flpliball_struct(Code1,Code)
	    ) 
	%% failed to parse the second term
	; true
	).

flora_body_metauniv(CANOTERM(_Funct,2,FL_PARENTHESIS,Args,_If,_Ip),_WS,_WSFrom,Code,Status) :-
	Args = [Left,Right],
	flora_pathexp(Left,LeftParsed,S1),
	(S1 == [] -> flora_pathexp(Right,RightParsed,Status)
	%% failed to parse the first term
	; Status=S1
	),
	(Status == [] -> flmetauniv_struct(LeftParsed,RightParsed,Code)
	%% failed to parse the second term
	; true
	).


/****************************************************************************
  flora_body_metaunivform(+CanoniTerm,+WS,+WSFrom,-Code,-Status)

  Parse the meta op ~..
  This is like =.. but is compiled differently: the left arg is meta.
  Also, all module specs are illegal:
      (_~.. _)@floramodule, (_ ~.. _)@prolog(mod), (_ ~.. _)@prolog(),
      (_ ~.. _)@prologall(mod), (_ ~.. _)@prologall(),

****************************************************************************/
flora_body_metaunivform(CANOTERM(_Funct,2,FL_PARENTHESIS,_Args,If,_Ip),WS,WS_FROM_BODY,_Code,Status) :-
	(get_module_from_spec(WS,_,_) ; get_module_from_spec(WS,null)),
	!,
	parsing_error(If,NO_WORKSPACE,Status).

flora_body_metaunivform(CANOTERM(_Funct,2,FL_PARENTHESIS,Args,_If,_Ip),_WS,_WSFrom,Code,Status) :-
	Args = [Left,Right],
	protect_reification(flora_body(Left,LeftParsed,S1)),
	(S1 == [] -> flora_pathexp(Right,RightParsed,Status)
	%% failed to parse the first term
	; Status=S1
	),
	(Status == [] -> flmetaunivform_struct(LeftParsed,RightParsed,Code)
	%% failed to parse the second term
	; true
	).

/****************************************************************************
  flora_body_controlconstruct(+CanoniTermList1,+WS,+WSFrom,+TopWrapper,-Code,-Status).
   Process control constructs while-do/loop, loop/do-until, unless-do
   CanoniTermList1 represents the inner part of the control construct,
   e.g., the do-part in while(do(Cond,Action)).
   It should be a singleton list that contains a canonic term.
   TopWrapper is the unary wrapper (whole,do,loop,unless) for the construct
****************************************************************************/
flora_body_controlconstruct([CANOTERM(InnerFunct,2,FL_PARENTHESIS,Args,If,_Ip)],WS,WSFrom,TopWrapper,Code,Status) :-
	get_name(InnerFunct,InnerName),
	!,
	(get_control_construct_definition(StructType,TopWrapper,InnerName), !
	;
	    flora_concat_atoms(['Illegal connective `', InnerName, ''' in `',
			        TopWrapper, ''' construct'],
			       ErrMsg),
	    parsing_error(If,ErrMsg,Status)
	),
	(var(Status)
	-> Args=[Cond,Action],
	    flora_body(Cond,WS,WSFrom,CondCode,S1),
	    (S1== [] -> flora_body(Action,WS,WSFrom,ActionCode,Status)
	    ; Status = S1
	    ),
	    (Status==[]
	    -> flcontrolconstruct_struct(CondCode,ActionCode,StructType,Code)
	    ; true
	    )
	; true % error
	).

%% If wrong number of args or wrong parenthesis - issue an error
flora_body_controlconstruct([CANOTERM(_InnerFunct,_Arity,_Parenthesis,_Args,If,_Ip)],_WS,_WSFrom,TopWrapper,_Code,Status) :-
	flora_concat_atoms(['Illegal syntax in `', TopWrapper, ''' construct'],
			   ErrMsg),
	parsing_error(If,ErrMsg,Status).


flora_body_controlconstruct([SomethingElse],_WS,_WSFrom,TopWrapper,_Code,Status) :-
	get_index(SomethingElse,Idx),
	flora_concat_atoms(['Illegal syntax in `', TopWrapper, ''' construct'],
			   ErrMsg),
	parsing_error(Idx,ErrMsg,Status).



/****************************************************************************
  flora_distribute_ws(+List,+WS,+WSFrom,-TransformedList,-Status)

  Distribute the workspace through a list of formulae
****************************************************************************/
flora_distribute_ws([],_WS,_WSFrom,[],[]) :- !.
flora_distribute_ws([A|Args],WS,WSFrom,[TA|TArgs],Status) :-
	(get_flvar_struct(A,TA), Status1 = [], !
	;
	    flora_body(A,WS,WSFrom,TA,Status1)
	),
	(Status1 == [] -> flora_distribute_ws(Args,WS,WSFrom,TArgs,Status)
	; Status=Status1
	).


/****************************************************************************
  flora_body_literal(+CanoniTerm,-Code,-Status)

  This predicate is called to parse a literal in a rule body, which does
  not associate with any module name specification.
****************************************************************************/
flora_body_literal(CanoniTerm,Code,Status) :-
	flora_exec_directive(CanoniTerm,_WS,_WSFrom,Code,Status),
	!.

%% :(_,_), ::(_,_)
flora_body_literal(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
	flora_pathexplist(Args,[LCode,RCode],Status),
	(Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true).

%% .(_,_), !(_,_), ..(_,_), !!(_,_)
flora_body_literal(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	is_objrefop(F),
	!,
	parsing_error(If,ERROR_BDLITERAL,Status).

%% catch{...}
flora_body_literal(CANOTERM(Funct,3,FL_BRACE,[Goal,Error,Handler],_If,_Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_catchop(Atom),
	!,
	flora_parse_catch(Goal,Error,Handler,Code,Status).

%% throw{...}
flora_body_literal(CANOTERM(Funct,1,FL_BRACE,[Error],_If,_Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_throwop(Atom),
	!,
	flora_parse_throw(Error,Code,Status).

%% p2h{...}
flora_body_literal(CANOTERM(Funct,2,FL_BRACE,[Prolog,Hilog],_If,_Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_p2hop(Atom),
	!,
	flora_parse_p2h(Prolog,Hilog,Code,Status).

%% newoid{...}
flora_body_literal(CANOTERM(Funct,1,FL_BRACE,[VarTerm],_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_newoidop(Atom),
	!,
	(get_flvar_struct(VarTerm,VarCode)
	->
	    flnewoidop_struct(VarCode,Code),
	    Status = []
	; 
	    parsing_error(Ip,EXP_VARIABLE,Status)
	).
	    

%% refresh{...}
flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_tablerefreshop(Atom),
	!,
	(N == 0 ->
	    parsing_error(Ip,EXP_ARGS,Status)
	;
	    flora_tablerefresh(Args,Code,Status)
	).

%% insert{...}
flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_dbinsertop(Atom),
	!,
	( N == 0 ->
	    parsing_error(Ip,EXP_ARGS,Status)
	;
	  flobject_struct(Funct,FCode),
	  flora_dbinsert(FCode,N,Args,Code,Status)
        ).

%% delete{...}
flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_dbdeleteop(Atom),
	!,
	( N == 0 ->
	    parsing_error(Ip,EXP_ARGS,Status)
	;
	  flobject_struct(Funct,FCode),
	  flora_dbdelete(FCode,N,Args,Code,Status)
        ).

%% newmodule{Module}
flora_body_literal(CANOTERM(Funct,1,FL_BRACE,[Arg],_If,Ip),Code,Status) :-
	get_name(Funct,FL_NEWMODULE),
	!,
	flobject_struct(Funct,FCode),
	(flora_name_or_normvar(Arg,MCode)
	-> flnewmodule_struct(FCode,MCode,Code),
	    Status = []
	;
	    parsing_error(Ip,ERROR_WSNAME,Status)
	).

%% caller{Module}
flora_body_literal(CANOTERM(Funct,1,FL_BRACE,[Arg],_If,Ip),Code,Status) :-
	get_name(Funct,FL_CALLERMODULE),
	!,
	flobject_struct(Funct,FCode),
	(flora_name_or_normvar(Arg,VCode)
	-> flcallermodule_struct(FCode,VCode,Code),
	    Status = []
	;
	    parsing_error(Ip,ERROR_WSNAME,Status)
	).


%% insertrule_a{...}, insertrule_z{...}, deleterule_a{...},
%% deleterule_z{...}, or deleterule{...}
flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_ruleupdateop(Atom),
	!,
	( N == 0 ->
	    parsing_error(Ip,EXP_ARGS,Status)
	;
	  flobject_struct(Funct,FCode),
	  flora_ruleupdate(FCode,N,Args,Code,Status)
        ).

%% clause{[Mode,]Head, Body}
flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,_If,Ip),Code,Status) :-
	get_name(Funct,Atom),
	is_clauseop(Atom),
	!,
        (N==2 ->
            Args = [Head,Body],
	    flora_comma_separated_list(Head,HeadList),
	    flora_dbliteral_list(FLCLS,HeadList,HeadCodeList,S),
            ( S == [] ->
                flora_body(Body,BodyCode,Status),
                ( Status == [] ->
                    flclause_struct(HeadCodeList,BodyCode,Code)
                ;
                    true
                )
            ;
                Status = S
            )
        ; N==3 ->
            Args = [Mode,Head,Body],
            flobject_struct(Mode,ModeCode),
            (is_flatom_struct(ModeCode,ModeAtom), valid_clause_mode(ModeAtom) ->
	        flora_comma_separated_list(Head,HeadList),
	        flora_dbliteral_list(FLCLS,HeadList,HeadCodeList,S),
                ( S == [] ->
                    flora_body(Body,BodyCode,Status),
                    ( Status == [] ->
                        flclause_struct(ModeCode,HeadCodeList,BodyCode,Code)
                    ;
                        true
                    )
                ;
                    Status = S
                )
            ;
                parsing_error(Ip,ERROR_CLAUSE,Status)
            )
        ;
            parsing_error(Ip,ERROR_CLAUSE,Status)
        ).
        
valid_clause_mode(STATIC) :- !.
valid_clause_mode(DYNAMIC) :- !.
valid_clause_mode(DYNA) :- !.
valid_clause_mode(DYNZ) :- !.

%% :=:
flora_body_literal(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_OBJEQL),
	!,
	flora_pathexplist(Args,[LCode,RCode],Status),
	(Status == [] -> flobjeql_struct(LCode,RCode,Code); true).

flora_body_literal(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flora_term(Funct,N,Args,Code,Status).

%% ...[...]
flora_body_literal(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_objspec(Funct,N,Args,Code,Status).

flora_body_literal(CANOLIST(L,T,_N,I,_Ib),Code,Status) :-
	!,
	( L == [] ->
	    parsing_error(I,ERROR_LOADLIST,Status)
	;
	  flora_loadlist(L,T,I,C,Status),
	  (Status == [] -> flload_struct(C,Code); true)
	).

%% {...} at the top level -- constraint
flora_body_literal(CANOBRACE(L,_N,_I),Code,Status) :-
	!,
	flora_constraint_list(L,Code,Status).

flora_body_literal(CanoniTerm,Code,[]) :-
	get_atom(CanoniTerm,A),
	!,
	( A == FL_CUT ->
	    get_index(CanoniTerm,I),
	    flcut_struct(I,Code)
	;
	  flobject_struct(CanoniTerm,Code)
        ).

flora_body_literal(CanoniTerm,Code,[]) :-
	get_flvar_struct(CanoniTerm,Code),
	!.

flora_body_literal(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_BDLITERAL,Status).


/****************************************************************************
  flora_body_wsliteral(+CanoniTerm,+FloraModSpec,+WSFrom,-WSFlag,-WorkspaceLiteral,-Status)

  This predicate is called to parse a literal in a rule body, which is
  associated with some module name specification.  If WSFlag is WITH_MODULE,
  then the code needs to be wrapped with the module specification; otherwise
  WSFlag is WITHOUT_MODULE.

  Note: Most builtin FLORA operators are allowed to be associated with
        module name specification.
****************************************************************************/
flora_body_wsliteral(CanoniTerm,FloraModSpec,WSFrom,WITH_MODULE,Code,Status) :-
	flora_exec_directive(CanoniTerm,FloraModSpec,WSFrom,Code,Status),
	!.

flora_body_wsliteral(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),_FloraModSpec,WSFrom,WSFlag,Code,Status) :-
	get_atom(Funct,F),
	!,
	( flora_nowsp(F,N) ->
	    ( WSFrom == WS_FROM_DYNRULE ->
	        flora_body_literal(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,Ip),Code,Status),
		WSFlag = WITHOUT_MODULE
	    ;
		parsing_error(If,NO_WORKSPACE,Status)
	    )

	; N == 2, is_birelop(F) ->
	    WSFlag = WITH_MODULE,
	    flora_pathexplist(Args,[LCode,RCode],Status),
	    (Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true)

	; N == 2, is_objrefop(F) ->
	    parsing_error(If,ERROR_BDLITERAL,Status)

	; N == 2, F == FL_OBJEQL ->
	    WSFlag = WITH_MODULE,
	    flora_pathexplist(Args,[LCode,RCode],Status),
	    (Status == [] -> flobjeql_struct(LCode,RCode,Code); true)

	;
	  WSFlag = WITH_MODULE,
	  flora_term(Funct,N,Args,Code,Status)
        ).

flora_body_wsliteral(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),_FloraModSpec,_WSFrom,WITH_MODULE,Code,Status) :-
	!,
	flora_term(Funct,N,Args,Code,Status).

flora_body_wsliteral(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),_FloraModSpec,_WSFrom,WITH_MODULE,Code,Status) :-
	!,
	flora_objspec(Funct,N,Args,Code,Status).


flora_body_wsliteral(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),_FloraModSpec,_WSFrom,WITHOUT_MODULE,Code,Status) :-
	get_atom(Funct,F),
	((is_dbinsertop(F); is_dbdeleteop(F);
	  is_ruleupdateop(F); is_clauseop(F); is_tablerefreshop(F);
	  is_callermoduleop(F); is_newmoduleop(F))),
	!,
	flora_body_literal(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),Code,Status).

flora_body_wsliteral(CanoniTerm,_FloraModSpec,WSFrom,WSFlag,Code,Status) :-
	get_atom(CanoniTerm,A),
	!,
	( flora_nowsp(A,0) ->
	    ( WSFrom == WS_FROM_DYNRULE ->
		WSFlag = WITHOUT_MODULE,
		flora_body_literal(CanoniTerm,Code,Status)
	    ;
	        parsing_error(CanoniTerm,NO_WORKSPACE,Status)
	    )
	;
	  WSFlag = WITH_MODULE,
	  flobject_struct(CanoniTerm,Code),
	  Status=[]
        ).

flora_body_wsliteral(CANOLIST(L,T,N,I,Ib),_FloraModSpec,WSFrom,WITHOUT_MODULE,Code,Status) :-
	!,
	( WSFrom == WS_FROM_DYNRULE ->
	    flora_body_literal(CANOLIST(L,T,N,I,Ib),Code,Status)
	;
	    parsing_error(I,NO_WORKSPACE,Status)
	).

flora_body_wsliteral(CanoniTerm,_FloraModSpec,_WSFrom,WITH_MODULE,Code,[]) :-
	get_flvar_struct(CanoniTerm,Code),
	!.

flora_body_wsliteral(CanoniTerm,_FloraModSpec,WS_FROM_DYNRULE,WITHOUT_MODULE,Code,Status) :-
	!,
	flora_body_literal(CanoniTerm,Code,Status).

flora_body_wsliteral(CanoniTerm,_FloraModSpec,_WSFrom,_WSFlag,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_BDLITERAL,Status).


/****************************************************************************
  flora_parse_body_template_list(+List,-CodeList,-Status)
****************************************************************************/
flora_parse_body_template_list([],[],[]) :- !.
flora_parse_body_template_list([H|T],[HCode|TCode],Status) :- 
        flora_parse_body_template(H,HCode,S),
        (S == [] ->
            flora_parse_body_template_list(T,TCode,Status)
        ;
            Status = S
        ).


/****************************************************************************
  flora_parse_body_template(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_parse_body_template(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_AT),
        flora_workspace_template(R,RCode,S),
        ( S == [] ->
            flora_parse_body_literal_template(L,LCode,Status),
	    (Status == [] -> 
                get_module_from_spec(RCode,ModuleType,Module),
                flmodule_struct(LCode,Module,ModuleType,Code)
	    ; 
                true
	    )
	; 
            Status = S
        ).

flora_parse_body_template(CanoniTerm,Code,Status) :-
        flora_parse_body_literal_template(CanoniTerm,Code,Status).

/****************************************************************************
  flora_workspace_template(+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_workspace_template(CanoniTerm,FLORAUSERMOD(MCode),[]) :-
%% atomic
        get_flname_struct(CanoniTerm,MCode),
        !.

flora_workspace_template(CanoniTerm,FLORAUSERMOD(MCode),[]) :-
%% anonymous variable
	get_flvar_struct(CanoniTerm,MCode),
        is_anonymous_flvar_struct(MCode),
        !.

flora_workspace_template(CanoniTerm,FLORAUSERMOD(MCode),[]) :-
%% _@
	get_spectoken(CanoniTerm,FL_THISMODULE),
        flobject_struct(CanoniTerm,MCode),
        !.

flora_workspace_template(CANOTERM(Mod,1,FL_PARENTHESIS,[M],_Ifu,_Ipa),FLORASYSMOD(MCode),[]) :-
%% system module
        get_name(Mod,FL_FLORALIB),
        get_name(M,MAtom),
        flora_system_module(MAtom),
        get_flname_struct(M,MCode),
        !.

flora_workspace_template(CanoniTerm,_Code,Status) :-
        parsing_error(CanoniTerm,ERROR_WSNAME,Status).


/****************************************************************************
  flora_parse_body_literal_template(+CanoniTerm,-Code,-Status)
****************************************************************************/
%% :(_,_), ::(_,_)
flora_parse_body_literal_template(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
        ( get_flvar_struct(L,LCode),is_anonymous_flvar_struct(LCode) ->
	    flora_term_template(R,RCode,Status),
	    (Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true)
        ;
	    parsing_error(L,EXP_ANONYVAR,Status)
        ).

%% insert{...} or delete{...}
flora_parse_body_literal_template(CANOTERM(Funct,N,FL_BRACE,Args,_If,_Ip),Code,Status) :-
	get_name(Funct,Atom),
	(is_dbinsertop(Atom),Type=FL_INSERT;
         is_dbdeleteop(Atom),Type=FL_DELETE),
	!,
	flobject_struct(Funct,FCode),
        ( N == 1, Args = [CANOTERM(Bar,2,FL_PARENTHESIS,[L,R],_Ifb,_Ipb)], get_atom(Bar,FL_BAR) ->
	    flora_comma_separated_list(L,LList),
            flora_anonymous_varlist(LList,LCode,Status),
            (Status == [] ->
	        ( get_flvar_struct(R,RCode),is_anonymous_flvar_struct(RCode) ->
                    (Type==FL_INSERT ->
	                flinsert_struct(FCode,LCode,RCode,Code)
                    ;
	                fldelete_struct(FCode,LCode,RCode,Code)
                    )
                ;
	            parsing_error(R,EXP_ANONYVAR,Status)
                )
            ;
	        true
            )
        ;
/*
            Args = [L],
	    flora_comma_separated_list(L,LList),
*/
            flora_anonymous_varlist(Args,LCode,Status),
            (Status == [] ->
                (Type==FL_INSERT ->
                    flinsert_struct(FCode,LCode,Code)
                ;
                    fldelete_struct(FCode,LCode,Code)
                )
            ;
	        true
            )
        ).

%% ...[...]
flora_parse_body_literal_template(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
        ( get_flvar_struct(Funct,OCode), is_anonymous_flvar_struct(OCode) ->
            ( N == 0 ->
                SpecCode=[],
                Status=[]
            ;
		Args=[Spec],
		flora_attmeth_template(Spec,SpecCode,Status)
	    ),
	    (Status == [] -> flobjspec_struct(OCode,SpecCode,Code); true)
        ;
            parsing_error(Funct,EXP_ANONYVAR,Status)
        ).

%% term
flora_parse_body_literal_template(CanoniTerm,Code,Status) :-
        flora_term_template(CanoniTerm,Code,Status),
	!.

flora_parse_body_literal_template(CanoniTerm,Code,Status) :-
	get_flvar_struct(CanoniTerm,Code),
	!,
        ( is_anonymous_flvar_struct(Code) ->
            Status = []
        ;
            parsing_error(CanoniTerm,EXP_ANONYVAR,Status)
        ).

flora_parse_body_literal_template(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_TEMPLATE,Status).


/****************************************************************************
  flora_attmeth_template(+CanoniTerm,-Code,-Status)
  methods and attributes can be term templates, and all other arguments must
  be anonymous variables
****************************************************************************/
flora_attmeth_template(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( is_fdattspecop(F) ->
            ( get_flvar_struct(R,RCode), is_anonymous_flvar_struct(RCode) ->
                flora_pathexp(L,LCode,Status),
	        (Status == [] -> flfdattspec_struct(LCode,F,RCode,Code); true)
            ;
                parsing_error(R,EXP_ANONYVAR,Status)
            )

	; is_mvdattspecop(F) ->
            ( get_flvar_struct(R,RCode), is_anonymous_flvar_struct(RCode) ->
                flora_pathexp(L,LCode,Status),
	        (Status == [] -> flmvdattspec_struct(LCode,F,RCode,Code); true)
            ;
                parsing_error(R,EXP_ANONYVAR,Status)
            )

	; is_incattspecop(F) ->
            ( get_flvar_struct(R,RCode), is_anonymous_flvar_struct(RCode) ->
                flora_pathexp(L,LCode,Status),
	        (Status == [] -> flincattspec_struct(LCode,F,RCode,Code); true)
            ;
                parsing_error(R,EXP_ANONYVAR,Status)
            )

	; is_tolistattspecop(F) ->
            ( get_flvar_struct(R,RCode), is_anonymous_flvar_struct(RCode) ->
                flora_pathexp(L,LCode,Status),
	        (Status == [] -> fltolistattspec_struct(LCode,F,RCode,Code); true)
            ;
                parsing_error(R,EXP_ANONYVAR,Status)
            )
        ),
	!.

flora_attmeth_template(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,FL_AT),
	!,
        ( (get_flname_struct(R,RCode)
	  ;
	      get_flvar_struct(R,RCode),
	      is_anonymous_flvar_struct(RCode)
	  )
	->
	    flora_attmeth_template(L,LCode,S),
	    ( S == [] ->
		( ( is_flattspec_struct(LCode)
		  ; is_flimethspec_struct(LCode)
		  ; is_fltranspec_struct(LCode)
		  ; is_passthru_struct(LCode)
		  )
		->
		      parsing_error(L,NO_WORKSPACE,Status)
		;
		    flmethspec_struct(C,LCode),
		    ( is_flworkspace_struct(C) ->
			parsing_error(If,NO_WSNESTING,Status)
		    ;
			flmodule_struct(C,RCode,FLORAUSERMOD,W),
			flmethspec_struct(W,Code),
			Status=[]
		    )
	        )
	    ;
		Status=S
	    )
	;
	    parsing_error(R,ERROR_WSNAME,Status)
        ).

flora_attmeth_template(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_INMETH),
	!,
	flora_term_template(A,C,Status),
	(Status == [] -> flimethspec_struct(C,Code); true).

flora_attmeth_template(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_TRAN),
	!,
	flora_term_template(A,C,Status),
	(Status == [] -> fltranspec_struct(C,Code); true).

%% Obj[X>Y], Obj[X=Y], etc.
flora_attmeth_template(CanoniTerm,Code,Status) :-
	flora_term_template(CanoniTerm,C,Status),
	flterm_struct(Funct,Arity,_Args,C), % decompose C
	is_flatom_struct(Funct,Atom),
	is_passthru_pred(Atom,Arity),
        !,
	(Status == [] -> flpassthru_struct(C,Code); true).

flora_attmeth_template(CanoniTerm,Code,Status) :-
	flora_term_template(CanoniTerm,C,Status),
	(Status == [] -> flmethspec_struct(C,Code); true).

/****************************************************************************
  flora_term_template(+CanoniTerm,-Code,-Status)
  Term template can be defined recursively:
    1) primitive structures except named variables are all term templates
    2) #Term is a term template is Term is a term template
    3) Term(_,_,...) is a term template is Term is a term template
****************************************************************************/
flora_term_template(CANOTERM(Funct,1,FL_PARENTHESIS,[Term],_If,_Ip),Code,Status) :-
        get_name(Funct,FL_TRAN),
	!,
        flobject_struct(Funct,FCode),
        flora_term_template(Term,TermCode,Status),
        (Status == [] ->
            flterm_struct(FCode,1,[TermCode],Code)
        ;
            true
        ).

flora_term_template(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
        flora_term_template(Funct,F,S),
        ( S == [] ->
            flora_anonymous_varlist(Args,AList,Status),
	    (Status == [] -> flterm_struct(F,N,AList,Code); true)
	;
	  Status=S
        ).

flora_term_template(ObjectTerm,Code,Status) :-
%%  primitive structures except named variables
	flobject_struct(ObjectTerm,Code),
	!,
	(is_flvar_struct(Code), not is_anonymous_flvar_struct(Code) ->
	    parsing_error(ObjectTerm,ERROR_NAMEDVAR,Status)
	;
	    Status = []
	).

flora_term_template(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_TEMPLATE,Status).

/****************************************************************************
  flora_anonymous_varlist(+List,-CodeList,-Status)
  parse a list of anonymous variables
****************************************************************************/
flora_anonymous_varlist([],[],[]) :- !.
flora_anonymous_varlist([H|L],[HCode|LCode],Status) :-
        ( get_flvar_struct(H,HCode), is_anonymous_flvar_struct(HCode) ->
            flora_anonymous_varlist(L,LCode,Status)
        ;
            parsing_error(H,EXP_ANONYVAR,Status)
        ).


/****************************************************************************
  flora_loadlist(+ListPrefix,+ListTail,+Index,-FLLIST,-Status)
****************************************************************************/
flora_loadlist([],[],Index,T,[]) :-
	!,
	fllist_struct([],[],Index,T).

flora_loadlist(L,T,Index,Code,Status) :-
	flora_loaditemlist(L,LCode,S),
	( S == [] ->
	    ( T == [] ->
		TCode=[],
		Status=[]

	    ; T=CANOLIST(List,Tail,_N,I,_Ib) ->
	        flora_loadlist(List,Tail,I,TCode,Status)

	    ; get_flvar_struct(T,TCode) ->
	        Status=[]
	    ;
	      parsing_error(T,ERROR_LOADLIST,Status)
	    ),
	    (Status == [] -> fllist_struct(LCode,TCode,Index,Code); true)
	;
	  Status=S
        ).


flora_loaditemlist([],[],[]) :- !.

flora_loaditemlist([T|L],[TCode|LCode],Status) :-
	flora_loaditem(T,TCode,S),
	(S == [] -> flora_loaditemlist(L,LCode,Status); Status=S).


flora_loaditem(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_RIGHTTO),
	flobject_struct(Funct,FCode),
	!,
	( flora_name_or_normvar(L,LCode) ->
	    ( flora_name_or_normvar(R,RCode) ->
		flterm_struct(FCode,2,[LCode,RCode],Code),
		Status=[]
	    ;
	      parsing_error(R,ERROR_WSNAME,Status)
	    )
	; flora_addfile(L,LCode,_S) ->  % support for adding files to modules
	    ( flora_name_or_normvar(R,RCode) ->
		flterm_struct(FCode,2,[LCode,RCode],Code),
		Status=[]
	    ;
		parsing_error(R,ERROR_WSNAME,Status)
	    )
	;
	    parsing_error(L,ERROR_LOADFILE,Status)
        ).

flora_loaditem(CanoniTerm,Code,[]) :-
	( flora_name_or_normvar(CanoniTerm,Code), !
	;
	    flora_addfile(CanoniTerm,Code,_S)
	),
	!.

flora_loaditem(CanoniTerm,_Code,Status) :-
	!,
	parsing_error(CanoniTerm,ERROR_LOADITEM,Status).


flora_name_or_normvar(CanoniTerm,Code) :-
	( get_flname_struct(CanoniTerm,Code)
        ;
	  get_flvar_struct(CanoniTerm,Code),
	  not is_anonymous_flvar_struct(Code)
        ),
	!.

%% support for adding files to modules
flora_addfile(CANOTERM(Funct,1,FL_PARENTHESIS,[L],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_PLUS),
	flobject_struct(Funct,FCode),
	!,
	( flora_name_or_normvar(L,LCode) ->
	    flterm_struct(FCode,1,[LCode],Code),
	    Status=[]
	;
	    parsing_error(L,ERROR_ADDFILE,Status)
        ).

thismodule_token(CanoniTerm,ThisModToken) :-
	get_spectoken(CanoniTerm,FL_THISMODULE),
	flobject_struct(CanoniTerm,ThisModToken).


/****************************************************************************
    flora_constraint_list(+L,-Code,-Status)
    Add brace to delineate constraints
****************************************************************************/

flora_constraint_list(L,Code,Status) :-
	flora_body_literal_list(L,Lcode,Status),
	flconstraint_struct(Lcode,Code).

flora_body_literal_list([L],Code,Status) :-
	!,
	flora_body_literal(L,Code,Status).

flora_body_literal_list([L|Lits],Code,Status) :-
	flora_body_literal(L,Lcode,S),
	(S == []
	-> flora_body_literal_list(Lits,LitsCode,Status),
	    (Status == [] -> flconjunct_struct(Lcode,LitsCode,Code); true)
	; Status = S
	).



/****************************************************************************
  flora_prlgterm(+CanoniTerm,-Code,-Status)

  This predicate is called to parse a Prolog predicate or prolog term.
  Its arguments can be F-logic molecules and path expressions, so the arguments
  are not parsed as Prolog terms.
****************************************************************************/
flora_prlgterm(CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,_Ip),Code,Status) :-
	!,
	( get_atom(Funct,FAtom) ->
	    ( FAtom == FL_AT, N == 2 ->
		parsing_error(If,NO_WSNESTING,Status)
	    ;
		flora_term(Funct,N,Args,Code,Status)
	    )
	;
	    parsing_error(If,ERROR_PRLGLIT,Status)
        ).

flora_prlgterm(CanoniTerm,Code,[]) :-
	get_flname_struct(CanoniTerm,Code),
	!.

flora_prlgterm(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_PRLGLIT,Status).


/****************************************************************************
  flora_term(+Funct,+Arity,+Args,-Code,-Status)

  Parse a term Funct-spec(Args). Arguments are parsed according to
  the argument spec in flora_argdef. The final parsed term is composed
  using flterm_struct
****************************************************************************/
flora_term(Funct,N,Args,Code,Status) :-
	get_atom(Funct,FAtom), flora_argdef(FAtom,N,ArgTypes),
	!, 
        flobject_struct(Funct,F),
	flora_argpathexplist(Args,ArgTypes,AList,Status), 
        (Status == [] -> flterm_struct(F,N,AList,Code); true).

flora_term(Funct,N,Args,Code,Status) :-
	change_atom_name_if_needed(Funct,Funct1),
	flora_pathexp(Funct1,F,S),
	( S == [] ->
	    flora_pathexplist(Args,AList,Status),
	    (Status == [] -> flterm_struct(F,N,AList,Code); true)
	;
	  Status=S
        ).

/****************************************************************************
  flora_pure_term(+Funct,+Arity,+Args,-Code,-Status)

  Parse a term Funct-spec(Args). Arguments are parsed as terms as well.
  No molecules are allowed, except reified molecules under ${...} and
  those apearing in meta-arguments.
****************************************************************************/
flora_pure_term(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),Code,Status) :-
	get_atom(Funct,Atom),
	is_reifyop(Atom),
	!,
	(N > 1
	-> flora_list_to_conjunct(Args,Conjunct,If,Ip),
	    flora_reify(Conjunct,Code,Status)
	;
	    Args = [Arg],
	    flora_reify(Arg,Code,Status)
	).

flora_pure_term(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,FAtom),
	flora_argdef(FAtom,N,ArgTypes),
	!,
	flobject_struct(Funct,F),
	flora_pure_term_list_with_argdefs(Args,ArgTypes,AList,Status),
	(Status == [] -> flterm_struct(F,N,AList,Code); true).

flora_pure_term(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flobject_struct(Funct,F),
	flora_pure_term_list(Args,AList,Status),
	(Status == [] -> flterm_struct(F,N,AList,Code); true).

flora_pure_term(CANOLIST(L,T,_N,Index,_Ib),Code,Status) :-
	!,
	flora_pure_term_list(L,LCode,LStatus),
	(LStatus == [] ->
	    ( T==[] -> TCode = [], Status = []
	    ;
		flora_pure_term(T,TCode,Status)
	    ),
	    (Status == [] -> fllist_struct(LCode,TCode,Index,Code)
	    ; true
	    )
	;
	  Status=LStatus
        ).

flora_pure_term(CanoniTerm,Code,[]) :-
	flobject_struct(CanoniTerm,Code),
	!.

flora_pure_term(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_HILGTERM,Status).


%% parse list of pure terms
flora_pure_term_list([],[],[]) :- !.
flora_pure_term_list([Arg|Args], [ArgCode|ArgCodeList], Status) :-
	flora_pure_term(Arg,ArgCode,Status1),
	(Status1 == []
	-> flora_pure_term_list(Args,ArgCodeList,Status)
	; Status = Status1
	).

%% parse list of pure terms taking into account argument definitions
%% in which these terms occur (FL_OID or FL_BODYFORMULA)
flora_pure_term_list_with_argdefs([],_,[],[]) :- !.
flora_pure_term_list_with_argdefs([Arg|Args],[FL_OID|ArgsDefs],[ArgCode|ArgCodeList], Status) :-
	flora_pure_term(Arg,ArgCode,Status1),
	(Status1 == []
	-> flora_pure_term_list_with_argdefs(Args,ArgsDefs,ArgCodeList,Status)
	; Status = Status1
	).
flora_pure_term_list_with_argdefs([Arg|Args],[FL_BODYFORMULA|ArgsDefs],[ArgCode|ArgCodeList], Status) :-
	flora_body(Arg,ArgCode,Status1),
	(Status1 == []
	-> flora_pure_term_list_with_argdefs(Args,ArgsDefs,ArgCodeList,Status)
	; Status = Status1
	).


/****************************************************************************
  flora_list(+ListPrefix,+ListTail,+Index,-FLLIST,-Status)

  Index is for '['.
****************************************************************************/
flora_list([],[],Index,T,[]) :-
	!,
	fllist_struct([],[],Index,T).

flora_list(L,T,Index,Code,Status) :-
	flora_pathexplist(L,LCode,S),
	( S == [] ->
	    ( T == [] ->
		TCode=[],
		Status=[]
	    ;
	      flora_pathexp(T,TCode,Status)
	    ),
	    (Status == [] -> fllist_struct(LCode,TCode,Index,Code); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_pathexplist(+ListOfCanoniTerms,-ListOfPathExpressions,-Status)

  parses a list of path expressions that are supposed to represent oids.
****************************************************************************/
flora_pathexplist([],[],[]) :- !.

flora_pathexplist([T|L],[TCode|LCode],Status) :-
	flora_pathexp(T,TCode,S),
	( S == [] ->
	    flora_pathexplist(L,LCode,Status)
	;
	  Status=S
        ).


/****************************************************************************
  flora_argpathexplist(+Terms,+ArgumentTypes,-PathExpressions,-Status)

  parses a list of path expressions according to a list of argument specification
  directives. FL_OID means the oid represented by a path expression while
  FL_BODYFORMULA means the formula represented by a path expression.
****************************************************************************/
flora_argpathexplist([],[],[],[]) :- !.

flora_argpathexplist([T|L],[FL_OID|Arguments],[TCode|LCode],Status) :-
	flora_pathexp(T,TCode,S),
	( S == [] ->
	    flora_argpathexplist(L,Arguments,LCode,Status)
	;
	  Status=S
        ).

flora_argpathexplist([T|L],[FL_BODYFORMULA|Arguments],[TCode|LCode],Status) :-
	protect_reification(flora_body(T,TCode,S)),
	( S == [] ->
	    flora_argpathexplist(L,Arguments,LCode,Status)
	;
	  Status=S
        ).


/****************************************************************************
  flora_pathexp(+CanoniTerm,-PathExpression,-Status)

  Parse path expression represented by CanoniTerm. A path expression is
  oid[molecule].oid[molecule]. ... .oid[molecule]
  (molecules are optional)
****************************************************************************/
flora_pathexp(CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	(is_birelop(F); is_objrefop(F)),
	!,
	flora_pathexplist(Args,[LCode,RCode],Status),
	( Status == [] ->
	    ( is_birelop(F) ->
		flbirelate_struct(LCode,F,RCode,Code)
	    ;
	      flobjref_struct(LCode,F,RCode,Code)
	    )
	;
	  true
        ).

%% DEPRECATED!!
%% This procedure is to handle module specification in the argument position.
%% It might be useful to support meta-programming feature. The distribution
%% and nesting rule for literals in rule body does not apply to arguments. For
%% instance, f((a[b],c[d])@mod) is not allowed.
flora_pathexp(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,FL_AT),
	!,
	%%abort('Parser - DEPRECATED!!'),
	flora_workspace(R,WSCode,S1),
	( S1 == [] ->
	    ( (WSCode = PROLOGMODULE; WSCode = PROLOGMODULE(Mod)) ->
		flora_prlgterm(L,LCode,S2)
	    
	    ; (WSCode = PROLOGALLMODULE; WSCode = PROLOGALLMODULE(Mod)) ->
		flora_pure_term(L,LCode,S2)

	    ; (WSCode = FLORAUSERMOD(Mod); WSCode = FLORASYSMOD(Mod)) ->
	        flora_pathexp(L,LCode,S2)
	    ),
	    %% Check if the module specification is valid.
	    ( S2 == [] ->
		( nowspathexp(LCode) ->
		    parsing_error(L,NO_WORKSPACE,Status)

		; is_flmodulespec_struct(LCode) ->
	            parsing_error(If,NO_WSNESTING,Status)
		;
		  Status=[],
		  ( WSCode = PROLOGMODULE ->
		      %% Covers: @prolog()
		      flplib_struct(LCode,Code)
		  
		  ; WSCode = PROLOGALLMODULE ->
		      %% Covers: @prologall()
		      flpliball_struct(LCode,Code)

		  %% Covers: @mod, @flora(mod), @prolog(mod), @prologall(mod)
		  ; get_module_from_spec(WSCode,ModuleType,Mod) ->
		      flmodule_struct(LCode,Mod,ModuleType,Code)
		  )
	        )
	    ;
	      Status=S2
	    )
	;
	  Status=S1
        ).

flora_pathexp(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flora_term(Funct,N,Args,Code,Status).

flora_pathexp(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_objspec(Funct,N,Args,Code,Status).

flora_pathexp(CANOLIST(L,T,_N,I,_Ib),Code,Status) :-
	!,
	flora_list(L,T,I,Code,Status).

%% ${...} - reification
flora_pathexp(CANOTERM(Funct,N,FL_BRACE,[Arg|Rest],If,Ip),Code,Status) :-
	get_atom(Funct,Atom),
	is_reifyop(Atom),
	!,
	(N > 1 
	-> flora_list_to_conjunct([Arg|Rest], Conjunct, If, Ip),
	    flora_reify(Conjunct,Code,Status)
	;
	    flora_reify(Arg,Code,Status)
	).

flora_pathexp(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),Code,Status) :-
	!,
	flora_aggregt(Funct,N,Args,If,Ip,Code,Status).

flora_pathexp(ObjectTerm,_Code,Status) :-
	%% New oid directive is only allowed in rule heads or reified formulas.
	get_spectoken(ObjectTerm,FL_NEWOID),
	if_not_reifying,
	!,
	parsing_error(ObjectTerm,ERROR_NEWOID,Status).

flora_pathexp(ObjectTerm,Code,[]) :-
	flobject_struct(ObjectTerm,Code),
	!.

flora_pathexp(CANOBRACE(_L,_N,I),_Code,Status) :-
	!,
	parsing_error(I,ERROR_SETNOTE,Status).

flora_pathexp(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_PATHEXP,Status).


%% Define which type of arguments should not have module specification.
nowspathexp(S) :- is_fllist_struct(S), !.
nowspathexp(S) :- is_flaggregt_struct(S), !.
nowspathexp(S) :- is_flreify_struct(S), !.
nowspathexp(S) :- is_flnumber_struct(S), !.
nowspathexp(S) :- is_flstring_struct(S), !.

nowspathexp(S) :-
	is_flatom_struct(S,FAtom),
	flora_nowsp(FAtom,0),
	!.

nowspathexp(S) :-
	flterm_struct(Funct,N,_Args,S),
	is_flatom_struct(Funct,FAtom),
	flora_nowsp(FAtom,N),
	!.


/****************************************************************************
  flora_objspec(+Obj,+Arity,+Args,-Code,-Status)
  flora_objspec(+CanoniTerm,-Code,-Status)

  parses ObjectSpecification as described in the BNF grammar at the
  beginning of this file.
****************************************************************************/
flora_objspec(Obj,N,Args,Code,Status) :-
	flora_pathexp(Obj,O,S),
	( S == [] ->
	    ( N == 0 ->
		Spec=[],
		Status=[]
	    ;
		Args=[Body],
		flora_objspec(Body,Spec,Status)
	    ),
	    (Status == [] -> flobjspec_struct(O,Spec,Code); true)
	;
	  Status=S
        ).


flora_objspec(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	(F == FL_COMMA; F == FL_SEMICOLON; F==FL_AND; F==FL_OR),
	!, %% conjunction or disjunction
	flora_objspec(L,LCode,S),
	( S == [] ->
	    flora_objspec(R,RCode,Status),
	    ( Status == [] ->
		( (F == FL_COMMA ; F==FL_AND) ->
		    flconjunct_struct(LCode,RCode,Code)
		;
		  fldisjunct_struct(LCode,RCode,Code)
	        )
	    ;
	      true
	    )
	;
	  Status=S
        ).

flora_objspec(CANOTERM(Funct,1,FL_PARENTHESIS,[G],_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!, %% negation
	flora_objspec(G,C,Status),
	( Status == [] ->
	    (is_notop(F) -> flnot_struct(C,Code); fltnot_struct(C,Code))
	;
	  true
        ).

flora_objspec(CanoniTerm,Code,Status) :-
	flora_attmethspec(CanoniTerm,Code,Status).
	


/****************************************************************************
  flora_attmethspec(+CanoniTerm,-Goal,-Status)
  flora_setexp(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_attmethspec(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( is_fdattspecop(F) ->
	    flora_pathexplist([L,R],[LCode,RCode],Status),
	    (Status == [] -> flfdattspec_struct(LCode,F,RCode,Code); true)

	; is_mvdattspecop(F) ->
	    flora_pathexp(L,LCode,S),
	    (S == [] -> flora_setexp(R,RCode,Status); Status=S),
	    (Status == [] -> flmvdattspec_struct(LCode,F,RCode,Code); true)

	; is_incattspecop(F) ->
	    flora_pathexplist([L,R],[LCode,RCode],Status),
	    (Status == [] -> flincattspec_struct(LCode,F,RCode,Code); true)

	; is_tolistattspecop(F) ->
	    flora_pathexplist([L,R],[LCode,RCode],Status),
	    (Status == [] -> fltolistattspec_struct(LCode,F,RCode,Code); true)
        ),
	!.

flora_attmethspec(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,FL_AT),
	!,
	( flora_name_or_normvar(R,RCode) ->
	    flora_attmethspec(L,LCode,S),
	    ( S == [] ->
		( ( is_flattspec_struct(LCode)
		  ; is_flimethspec_struct(LCode)
		  ; is_fltranspec_struct(LCode)
		  ; is_passthru_struct(LCode)
		  )
		->
		      parsing_error(L,NO_WORKSPACE,Status)
		;
		    flmethspec_struct(C,LCode),
		    ( is_flworkspace_struct(C) ->
			parsing_error(If,NO_WSNESTING,Status)
		    ;
			flmodule_struct(C,RCode,FLORAUSERMOD,W),
			flmethspec_struct(W,Code),
			Status=[]
		    )
	        )
	    ;
		Status=S
	    )
	;
	    parsing_error(R,ERROR_WSNAME,Status)
        ).

flora_attmethspec(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_INMETH),
	!,
	flora_pathexp(A,C,Status),
	(Status == [] -> flimethspec_struct(C,Code); true).

flora_attmethspec(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_TRAN),
	!,
	flora_pathexp(A,C,Status),
	(Status == [] -> fltranspec_struct(C,Code); true).

%% Obj[true], Obj[fail], Obj[!] - interpreted as true, false, !
flora_attmethspec(CanoniTerm,Code,Status) :-
	flora_pathexp(CanoniTerm,C,Status),
	is_flatom_struct(C,Atom),
	is_passthru_atom(Atom),
        !,
	(Status == [] -> flpassthru_struct(C,Code); true).

%% Obj[X>Y], Obj[X=Y], etc.
flora_attmethspec(CanoniTerm,Code,Status) :-
	flora_pathexp(CanoniTerm,C,Status),
	flterm_struct(Funct,Arity,_Args,C), % decompose C
	is_flatom_struct(Funct,Atom),
	is_passthru_pred(Atom,Arity),
        !,
	(Status == [] -> flpassthru_struct(C,Code); true).

flora_attmethspec(CanoniTerm,Code,Status) :-
	flora_pathexp(CanoniTerm,C,Status),
	(Status == [] -> flmethspec_struct(C,Code); true).


flora_setexp(CANOBRACE(L,_N,_I),Code,Status) :-
	!,
	flora_pathexplist(L,Code,Status).

flora_setexp(CanoniTerm,[Code],Status) :-
	flora_pathexp(CanoniTerm,Code,Status).


/****************************************************************************
  flora_aggregt(+Funct,+Arity,+Args,+IndxFunct,+IndxBrace,-Code,-Status)
  aggregt_vars(+CanoniTerm,-Var,-GroupVars,-Status)
  var_list(+List,-GroupVars,-Status)
****************************************************************************/
flora_aggregt(Funct,N,Args,If,Ip,Code,Status) :-
	( get_name(Funct,FAtom), is_aggregtop(FAtom) ->
	    flobject_struct(Funct,F),
	    ( N == 1, Args=[CANOTERM(Bar,2,FL_PARENTHESIS,[L,R],_Il,_Ir)],
	      get_atom(Bar,FL_BAR) ->
	        aggregt_vars(L,Var,GroupVars,S),
		( S == [] ->
		    flora_body(R,Conds,Status),
		    ( Status == [] ->
			flaggregt_struct(F,Var,GroupVars,Conds,Code)
		    ;
		      true
		    )
		;
		  Status=S
	        )
	    ;
	      parsing_error(Ip,ERROR_AGGREGT,Status)
	    )

	; get_name(Funct,FAtom),
	    (is_dbinsertop(FAtom); is_dbdeleteop(FAtom); is_ruleupdateop(FAtom)) ->
	    parsing_error(If,ERROR_UPDATEOP,Status)
	;
	  parsing_error(If,UNKNOWN_AGGREGT,Status)
        ).


aggregt_vars(Term,Var,[],[]) :-
	get_flvar_struct(Term,Var),
	!.

aggregt_vars(CANOTERM(Funct,N,FL_BRACKET,L,If,_Ip),Var,GroupVars,Status) :-
	!,
	( get_flvar_struct(Funct,Var) ->
	    ( N == 0 ->
		GroupVars=[],
		Status=[]
	    ;
	      L=[T],
	      var_list(T,GroupVars,Status)
	    )
	;
	  parsing_error(If,EXP_AGGREGVAR,Status)
        ).

aggregt_vars(CanoniTerm,_V,_GV,Status) :-
	parsing_error(CanoniTerm,EXP_AGGRGRPVAR,Status).


var_list(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),[Var|GV],Status) :-
	get_atom(Funct,F),
	!,
	( F == FL_COMMA ->
	    ( get_flvar_struct(L,Var) ->
		var_list(R,GV,Status)
	    ;
	      parsing_error(L,EXP_VARIABLE,Status)
	    )

	; F == FL_BAR ->
	    parsing_error(If,NO_LISTTAIL,Status)

	;
	  parsing_error(If,EXP_VARIABLE,Status)
        ).

var_list(CanoniTerm,[Var],Status) :-
	( get_flvar_struct(CanoniTerm,Var) ->
	    Status=[]
	;
	  parsing_error(CanoniTerm,EXP_VARIABLE,Status)
        ).


/****************************************************************************
  flora_head_term(+Funct,+Arity,+Args,-Code,-Status)

  This predicate is called to parse a term in a rule head. Parsing of its
  arguments is adjusted according to its arguments mode definition.
****************************************************************************/
flora_head_term(Funct,N,Args,Code,Status) :-
	get_atom(Funct,FAtom),
	flora_argdef(FAtom,N,ArgTypes),
	!,
	flobject_struct(Funct,F),
	flora_head_argpathexplist(Args,ArgTypes,AList,Status),
	(Status == [] -> flterm_struct(F,N,AList,Code); true).


flora_head_term(Funct,N,Args,Code,Status) :-
	flora_head_pathexp(Funct,F,S),
	( S == [] ->
	    flora_head_pathexplist(Args,AList,Status),
	    (Status == [] -> flterm_struct(F,N,AList,Code); true)
	;
	  Status=S
        ).


/**************.*******************************.*****************************
 flora_head_list(+ListPrefix,+ListTail,+Index,-FLLIST,-Status)
****************************************************************************/
flora_head_list([],[],Index,T,[]) :-
	!,
	fllist_struct([],[],Index,T).

flora_head_list(L,T,Index,Code,Status) :-
	flora_head_pathexplist(L,LCode,S),
	( S == [] ->
	    ( T == [] ->
		TCode=[],
		Status=[]
	    ;
	      flora_head_pathexp(T,TCode,Status)
	    ),
	    (Status == [] -> fllist_struct(LCode,TCode,Index,Code); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_head_argpathexplist(+Terms,+ArgumentTypes,-PathExpressions,-Status)
****************************************************************************/
flora_head_argpathexplist([],[],[],[]) :- !.

flora_head_argpathexplist([T|L],[FL_OID|Arguments],[TCode|LCode],Status) :-
	flora_head_pathexp(T,TCode,S),
	( S == [] ->
	    flora_head_argpathexplist(L,Arguments,LCode,Status)
	;
	  Status=S
        ).

flora_head_argpathexplist([T|L],[FL_BODYFORMULA|Arguments],[TCode|LCode],Status) :-
	flora_body(T,TCode,S),
	( S == [] ->
	    flora_head_argpathexplist(L,Arguments,LCode,Status)
	;
	  Status=S
        ).


/****************************************************************************
  flora_head_pathexplist(+ListOfCanoniTerms,-ListOfPathExpressions,-Status)
****************************************************************************/
flora_head_pathexplist([],[],[]) :- !.

flora_head_pathexplist([T|L],[TCode|LCode],Status) :-
	flora_head_pathexp(T,TCode,S),
	( S == [] ->
	    flora_head_pathexplist(L,LCode,Status)
	;
	  Status=S
        ).


/****************************************************************************
  flora_head_pathexp(+CanoniTerm,-HeadPathExpression,-Status)
****************************************************************************/
flora_head_pathexp(CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	!,
	( (is_birelop(F); is_fdobjrefop(F)) ->
	    flora_head_pathexplist(Args,[LCode,RCode],Status),
	    ( Status == [] ->
		( is_birelop(F) ->
		    flbirelate_struct(LCode,F,RCode,Code)
		;
		  flobjref_struct(LCode,F,RCode,Code)
	        )
	    ;
	      true
	    )

	; is_mvdobjrefop(F) ->
	    parsing_error(If,NO_MULTIATT,Status)

	; F == FL_AT ->
	    %% Module specs for F-logic molecules in the head are not allowed.
	    parsing_error(If,NO_WSINRULEHEAD,Status)
	;
	  flora_head_term(Funct,2,Args,Code,Status)
        ).

flora_head_pathexp(CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flora_head_term(Funct,N,Args,Code,Status).

flora_head_pathexp(CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_head_objspec(Funct,N,Args,Code,Status).

flora_head_pathexp(CANOLIST(L,T,_N,I,_Ib),Code,Status) :-
	!,
	flora_head_list(L,T,I,Code,Status).

flora_head_pathexp(ObjectTerm,Code,[]) :-
	flobject_struct(ObjectTerm,Code),
	!.

%% ${...} - reification
flora_head_pathexp(CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),Code,Status) :-
	get_atom(Funct,Atom),
	is_reifyop(Atom),
	!,
	(N > 1
	-> flora_list_to_conjunct(Args,Conjunct,If,Ip),
	    flora_reify(Conjunct,Code,Status)
	;
	    Args = [Arg],
	    flora_reify(Arg,Code,Status)
	).

flora_head_pathexp(CANOTERM(_Funct,_N,FL_BRACE,_Args,_If,Ip),_Code,Status) :-
	!,
	parsing_error(Ip,NO_AGGINHEAD,Status).

flora_head_pathexp(CANOBRACE(_L,_N,I),_Code,Status) :-
	!,
	parsing_error(I,ERROR_SETNOTE,Status).

flora_head_pathexp(CanoniTerm,_Code,Status) :-
	parsing_error(CanoniTerm,ERROR_EXPINHEAD,Status).


/****************************************************************************
  flora_head_objspec(+Obj,+Arity,+Args,-Code,-Status)
  flora_head_objspec(+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_head_objspec(Obj,N,Args,Code,Status) :-
	flora_head_pathexp(Obj,O,S),
	( S == [] ->
	    ( N == 0 ->
		Spec=[],
		Status=[]
	    ;
	      Args=[Body],
	      flora_head_objspec(Body,Spec,Status)
	    ),
	    (Status == [] -> flobjspec_struct(O,Spec,Code); true)
	;
	  Status=S
        ).


flora_head_objspec(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( (F == FL_COMMA ; F==FL_AND) ->
	    flora_head_objspec(L,LCode,S),
	    ( S == [] ->
		flora_head_objspec(R,RCode,Status),
		(Status == [] -> flconjunct_struct(LCode,RCode,Code); true)
	    ;
	      Status=S
	    )
	;
	  (F == FL_SEMICOLON ; F==FL_OR),
	  parsing_error(If,NO_DISJUNCTION,Status)
        ),
	!.

flora_head_objspec(CANOTERM(Funct,1,FL_PARENTHESIS,[_G],If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!,
	parsing_error(If,NO_NEGATION,Status).

flora_head_objspec(CanoniTerm,Code,Status) :-
	flora_head_attmethspec(CanoniTerm,Code,Status).


/****************************************************************************
  flora_head_attmethspec(+CanoniTerm,-Goal,-Status)
  flora_head_setexp(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_head_attmethspec(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( is_fdattspecop(F) ->
	    flora_head_pathexplist([L,R],[LCode,RCode],Status),
	    (Status == [] -> flfdattspec_struct(LCode,F,RCode,Code); true)

	; is_mvdattspecop(F) ->
	    flora_head_pathexp(L,LCode,S),
	    (S == [] -> flora_head_setexp(R,RCode,Status); Status=S),
	    (Status == [] -> flmvdattspec_struct(LCode,F,RCode,Code); true)

	; (is_incattspecop(F); is_tolistattspecop(F)) ->
	    parsing_error(If,ERROR_HDLITERAL,Status)
        ;
	  F == FL_AT,
	  parsing_error(If,NO_WSINRULEHEAD,Status)
        ),
	!.

flora_head_attmethspec(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_INMETH),
	!,
	flora_head_pathexp(A,C,Status),
	(Status == [] -> flimethspec_struct(C,Code); true).

flora_head_attmethspec(CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_TRAN),
	!,
	flora_head_pathexp(A,C,Status),
	(Status == [] -> fltranspec_struct(C,Code); true).

flora_head_attmethspec(CanoniTerm,Code,Status) :-
	flora_head_pathexp(CanoniTerm,C,Status),
	(Status == [] -> flmethspec_struct(C,Code); true).


flora_head_setexp(CANOBRACE(L,_N,_I),CodeList,Status) :-
	!,
	flora_head_pathexplist(L,CodeList,Status).

flora_head_setexp(CanoniTerm,[Code],Status) :-
	flora_head_pathexp(CanoniTerm,Code,Status).


/****************************************************************************
  flora_tablerefresh(+ArgsList,-Code,-Status)
****************************************************************************/

flora_tablerefresh(Args,Code,Status) :-
	flora_dbliteral_list(FLREF,Args,CodeList,Status),
	(Status == []
	-> flrefresh_struct(CodeList,Code)
	; true
	).


/****************************************************************************
  flora_dbinsert(+OpCode,+N,+ArgsList,-Code,-Status)
****************************************************************************/
flora_dbinsert(OpCode,1,[CANOTERM(Bar,2,FL_PARENTHESIS,[L,R],_If,_Ip)],Code,Status) :-
	get_atom(Bar,FL_BAR),
	!,
	flora_comma_separated_list(L,LList),
	flora_dbliteral_list(FLINS,LList,LCodeList,S),
	( S == [] ->
	    flora_body(R,RCode,Status),
	    (Status == []
	    -> flinsert_struct(OpCode,LCodeList,RCode,Code)
	    ; true
	    )
	;
	  Status=S
        ).

flora_dbinsert(OpCode,_N,Args,Code,Status) :-
	flora_dbliteral_list(FLINS,Args,CodeList,Status),
	(Status == []
	-> flinsert_struct(OpCode,CodeList,Code)
	; true
	).


/****************************************************************************
  flora_dbdelete(+OpCode,+N,+Args,-Code,-Status)
****************************************************************************/
flora_dbdelete(OpCode,1,[CANOTERM(Bar,2,FL_PARENTHESIS,[L,R],_If,_Ip)],Code,Status) :-
	get_atom(Bar,FL_BAR),
	!,
	flora_comma_separated_list(L,LList),
	flora_dbliteral_list(FLDEL,LList,LCodeList,S),
	( S == [] ->
	    flora_body(R,RCode,Status),
	    (Status == []
	    ->
		fldelete_struct(OpCode,LCodeList,RCode,Code)
	    ;
		true
	    )
	;
	  Status=S
        ).

flora_dbdelete(OpCode,_N,Args,Code,Status) :-
	flora_dbliteral_list(FLDEL,Args,CodeList,Status),
	(Status == []
	->
	    fldelete_struct(OpCode,CodeList,Code)
	; true
	).

/****************************************************************************
  flora_dbliteral_list(+Mode,+ArgsList,-CodeList,-Status)

  flora_dbliteral_list/4 is for both insert and delete literals. The
  value of Mode can be either FLINS (insert) or FLDEL (delete). The
  difference between insert and delete literals is that insert literals
  cannot contain multivalued reference whereas delete literals can.
****************************************************************************/
flora_dbliteral_list(_Mode,[],[],[]) :- !.

flora_dbliteral_list(Mode,[H|T],CodeList,Status) :-
	!,
	flora_dbliteral(Mode,H,HCL,S),
	( S == [] ->
	    flora_dbliteral_list(Mode,T,TCL,Status),
	    (Status == [] -> append(HCL,TCL,CodeList); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_dbliteral(+Mode,+CanoniTerm,-CodeList,-Status)

  Note: Module names are allowed in insert/delete literals.
****************************************************************************/
flora_dbliteral(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),CodeList,Status) :-
	get_atom(Funct,FL_AT),
	!,
	%% Module name, Var, or special token _@
	( (flora_name_or_normvar(R,RCode)
	  ; thismodule_token(R,RCode)
	  %% ; flora_workspace(R,RCode,S), S==[]
	  )
	->
	    flora_comma_separated_list(L,LList),
	    flora_dbwsliteral_list(Mode,LList,RCode,CodeList,Status)
	; % illegal module name
	  parsing_error(R,ERROR_WSNAME,Status)
	).

flora_dbliteral(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),CodeList,Status) :-
	(get_atom(Funct,FL_COMMA) ; get_atom(Funct,FL_AND)),
	!,
	flora_dbliteral(Mode,L,LCode,S),
	(S==[] ->
	    flora_dbliteral(Mode,R,RCode,Status),
	    append(LCode,RCode,CodeList)
	; S == Status
	).

flora_dbliteral(Mode,CanoniTerm,[Code],Status) :-
	flora_dblit(Mode,CanoniTerm,Code,Status).


/****************************************************************************
  flora_dbwsliteral_list(+Mode,+CanoniTermList,+WS,-CodeList,-Status)
****************************************************************************/
flora_dbwsliteral_list(_Mode,[],_WS,[],[]) :- !.

flora_dbwsliteral_list(Mode,[H|T],WS,CodeList,Status) :-
	!,
	flora_dbwsliteral(Mode,H,WS,HCodeList,S),
	( S == [] ->
	    flora_dbwsliteral_list(Mode,T,WS,TCodeList,Status),
	    (Status == [] -> append(HCodeList,TCodeList,CodeList); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_dbwsliteral(+Mode,+CanoniTerm,+WS,-CodeList,-Status)
****************************************************************************/
flora_dbwsliteral(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),_WS,CodeList,Status) :-
	get_atom(Funct,FL_AT),
	!,
	%% nested module name
	%% Module name, Var, or special token _@
	( (flora_name_or_normvar(R,RCode)
	  ; thismodule_token(R,RCode)
	  )
	->
	    flora_comma_separated_list(L,LList),
	    flora_dbwsliteral_list(Mode,LList,RCode,CodeList,Status)
	; % illegal module name
	  parsing_error(R,ERROR_WSNAME,Status)
        ).

flora_dbwsliteral(Mode,CanoniTerm,WS,[WSCode],Status) :-
	flora_dbwslit(Mode,CanoniTerm,Code,Status),
	(get_module_from_spec(WS,ModuleType,Module)
	-> % this one is primarily for system modules
	    flmodule_struct(Code,Module,ModuleType,WSCode)
	;  % variable, atom-module, _@
	    flmodule_struct(Code,WS,FLORAUSERMOD,WSCode)
	).


/****************************************************************************
        flora_reify(+Arg,-Code,-Status)
	Handle reification, ${...}
****************************************************************************/
flora_reify(Arg,Code,Status) :-
	protect_reification(flora_body(Arg,ArgCode,Status)),
	(Status == [] -> flreify_struct(ArgCode,Code); true).


/****************************************************************************
        flora_parse_catch(Goal,Error,Handler,Code,Status)
	Handle catch{Goal,Error,Handler}
****************************************************************************/
flora_parse_catch(Goal,Error,Handler,Code,Status) :-
	flora_body(Goal,GoalCode,GoalStatus),
	(GoalStatus == []
	-> flora_pure_term(Error,ErrorCode,ErrorStatus),
	    (ErrorStatus == []
	    -> flora_body(Handler,HandlerCode,Status),
		(Status == []
		-> flcatch_struct(GoalCode,ErrorCode,HandlerCode,Code)
		; true
		)
	    ; Status = ErrorStatus
	    )
	; Status = GoalStatus
	).

/****************************************************************************
        flora_parse_throw(Error,Code,Status)
	Handle throw{Error}
****************************************************************************/
flora_parse_throw(Error,Code,Status) :-
	flora_pure_term(Error,ErrCode,Status),
	(Status == []
	-> flthrow_struct(ErrCode,Code)
	; true
	).

/****************************************************************************
        flora_parse_p2h(Prolog,Hilog,Code,Status)
	Handle p2h{Prolog,Hilog}
****************************************************************************/
flora_parse_p2h(Prolog,Hilog,Code,Status) :-
	flora_pure_term(Prolog,PrlgCode,PrlgStatus),
	(PrlgStatus == []
	-> flora_pure_term(Hilog,HlgCode,Status),
	    (Status == []
	    -> flp2h_struct(PrlgCode,HlgCode,Code)
	    ; true
	    )
	; Status = PrlgStatus
	).


/****************************************************************************
   The following flora_check_update_* statements make sure that builtins
   and other inappropriate things don't occur in update statements.
****************************************************************************/

/****************************************************************************
  flora_check_update_builtin(+Mode,+CanoniTerm,-Status)
****************************************************************************/
flora_check_update_builtin(Mode,CANOTERM(Funct,N,FL_PARENTHESIS,_Args,If,_Ip),Status) :-
	get_atom(Funct,F),
	flora_nodefp(F,N),
	( Mode == FLINS ->
	    parsing_error(If,NO_INSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(If,NO_DELETE,Status)
        ; 
          parsing_error(If,ERROR_BUILTIN,Status)
	).


/****************************************************************************
  flora_check_update_ifthenelse(+CanoniTerm,-Status)
****************************************************************************/
/*
flora_check_update_ifthenelse(CANOTERM(Funct,1,FL_PARENTHESIS,_Args,If,_Ip),Status) :-
        get_name(Funct,FL_IF),
        !,
        parsing_error(If,NO_UPDATEIF,Status).

flora_check_update_ifthenelse(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),Status) :-
        get_name(Funct,FL_THEN),
        !,
        parsing_error(If,NO_UPDATETHEN,Status).

flora_check_update_ifthenelse(CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),Status) :-
        get_name(Funct,FL_ELSE),
        !,
        parsing_error(If,NO_UPDATEELSE,Status).
*/


/****************************************************************************
  flora_dblit(+Mode,+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_dblit(Mode,CanoniTerm,_Code,Status) :-
	flora_check_update_builtin(Mode,CanoniTerm,Status),
	!.

flora_dblit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true).

flora_dblit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	is_objrefop(F),
	!,
	( Mode == FLINS ->
	    parsing_error(If,ERROR_INSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(If,ERROR_DELETE,Status)
        ;
          Mode == FLREF,
          parsing_error(If,ERROR_REFRESH,Status)
        ;
          Mode == FLCLS,
          parsing_error(If,ERROR_CLAUSE,Status)
	).

flora_dblit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_OBJEQL),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flobjeql_struct(LCode,RCode,Code); true).

/*
flora_dblit(_Mode,CanoniTerm,_Code,Status) :-
	flora_check_update_ifthenelse(CanoniTerm,Status),
	!.

flora_dblit(_Mode,CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
        get_name(Funct,FL_THEN),
        !,
        parsing_error(If,NO_UPDATETHEN,Status).

flora_dblit(_Mode,CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
        get_name(Funct,FL_ELSE),
        !,
        parsing_error(If,NO_UPDATEELSE,Status).
*/



flora_dblit(Mode,CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,_Ip),Code,Status) :-
	!,
	( get_atom(Funct,F), flora_prlgdef(F,N) ->
	    parsing_error(If,NO_PROLOG,Status)
	;
	  flora_db_term(Mode,Funct,N,Args,Code,Status)
	).

flora_dblit(Mode,CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_db_objspec(Mode,Funct,N,Args,Code,Status).

flora_dblit(Mode,CanoniTerm,Code,Status) :-
	get_atom(CanoniTerm,A),
	!,
	( flora_nodefp(A,0) ->
	    ( Mode == FLINS ->
		parsing_error(CanoniTerm,NO_INSERT,Status)
	    ;
	      Mode == FLDEL,
	      parsing_error(CanoniTerm,NO_DELETE,Status)
            ;
              parsing_error(CanoniTerm,ERROR_BUILTIN,Status)
	    )

	; flora_prlgdef(A,0) ->
	    parsing_error(CanoniTerm,NO_PROLOG,Status)
	;
	  flobject_struct(CanoniTerm,Code),
	  Status=[]
        ).

flora_dblit(_Mode,CanoniTerm,Code,[]) :-
	get_flvar_struct(CanoniTerm,Code),
	not is_anonymous_flvar_struct(Code),
	!.

flora_dblit(Mode,CanoniTerm,_Code,Status) :-
	!,
	( Mode == FLINS ->
	    parsing_error(CanoniTerm,ERROR_INSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(CanoniTerm,ERROR_DELETE,Status)
        ;
          Mode == FLREF,
          parsing_error(CanoniTerm,ERROR_REFRESH,Status)
        ;
          Mode == FLCLS,
          parsing_error(CanoniTerm,ERROR_CLAUSE,Status)
        
	).


/****************************************************************************
  flora_dbwslit(+Mode,+CanoniTerm,-Code,-Status)

  Note: Updating Prolog predicates is not allowed. But explicit module name
        specification overrides the Prolog directive.
****************************************************************************/
flora_dbwslit(Mode,CanoniTerm,_Code,Status) :-
	flora_check_update_builtin(Mode,CanoniTerm,Status),
	!.

flora_dbwslit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true).

flora_dbwslit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,_Args,If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	is_objrefop(F),
	!,
	( Mode == FLINS ->
	    parsing_error(If,ERROR_INSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(If,ERROR_DELETE,Status)
	;
	  Mode == FLREF,
	  parsing_error(If,ERROR_REFRESH,Status)
	;
	  Mode == FLCLS,
	  parsing_error(If,ERROR_CLAUSE,Status)
	).

flora_dbwslit(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_OBJEQL),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flobjeql_struct(LCode,RCode,Code); true).


flora_dbwslit(Mode,CANOTERM(Funct,N,FL_PARENTHESIS,Args,If,_Ip),Code,Status) :-
	!,
	( get_atom(Funct,F), flora_nowsp(F,N) ->
	    parsing_error(If,NO_WORKSPACE,Status)
	;
	  flora_db_term(Mode,Funct,N,Args,Code,Status)
	).

flora_dbwslit(Mode,CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_db_objspec(Mode,Funct,N,Args,Code,Status).

flora_dbwslit(Mode,CanoniTerm,Code,Status) :-
	get_atom(CanoniTerm,A),
	!,
	( flora_nodefp(A,0) ->
	    ( Mode == FLINS ->
		parsing_error(CanoniTerm,NO_INSERT,Status)
	    ;
	      Mode == FLDEL,
	      parsing_error(CanoniTerm,NO_DELETE,Status)
            ; parsing_error(CanoniTerm,ERROR_BUILTIN,Status)
	    )

	; flora_nowsp(A,0) ->
	    parsing_error(CanoniTerm,NO_WORKSPACE,Status)
	;
	  flobject_struct(CanoniTerm,Code),
	  Status=[]
        ).

flora_dbwslit(_Mode,CanoniTerm,Code,[]) :-
	get_flvar_struct(CanoniTerm,Code),
	not is_anonymous_flvar_struct(Code),
	!.

/**** allow insert{Var@Mod}
flora_dbwslit(_Mode,CanoniTerm,_Code,Status) :-
	get_flvar_struct(CanoniTerm,_V),
	!,
	parsing_error(CanoniTerm,NO_WORKSPACE,Status).
****/

flora_dbwslit(Mode,CanoniTerm,_Code,Status) :-
	!,
	( Mode == FLINS ->
	    parsing_error(CanoniTerm,ERROR_INSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(CanoniTerm,ERROR_DELETE,Status)
	;
	  Mode == FLREF,
	  parsing_error(CanoniTerm,ERROR_REFRESH,Status)
	;
	  Mode == FLCLS,
	  parsing_error(CanoniTerm,ERROR_CLAUSE,Status)
	).


/****************************************************************************
  flora_db_term(+Mode,+Funct,+Arity,+Args,-Code,-Status)
****************************************************************************/
flora_db_term(Mode,Funct,N,Args,Code,Status) :-
	flora_db_pathexp(Mode,Funct,F,S),
	( S == [] ->
	    flora_db_pathexplist(Mode,Args,AList,Status),
	    (Status == [] -> flterm_struct(F,N,AList,Code); true)
	;
	  Status=S
        ).


/**********************************************.*****************************
  flora_db_list(+Mode,+ListPrefix,+ListTail,+Index,-FLLIST,-Status)
****************************************************************************/
flora_db_list(_Mode,[],[],Index,T,[]) :-
	!,
	fllist_struct([],[],Index,T).

flora_db_list(Mode,L,T,Index,Code,Status) :-
	flora_db_pathexplist(Mode,L,LCode,S),
	( S == [] ->
	    ( T == [] ->
		TCode=[],
		Status=[]
	    ;
	      flora_db_pathexp(Mode,T,TCode,Status)
	    ),
	    (Status == [] -> fllist_struct(LCode,TCode,Index,Code); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_db_pathexplist(+Mode,+ListOfCanoniTerms,-ListOfPathExpressions,-Status)
****************************************************************************/
flora_db_pathexplist(_Mode,[],[],[]) :- !.

flora_db_pathexplist(Mode,[T|L],[TCode|LCode],Status) :-
	flora_db_pathexp(Mode,T,TCode,S),
	( S == [] ->
	    flora_db_pathexplist(Mode,L,LCode,Status)
	;
	  Status=S
        ).


/****************************************************************************
  flora_db_pathexp(+Mode,+CanoniTerm,-InsertPathExpression,-Status)
****************************************************************************/
flora_db_pathexp(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_birelop(F),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flbirelate_struct(LCode,F,RCode,Code); true).

flora_db_pathexp(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_fdobjrefop(F),
	!,
	flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	(Status == [] -> flobjref_struct(LCode,F,RCode,Code); true).

flora_db_pathexp(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,Args,If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	is_mvdobjrefop(F),
	!,
	( Mode == FLINS ->
	    parsing_error(If,NO_INSERTMULATT,Status)
	;
	  (Mode==FLDEL; Mode==FLREF; Mode==FLCLS),
	  flora_db_pathexplist(Mode,Args,[LCode,RCode],Status),
	  (Status == [] -> flobjref_struct(LCode,F,RCode,Code); true)
	).

flora_db_pathexp(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,FL_AT),
	!,
	( (flora_name_or_normvar(R,RCode) ; thismodule_token(R,RCode))
	->
	    flora_db_pathexp(Mode,L,LCode,S),
	    ( S == [] ->
		( is_flworkspace_struct(LCode) ->
		    parsing_error(If,NO_WSNESTING,Status)

		; nowspathexp(LCode) ->
		    parsing_error(L,NO_WORKSPACE,Status)
		;
		  flmodule_struct(LCode,RCode,FLORAUSERMOD,Code),
		  Status=[]
	        )
	    ;
	      Status=S
	    )
	;
	  parsing_error(R,ERROR_WSNAME,Status)
        ).

flora_db_pathexp(Mode,CANOTERM(Funct,N,FL_PARENTHESIS,Args,_If,_Ip),Code,Status) :-
	!,
	flora_db_term(Mode,Funct,N,Args,Code,Status).

flora_db_pathexp(Mode,CANOTERM(Funct,N,FL_BRACKET,Args,_If,_Ip),Code,Status) :-
	!,
	flora_db_objspec(Mode,Funct,N,Args,Code,Status).

%% Reification in insert/delete seems to be blocked elsewhere.
%% This clause is here in case we decide to unblock later.
flora_db_pathexp(_Mode,CANOTERM(Funct,N,FL_BRACE,Args,If,Ip),Code,Status) :-
	get_atom(Funct,Atom),
	is_reifyop(Atom),
	!,
	(N > 1
	-> flora_list_to_conjunct(Args,Conjunct,If,Ip),
	    flora_reify(Conjunct,Code,Status)
	;
	    Args = [Arg],
	    flora_reify(Arg,Code,Status)
	).

flora_db_pathexp(Mode,CANOLIST(L,T,_N,I,_Ib),Code,Status) :-
	!,
	flora_db_list(Mode,L,T,I,Code,Status).


%% Anonymous oid IS allowed in insert/delete
flora_db_pathexp(_Mode,ObjectTerm,Code,[]) :-
	flobject_struct(ObjectTerm,Code),
	!.

flora_db_pathexp(Mode,CanoniTerm,_Code,Status) :-
	( Mode == FLINS ->
	    parsing_error(CanoniTerm,ERROR_EXPINSERT,Status)
	;
	  Mode == FLDEL,
	  parsing_error(CanoniTerm,ERROR_EXPDELETE,Status)
	;
	  Mode == FLREF,
	  parsing_error(CanoniTerm,ERROR_EXPREFRESH,Status)
	;
	  Mode == FLCLS,
	  parsing_error(CanoniTerm,ERROR_EXPCLAUSE,Status)
	).


/****************************************************************************
  flora_db_objspec(+Mode,+Obj,+Arity,+Args,-Code,-Status)
  flora_db_objspec(+Mode,+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_db_objspec(Mode,Obj,N,Args,Code,Status) :-
	flora_db_pathexp(Mode,Obj,O,S),
	( S == [] ->
	    ( N == 0 ->
		Spec=[],
		Status=[]
	    ;
	      Args=[Body],
	      flora_db_objspec(Mode,Body,Spec,Status)
	    ),
	    (Status == [] -> flobjspec_struct(O,Spec,Code); true)
	;
	  Status=S
        ).


flora_db_objspec(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( (F == FL_COMMA ; F==FL_AND) ->
	    flora_db_objspec(Mode,L,LCode,S),
	    ( S == [] ->
		flora_db_objspec(Mode,R,RCode,Status),
		(Status == [] -> flconjunct_struct(LCode,RCode,Code); true)
	    ;
	      Status=S
	    )
	;
	  (F == FL_SEMICOLON ; F==FL_OR),
	  ( Mode == FLINS ->
	      parsing_error(If,NO_INSERTDISJUN,Status)
	  ;
	    Mode == FLDEL,
	    parsing_error(If,NO_DELETEDISJUN,Status)
          ; parsing_error(If,NO_DISJUNCTION,Status)
	  )
	).

flora_db_objspec(Mode,CANOTERM(Funct,1,FL_PARENTHESIS,[_G],If,_Ip),_Code,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!,
	( Mode == FLINS ->
	    parsing_error(If,NO_INSERTNEG,Status)
	;
	  Mode == FLDEL,
	  parsing_error(If,NO_DELETENEG,Status)
	;
	  Mode == FLREF,
	  parsing_error(If,ERROR_REFRESH,Status)
	;
	  Mode == FLCLS,
	  parsing_error(If,ERROR_CLAUSE,Status)
	).

flora_db_objspec(Mode,CanoniTerm,Code,Status) :-
	flora_db_attmethspec(Mode,CanoniTerm,Code,Status).


/****************************************************************************
  flora_db_attmethspec(+Mode,+CanoniTerm,-Goal,-Status)
  flora_db_setexp(+Mode,+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_db_attmethspec(Mode,CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),Code,Status) :-
	get_atom(Funct,F),
	( is_fdattspecop(F) ->
	    flora_db_pathexplist(Mode,[L,R],[LCode,RCode],Status),
	    (Status == [] -> flfdattspec_struct(LCode,F,RCode,Code); true)

	; is_mvdattspecop(F) ->
	    flora_db_pathexp(Mode,L,LCode,S),
	    (S == [] -> flora_db_setexp(Mode,R,RCode,Status); Status=S),
	    (Status == [] -> flmvdattspec_struct(LCode,F,RCode,Code); true)

	; (is_incattspecop(F); is_tolistattspecop(F)) ->
	    ( Mode == FLINS ->
		parsing_error(If,ERROR_INSERT,Status)
	    ;
	      Mode == FLDEL,
	      parsing_error(If,ERROR_DELETE,Status)
	    ;
	      Mode == FLREF,
	      parsing_error(If,ERROR_REFRESH,Status)
	    ;
	      Mode == FLCLS,
	      parsing_error(If,ERROR_CLAUSE,Status)
	    )
        ;
	  F == FL_AT,
	  parsing_error(If,NO_WORKSPACE,Status)
        ),
	!.

flora_db_attmethspec(Mode,CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_INMETH),
	!,
	flora_db_pathexp(Mode,A,C,Status),
	(Status == [] -> flimethspec_struct(C,Code); true).

flora_db_attmethspec(Mode,CANOTERM(Funct,1,FL_PARENTHESIS,[A],_If,_Ip),Code,Status) :-
	get_atom(Funct,FL_TRAN),
	!,
	flora_db_pathexp(Mode,A,C,Status),
	(Status == [] -> fltranspec_struct(C,Code); true).

flora_db_attmethspec(Mode,CanoniTerm,Code,Status) :-
	flora_db_pathexp(Mode,CanoniTerm,C,Status),
	(Status == [] -> flmethspec_struct(C,Code); true).


flora_db_setexp(Mode,CANOBRACE(L,_N,_I),CodeList,Status) :-
	!,
	flora_db_pathexplist(Mode,L,CodeList,Status).

flora_db_setexp(Mode,CanoniTerm,[Code],Status) :-
	flora_db_pathexp(Mode,CanoniTerm,Code,Status).

/****************************************************************************
  flora_ruleupdate(+OpCode,+N,+ArgsList,-Code,-Status)
****************************************************************************/
flora_ruleupdate(OpCode,_N,Args,Code,Status) :-
	flora_dynrule_list(Args,CodeList,Status),
	(Status == [] -> flupdaterule_struct(OpCode,CodeList,Code); true).

/****************************************************************************
  flora_dynrule_list(+RuleList,-CodeList,-Status)
****************************************************************************/
flora_dynrule_list([],[],[]) :- !.
flora_dynrule_list([H|T],CodeList,Status) :-
	!,
	flora_dynrule(H,HCL,S),
	( S == [] ->
	    flora_dynrule_list(T,TCL,Status),
	    (Status == [] -> append(HCL,TCL,CodeList); true)
	;
	    Status=S
	).

/****************************************************************************
  flora_dynrule(+CanoniTerm,-CodeList,-Status)
****************************************************************************/
flora_dynrule(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),CodeList,Status) :-
	get_atom(Funct,FL_AT),
	!,
	%% Module name, Var, or special token _@
	( (flora_name_or_normvar(R,RCode)
	  ; thismodule_token(R,RCode)
	  %% ; flora_workspace(R,RCode,S), S==[]
	  )
	->
	    flora_comma_separated_list(L,LList),
	    flora_wsdynrule_list(LList,RCode,CodeList,Status)
	; % illegal module name
	  parsing_error(R,ERROR_WSNAME,Status)
	).

flora_dynrule(CanoniTerm,[Code],Status) :-
	flora_dynrl(CanoniTerm,Code,Status).


/****************************************************************************
  flora_wsdynrule_list(+CanoniTermList,+WS,-CodeList,-Status)
****************************************************************************/
flora_wsdynrule_list([],_WS,[],[]) :- !.

flora_wsdynrule_list([H|T],WS,CodeList,Status) :-
	!,
	flora_wsdynrule(H,WS,HCodeList,S),
	( S == [] ->
	    flora_wsdynrule_list(T,WS,TCodeList,Status),
	    (Status == [] -> append(HCodeList,TCodeList,CodeList); true)
	;
	  Status=S
        ).


/****************************************************************************
  flora_wsdynrule(+CanoniTerm,+WS,-CodeList,-Status)
****************************************************************************/
flora_wsdynrule(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],_If,_Ip),_WS,CodeList,Status) :-
	get_atom(Funct,FL_AT),
	!,
	%% nested module name
	%% Module name, Var, or special token _@
	( (flora_name_or_normvar(R,RCode)
	  ; thismodule_token(R,RCode)
	  )
	->
	    flora_comma_separated_list(L,LList),
	    flora_wsdynrule_list(LList,RCode,CodeList,Status)
	; % illegal module name
	  parsing_error(R,ERROR_WSNAME,Status)
        ).

flora_wsdynrule(CanoniTerm,WS,[Code],Status) :-
        ( is_rule(CanoniTerm,Head,Body) ->
	    flora_dynhead(Head,HCL,S),
	    ( S == [] ->
		(get_module_from_spec(WS,ModuleType,Module)
		-> % this is typically a system module case
		    flora_body(Body,WS,WS_FROM_DYNRULE,BodyCode,Status),
		    flmodule_structlist(HCL,Module,ModuleType,WSHCL)
		; % module is a var, an atom, or a _@
		    flora_body(Body,FLORAUSERMOD(WS),WS_FROM_DYNRULE,BodyCode,Status),
		    flmodule_structlist(HCL,WS,FLORAUSERMOD,WSHCL)
		),
		fldynrule_struct(WSHCL,BodyCode,RuleCode),
		flmodule_struct(RuleCode,WS,FLORARULEWORKSPACE,Code)
	    ;
		Status=S
            )
	;
	    get_flvar_struct(CanoniTerm,Code), Status = []
        ;
            parsing_error(CanoniTerm, EXP_RULES, Status) 
        ).

/****************************************************************************
  flora_dynrl(+CanoniTerm,-Code,-Status)
****************************************************************************/
flora_dynrl(CanoniTerm,Code,Status) :-
        ( is_rule(CanoniTerm,Head,Body) ->
	    flora_dynhead(Head,HCL,S),
	    ( S == [] ->
		flora_body(Body,BodyCode,Status),
		fldynrule_struct(HCL,BodyCode,Code)
	    ;
		Status=S
            )
	;
	    get_flvar_struct(CanoniTerm,Code), Status = []
        ;
            parsing_error(CanoniTerm, EXP_RULES, Status) 
        ).

/****************************************************************************
  flora_dynhead(+CanoniTerm,-CodeList,-Status)

  Similar to flora_head, but each element of the conjuction may be a
  normal variable or flora_head_literal
****************************************************************************/
flora_dynhead(CANOTERM(Funct,2,FL_PARENTHESIS,[L,R],If,_Ip),CodeList,Status) :-
	get_atom(Funct,F),
	( (F == FL_COMMA ; F==FL_AND) ->
	    flora_dynhead(L,LCodeList,S),
	    ( S == [] ->
		flora_dynhead(R,RCodeList,Status),
		( Status == [] ->
		    append(LCodeList,RCodeList,CodeList)
		;
		  true
		)
	    ;
	      Status=S
	    )

	; (F == FL_SEMICOLON ; F==FL_OR) -> % Disjunction is prohibited.
	    parsing_error(If,NO_DISJUNCTION,Status)

	; % Module name in rule head is prohibited.
	  F == FL_AT,
	  parsing_error(If,NO_WSINRULEHEAD,Status)
	),
	!.

flora_dynhead(CANOTERM(Funct,1,FL_PARENTHESIS,[_G],If,_Ip),_CodeList,Status) :-
	get_atom(Funct,F),
	(is_notop(F); is_tnotop(F)),
	!,
	parsing_error(If,NO_NEGATION,Status).

flora_dynhead(CanoniTerm,[Code],Status) :-
        ( get_flvar_struct(CanoniTerm, Code) ->
            ( Code=FLVAR(FL_UNDERSCORE,I) ->
                parsing_error(I,ERROR_HDLITERAL,Status)
            ;
                Status=[]
            )
        ;
	    flora_head_literal(CanoniTerm,Code,Status)
        ).

/****************************************************************************
  flmodule_structlist(+List,+WS,+MOD,-ListWithModule)
  distribute module name to each element of the input list
****************************************************************************/
flmodule_structlist([],_WS,_ModType,[]) :- !.
flmodule_structlist([H|L],WS,ModType,[HM|LM]) :-
	flmodule_struct(H,WS,ModType,HM),
	flmodule_structlist(L,WS,ModType,LM).

/****************************************************************************
  flatomvar_list(+List,-ListCodeWS,-Status)
  parse a list of atoms and regular vars
****************************************************************************/
/*
flatomvar_list([],[],[]) :- !.
flatomvar_list([H|L],[HCode|LCode],Status) :-
	( flora_name_or_normvar(H,HCode) ->
	    flatomvar_list(L,LCode,Status)
	;
	    parsing_error(H,EXP_VARORATOM,Status)
	).
*/

parse_semantics_directive_args(_,[],[],[]).
parse_semantics_directive_args(AllowVariables,[CANOTERM(F,1,FL_PARENTHESIS,[Arg],If,_Ip)|Rest],[HCode|RestCode],Status) :-
	get_atom(F,FAtom),
	flobject_struct(Arg,ArgStruct),
	is_valid_semantics_direct_option(AllowVariables,FAtom,ArgStruct),
	!,
	(flora_prlgterm(CANOTERM(F,1,FL_PARENTHESIS,[Arg],If,_Ip),CodeHilog,S),
	    S == [],
	    flplib_struct(CodeHilog,HCode)
	-> 
	    parse_semantics_directive_args(AllowVariables,Rest,RestCode,Status)
	;
	    get_index(Arg,Ind),
	    (AllowVariables == ALLOW_VARIABLES
	    ->
		parsing_error(Ind,ERROR_SEMOPT,Status)
	    ;
		parsing_error(Ind,ERROR_SETSEMOPT,Status)
	    )
	).
parse_semantics_directive_args(AllowVariables, [Arg|_], _, Status) :-
	get_index(Arg,Ind),
	!,
	(AllowVariables == ALLOW_VARIABLES
	->
	    parsing_error(Ind,ERROR_SEMOPT,Status)
	;
	    parsing_error(Ind,ERROR_SETSEMOPT,Status)
	).


is_valid_semantics_direct_option(ALLOW_VARIABLES,Opt,Val) :-
	!,
	valid_semantics_direct_opt_name(Opt),
	( is_flvar_struct(Val), !
	; is_flatom_struct(Val,Atom),
	    valid_semantics_direct_option(Opt,Atom)
	).
is_valid_semantics_direct_option(DISALLOW_VARIABLES,Opt,Val) :-
	!,
	is_flatom_struct(Val,Atom),
	valid_semantics_direct_option(Opt,Atom).

valid_semantics_direct_opt_name(FL_EQUALITY).
valid_semantics_direct_opt_name(FL_INHERITANCE).
valid_semantics_direct_opt_name(FL_CUSTOM).
valid_semantics_direct_option(FL_EQUALITY,NONE).
valid_semantics_direct_option(FL_EQUALITY,BASIC).
valid_semantics_direct_option(FL_EQUALITY,FLOGIC).
valid_semantics_direct_option(FL_INHERITANCE,NONE).
valid_semantics_direct_option(FL_INHERITANCE,FLOGIC).
valid_semantics_direct_option(FL_CUSTOM,NONE).
valid_semantics_direct_option(FL_CUSTOM,X) :- atom(X).


%%% Misc
protect_reification(Call) :-
	assert(FLORA_SYMBOL('parser_flag')(reifying)),
	call(Call),
	(retract(FLORA_SYMBOL('parser_flag')(reifying))
	; true).

if_reifying :-
	FLORA_SYMBOL('parser_flag')(reifying).
if_not_reifying :-
	\+ FLORA_SYMBOL('parser_flag')(reifying).
