/* A converter for transforming the problem format XCSP 2.1 into B-Prolog */
/* by Neng-Fa Zhou, Last updated, January 2, 2008.                        */
%:-set_prolog_flag(gc_threshold,20000).

:-op(1050,xfy,':').  % needed for version B-Prolog 7.4 and up

main:-
    get_main_args(L),
    process_args(L,BaseName),
    xcsp2pl(BaseName).

process_args([],_InFile):-true : format("usage: convert FileName",[]),halt.
process_args([BaseName|_],BaseName1):-true : BaseName1=BaseName.

convert(File):-
    xcsp2pl(File).

xcsp2pl(File):- %File is a base name
    cputime(ConvStart),
    writeln(user,'c converting'(File)),
    atom_codes(File,MainString),
    append(MainString,".xml",InFileString),
    atom_codes(InFile,InFileString),
    append(MainString,".pl",OutFileString),
    atom_codes(OutFile,OutFileString),
    (exists(InFile)->true;format("File not found:~w~n",[InFile]),halt),
    see(InFile),
    tell(OutFile),
    process_xcsp_xml,
    seen,told,
    cputime(ConvEnd),
    ConvTime is ConvEnd-ConvStart,
    format("c Converted in ~w ms~n",[ConvTime]).

process_xcsp_xml:-
    writeln('csp(Vs):-'),
    read_next_key_token(Token),
    process_sections(Token,_Preds),
    writeln('true.').

process_sections(Token,_Preds):-var(Token) : true.  % end-of-file
process_sections(presentation,Preds):-true :
    b_NEXT_TOKEN_ff(_,Token),
    skip_presentation(Token),
    read_next_key_token(KeyToken),
    process_sections(KeyToken,Preds).
process_sections(domain,Preds):-true :
    not(not(process_domain)),
    read_next_key_token(KeyToken),
    process_sections(KeyToken,Preds).
process_sections(variable,Preds):-true :
    process_variables([],Preds).
process_sections(relation,Preds):-true :
    not(not(process_relation)),
    read_next_key_token(KeyToken),
    process_sections(KeyToken,Preds).
process_sections(predicate,Preds):-true :
    process_predicate(Preds),
    read_next_key_token(KeyToken),
    process_sections(KeyToken,Preds).
process_sections(constraint,Preds):-true :
    closetail(Preds),
    not(not(process_constraint(Preds))),
    read_next_key_token(KeyToken),
    process_sections(KeyToken,Preds).
    
skip_presentation('</'):-true :
    b_NEXT_TOKEN_ff(_,Token),
    (Token==presentation -> true;
     skip_presentation(Token)).
skip_presentation('/>'):-true : true.
skip_presentation(_):-true :
    b_NEXT_TOKEN_ff(_,Token),
    skip_presentation(Token).

process_variables(Vars,Preds):-
    process_variable(Var),
    Vars1=[Var|Vars],
    read_next_key_token(KeyToken),
    (KeyToken==variable->
      process_variables(Vars1,Preds);
      reverse(Vars1,Vars2),
      format("Vs=[~@],~n",[output_vars(Vars2)]),
      process_sections(KeyToken,Preds)).

%%%%
process_domain:-
    b_NEXT_TOKEN_ff(_,AName),         % name
    process_attrs(AName,Attrs,NextToken),
    assoc_member(name,NameCodes,Attrs),
    format("D~s=[",[NameCodes]),
    process_dom_items(NextToken,_IsFirst),
    skip1(domain).

process_dom_items('-',IsFirst):-true : 
    b_NEXT_TOKEN_ff(_,Token),  % must be an int
    Token1 is -Token,
    process_dom_items(Token1,IsFirst).
process_dom_items('+',IsFirst):-true : 
    b_NEXT_TOKEN_ff(_,Token),  % must be an int
    process_dom_items(Token,IsFirst).
process_dom_items('..-',IsFirst):-true : 
    b_NEXT_TOKEN_ff(_,Token),  % must be an int
    Token1 is -Token,
    writename(' .. '), writename(Token1),
    b_NEXT_TOKEN_ff(_,NToken),
    process_dom_items(NToken,IsFirst).
process_dom_items('..+',IsFirst):-true : 
    b_NEXT_TOKEN_ff(_,Token),  % must be an int
    writename(' .. '), writename(Token),
    b_NEXT_TOKEN_ff(_,NToken),
    process_dom_items(NToken,IsFirst).
process_dom_items('..',IsFirst):-true : 
    b_NEXT_TOKEN_ff(_,Token),  % must be an int
    writename(' .. '), writename(Token),
    b_NEXT_TOKEN_ff(_,NToken),
    process_dom_items(NToken,IsFirst).
process_dom_items(Elm,IsFirst):-integer(Elm) : 
    (var(IsFirst)->IsFirst=0;write(',')),
    writename(Elm),
    b_NEXT_TOKEN_ff(_,NToken),
    process_dom_items(NToken,IsFirst).
process_dom_items(_Token,_IsFirst):-true : 
    writename(']'),writename(','),nl.
    
%%%%
process_variable(Var):-
    b_NEXT_TOKEN_ff(_,AName), 
    process_attrs(AName,Attrs,_NextToken),
    assoc_member(name,VNameCodes,Attrs),
    assoc_member(domain,DNameCodes,Attrs),
    atom_codes(Var,VNameCodes),
    format("V~s :: D~s,~n",[VNameCodes,DNameCodes]).

%%%%
process_relation:-
    b_NEXT_TOKEN_ff(_,AName), 
    process_attrs(AName,Attrs,NextToken1),
    assoc_member(name,RNameCodes,Attrs),
    assoc_member(arity,ArityCodes,Attrs),
    assoc_member(semantics,Semantics,Attrs),
    (Semantics=="supports"->Type=sr;Type=cr),
    format("~w(R~s,~s,[",[Type,RNameCodes,ArityCodes]),
    process_tuples(NextToken1,NextToken2,_),
    writeln(']),'),
    (NextToken2='/>'->
       (b_NEXT_TOKEN_ff(_,'</'),b_NEXT_TOKEN_ff(_,relation)->true;true);
       skip1(relation)).
         % handle empty relation   <relation .../> </relation>
         %                         <relation />
         %        nonempty         <relation ...>12 12</relation>

process_tuples('-',NToken,IsFirstTuple):-true :
    b_NEXT_TOKEN_ff(_,Token1), % must be an integer
    Token2 is -Token1,
    process_tuples(Token2,NToken,IsFirstTuple).
process_tuples('+',NToken,IsFirstTuple):-true :
    b_NEXT_TOKEN_ff(_,Token1), % must be an integer
    process_tuples(Token1,NToken,IsFirstTuple).
process_tuples(Token,NToken,IsFirstTuple):-integer(Token) :
    (var(IsFirstTuple)->IsFirstTuple=0;writename(',')),
    process_tuple(Token,Token1,_),
    process_tuples(Token1,NToken,IsFirstTuple).
process_tuples('|',NToken,IsFirstTuple):-true :
    b_NEXT_TOKEN_ff(_,Token), 
    process_tuples(Token,NToken,IsFirstTuple).
process_tuples(Token,NToken,_IsFirstTuple):-NToken=Token.

process_tuple('-',NToken,IsFirstElm):-true :
    b_NEXT_TOKEN_ff(_,Token1), % must be an integer
    Token2 is -Token1, 
    process_tuple(Token2,NToken,IsFirstElm).
process_tuple('+',NToken,IsFirstElm):-true :
    b_NEXT_TOKEN_ff(_,Token1), % must be an integer
    process_tuple(Token1,NToken,IsFirstElm).
process_tuple(Token,NToken,IsFirstElm):-integer(Token) :
    (var(IsFirstElm)->writename('t('),IsFirstElm=0;writename(',')),
    writename(Token),
    b_NEXT_TOKEN_ff(_,Token1), 
    process_tuple(Token1,NToken,IsFirstElm).
process_tuple(Token,NToken,_IsFirstElm):-true :
    NToken=Token,
    writename(')').

%%%%
process_constraint(Preds):-
    b_NEXT_TOKEN_ff(_,AName), 
    process_attrs(AName,Attrs,NextToken),
    assoc_member(scope,Scope,Attrs),
    assoc_member(reference,RefCodes,Attrs),
    process_constraint(RefCodes,Scope,Preds,NextToken).

process_constraint("global:allDifferent",Scope,_Preds,NextToken):-true :
    tokenize(Scope,ActualArgs),
    format("call_all_distinct([~@]),~n",[output_vars(ActualArgs)]),
    (NextToken=='/>'->true;skip1(constraint)).
process_constraint("global:alldifferent",Scope,Preds,NextToken):-true :
    process_constraint("global:allDifferent",Scope,Preds,NextToken).
process_constraint("global:cumulative",_Scope,_Preds,_):-true :
    'skip_until>'(_,PToken),      % <parameters>
    process_cumulative_params(PToken,Os,Ds,Es,Hs,Limit),
    format("call_cumulative([~@],[~@],[~@],[~@],~w),~n",[output_args(Os),output_args(Ds),output_args(Es),output_args(Hs),Limit]),
    skip1(constraint).
process_constraint("global:element",_Scope,_Preds,_):-true :
    'skip_until>'(_,IToken),           % <parameters> I
    read_int_or_id(IToken,I),
    b_NEXT_TOKEN_ff(_,PToken),         % 
    process_element_params(PToken,As), % [A1,...,An]
    b_NEXT_TOKEN_ff(_,VToken),         % V
    read_int_or_id(VToken,V),
    format("call_element(~@,[~@],~@),~n",[output_arg(I),output_args(As),output_arg(V)]),
    skip1(constraint).
process_constraint("global:weightedSum",_Scope,_Preds,_):-true :
    'skip_until>'(_,PToken),           % <parameters> 
    process_sum_params(PToken,Coes,Vs,Rel,Rhs),
    format("call_weightedSum([~@],[~@],~w,~w),~n",[output_args(Coes),output_args(Vs),Rel,Rhs]),
    skip1(constraint).
process_constraint("global:weightedsum",_Scope,_Preds,_):-true :
    'skip_until>'(_,PToken),           % <parameters> 
    process_sum_params(PToken,Coes,Vs,Rel,Rhs),
    format("call_weightedSum([~@],[~@],~w,~w),~n",[output_args(Coes),output_args(Vs),Rel,Rhs]),
    skip1(constraint).
process_constraint(RefCodes,Scope,Preds,_):- true ?  % predicate, must exist
    member(pred(RefCodes,FormalArgs,Body),Preds),!,  
    tokenize(Scope,ScopeVars),
    writename('constr_scope(['),output_vars(ScopeVars),writename(']),'),nl,
    b_NEXT_TOKEN_ff(_,_),         % <constraint ...>
    'skip_until>'(_,PToken),      % <parameters>
    process_actual_params(PToken,ActualArgs),
    copy_term((FormalArgs,Body),(FormalArgsCp,BodyCp)),
    ActualArgs=FormalArgsCp,
    output_constrs(BodyCp),
    skip1(constraint).
process_constraint(RefCodes,Scope,_Preds,NextToken):-true :   % extension
    tokenize(Scope,ActualArgs),
    format("ec(R~s,~@),~n",[RefCodes,output_vars_tuple(ActualArgs)]),
    (NextToken=='/>'->true;skip1(constraint)).

process_actual_params('</',Args):-true : Args=[].
process_actual_params(Token,Args):-integer(Token) : 
    Args=[Token|Args1],
    b_NEXT_TOKEN_ff(_,Token1),
    process_actual_params(Token1,Args1).
process_actual_params('-',Args):-true :
    b_NEXT_TOKEN_ff(_,Token1),
    Token2 is -Token1,
    process_actual_params(Token2,Args).
process_actual_params('+',Args):-true :
    b_NEXT_TOKEN_ff(_,Token1),
    process_actual_params(Token1,Args).
process_actual_params(Token,Args):-true :
    atom_codes(Token,Codes),
    atom_codes(VToken,[0'V|Codes]),
    Args=[VToken|Args1],
    b_NEXT_TOKEN_ff(_,Token1),
    process_actual_params(Token1,Args1).
    
process_cumulative_params(']',Os,Ds,Es,Hs,Limit):-true : 
    b_NEXT_TOKEN_ff(_,LimitToken),    
    read_int_or_id(LimitToken,Limit),
    Os=[],Ds=[],Es=[],Hs=[].
process_cumulative_params('[',Os,Ds,Es,Hs,Limit):-true : 
    b_NEXT_TOKEN_ff(_,NToken),
    process_cumulative_params(NToken,Os,Ds,Es,Hs,Limit).
process_cumulative_params('{',Os,Ds,Es,Hs,Limit):-true : 
    Os=[O|Os1],Ds=[D|Ds1],Es=[E|Es1],Hs=[H|Hs1],
    process_cumulative_param(O),
    process_cumulative_param(D),
    process_cumulative_param(E),
    process_cumulative_param(H),
    b_NEXT_TOKEN_ff(_,_),  % }
    b_NEXT_TOKEN_ff(_,NToken),
    process_cumulative_params(NToken,Os1,Ds1,Es1,Hs1,Limit).

process_cumulative_param(A):-
    b_NEXT_TOKEN_ff(_,Token),
    process_cumulative_param(Token,A).

process_cumulative_param('<',A):-true : A='_$dummy',
    b_NEXT_TOKEN_ff(_,_),   % nil
    b_NEXT_TOKEN_ff(_,_).   % />
process_cumulative_param(Token,A):-true : 
    read_int_or_id(Token,A).

process_element_params('[',As):-true :
    b_NEXT_TOKEN_ff(_,Token),
    process_element_params(Token,As).
process_element_params(']',As):-true : As=[].
process_element_params(AToken,As):-true : As=[A|As1],
    read_int_or_id(AToken,A),
    b_NEXT_TOKEN_ff(_,NToken),
    process_element_params(NToken,As1).
    
process_sum_params('[',Coes,Vs,Rel,Rhs):-true :
    b_NEXT_TOKEN_ff(_,Token),
    process_sum_params(Token,Coes,Vs,Rel,Rhs).
process_sum_params(']',Coes,Vs,Rel,Rhs):-true :
    Coes=[],Vs=[],
    b_NEXT_TOKEN_ff(_,_),   %<
    b_NEXT_TOKEN_ff(_,Rel),
    b_NEXT_TOKEN_ff(_,_),   %/>
    b_NEXT_TOKEN_ff(_,RhsToken),
    read_int_or_id(RhsToken,Rhs).
process_sum_params('{',Coes,Vs,Rel,Rhs):-true :
    Coes=[Coe|Coes1],
    Vs=[V|Vs1],
    b_NEXT_TOKEN_ff(_,CoeToken),
    read_int_or_id(CoeToken,Coe),
    b_NEXT_TOKEN_ff(_,V),
    b_NEXT_TOKEN_ff(_,_), % }
    b_NEXT_TOKEN_ff(_,Token),
    process_sum_params(Token,Coes1,Vs1,Rel,Rhs).

%%%%
process_predicate(Preds):-
    b_NEXT_TOKEN_ff(_,AName), 
    process_attrs(AName,Attrs,_NextToken),
    assoc_member(name,PNameCodes,Attrs),
    'skip_until>'(_,PToken),      % <parameters>
    process_formal_params(PToken,PredArgs,ArgsTab),
    skip2(expression,'>'),
    skip1(functional),
    'skip_until>'(Type,EToken),
    read_expression_tokens(Type,EToken,ETokens),
    process_expression(ETokens,Constr,ArgsTab),
    attach(pred(PNameCodes,PredArgs,Constr),Preds),
    skip2(predicate,'>').
     
process_formal_params('</',Args,_ArgsTab):-true : Args=[].
process_formal_params(int,Args,ArgsTab):-true : 
    b_NEXT_TOKEN_ff(_,Token),
    process_formal_params(Token,Args,ArgsTab).
process_formal_params(Token,Args,ArgsTab):-true : 
    Args=[VArg|Args1],
    attach(arg(Token,VArg),ArgsTab),
    b_NEXT_TOKEN_ff(_,NToken),
    process_formal_params(NToken,Args1,ArgsTab).
    
read_expression_tokens(_Type,'</',ETokens):-true : ETokens=[].
read_expression_tokens(2,Token,ETokens):-true : 
    ETokens=[Token,'('|ETokens1],
    b_NEXT_TOKEN_ff(Type,Token1),
    read_expression_tokens(Type,Token1,ETokens1).
read_expression_tokens(_,Token,ETokens):-true : 
    ETokens=[Token|ETokens1],
    b_NEXT_TOKEN_ff(Type,Token1),
    read_expression_tokens(Type,Token1,ETokens1).

process_expression([],Constrs,_ArgsTab):-true : Constrs=[].
process_expression(ETokens,Constrs,ArgsTab):-true :
    process_bool_exp(ETokens,ETokens1,Constr,ArgsTab),
    expand_and(Constr,Constrs,Constrs1),
    process_expression(ETokens1,Constrs1,ArgsTab).

expand_and((Constr1 #/\ Constr2),Constrs,ConstrsR):-true :
      expand_and(Constr1,Constrs,Constrs1),
      expand_and(Constr2,Constrs1,ConstrsR).
expand_and(1,Constrs,ConstrsR):-true : Constrs=ConstrsR.
expand_and(0,Constrs,ConstrsR):-true : Constrs=[fail|ConstrsR].
expand_and(Constr,Constrs,ConstrsR):-true : Constrs=[Constr|ConstrsR].

process_bool_exp([false|Tokens],TokensR,Constr,_ArgsTab):-true : 
      Constr=0,TokensR=Tokens.
process_bool_exp([true|Tokens],TokensR,Constr,_ArgsTab):-true : 
      Constr=1,TokensR=Tokens.
process_bool_exp([not,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Constr1,ArgsTab),
      Tokens1=[')'|TokensR],
      Constr=(#\ Constr1).
process_bool_exp([and,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Constr1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_bool_exp(Tokens2,Tokens3,Constr2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Constr1 #/\ Constr2).
process_bool_exp([or,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Constr1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_bool_exp(Tokens2,Tokens3,Constr2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Constr1 #\/ Constr2).
process_bool_exp([xor,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Constr1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_bool_exp(Tokens2,Tokens3,Constr2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Constr1 #\ Constr2).
process_bool_exp([iff,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Constr1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_bool_exp(Tokens2,Tokens3,Constr2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Constr1 #<=>Constr2).
process_bool_exp([eq,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Exp1 #= Exp2).
process_bool_exp([ne,'('|Tokens],TokensR,Constr,ArgsTab):-true :
       process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
       Tokens1=[','|Tokens2],
       process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
       Tokens3=[')'|TokensR],
       Constr=(Exp1 #\= Exp2).
process_bool_exp([ge,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Exp1 #>= Exp2).
process_bool_exp([gt,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Exp1 #> Exp2).
process_bool_exp([le,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Exp1 #=< Exp2).
process_bool_exp([lt,'('|Tokens],TokensR,Constr,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Constr=(Exp1 #< Exp2).

process_int_exp([neg,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[')'|TokensR],
      Exp=(-Exp1).
process_int_exp([abs,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[')'|TokensR],
      Exp=abs(Exp1).
process_int_exp([add,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1+Exp2).
process_int_exp([sub,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1-Exp2).
process_int_exp([mul,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1*Exp2).
process_int_exp([div,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1//Exp2).
process_int_exp([mod,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1 mod Exp2).
process_int_exp([pow,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=(Exp1 ** Exp2).
process_int_exp([min,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=min(Exp1,Exp2).
process_int_exp([max,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_int_exp(Tokens,Tokens1,Exp1,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp2,ArgsTab),
      Tokens3=[')'|TokensR],
      Exp=max(Exp1,Exp2).
process_int_exp([if,'('|Tokens],TokensR,Exp,ArgsTab):-true :
      process_bool_exp(Tokens,Tokens1,Cond,ArgsTab),
      Tokens1=[','|Tokens2],
      process_int_exp(Tokens2,Tokens3,Exp1,ArgsTab),
      Tokens3=[','|Tokens4],
      process_int_exp(Tokens4,Tokens5,Exp2,ArgsTab),
      Tokens5=[')'|TokensR],
      Exp=if(Cond,Exp1,Exp2).
process_int_exp(['-',Token|Tokens],TokensR,Exp,_ArgsTab):-integer(Token) :
      Exp is -Token,
      Tokens=TokensR.
process_int_exp(['+',Token|Tokens],TokensR,Exp,_ArgsTab):-integer(Token) :
      Exp is Token,
      Tokens=TokensR.
process_int_exp([Token|Tokens],TokensR,Exp,_ArgsTab):-integer(Token) :
      Exp=Token,
      Tokens=TokensR.
process_int_exp([Token|Tokens],TokensR,Exp,ArgsTab):-true :
      Tokens=TokensR,
      member(arg(Token,Exp),ArgsTab),!.

%%%%
process_attrs('>',Attrs,NextToken):-true : Attrs=[],b_NEXT_TOKEN_ff(_,NextToken).
process_attrs('>+',Attrs,NextToken):-true : Attrs=[],NextToken='+'.
process_attrs('>-',Attrs,NextToken):-true : Attrs=[],NextToken='-'.
process_attrs('/>',Attrs,NextToken):-true : Attrs=[],NextToken='/>'.
process_attrs(AName,Attrs,NextToken):-true : 
     b_NEXT_TOKEN_ff(_,_),    % =
     b_NEXT_TOKEN_ff(_,Val),
     (atom(Val)->atom_codes(Val,Value);
      integer(Val)->number_codes(Val,Value);
      Value=Val),
     Attrs=[AName=Value|Attrs1],
     b_NEXT_TOKEN_ff(_,AName1),
     process_attrs(AName1,Attrs1,NextToken).

%%%%
'skip_until>'(Type,Token):-
     b_NEXT_TOKEN_ff(_,Token1),
     'skip_until>'(Token1,Type,Token).

'skip_until>'('>',Type,Token):-true :
     b_NEXT_TOKEN_ff(Type,Token).
'skip_until>'('>+',Type,Token):-true :
     Type=4,Token='+'.
'skip_until>'('>-',Type,Token):-true :
     Type=4,Token='-'.
'skip_until>'(_,Type,Token):-true :
     b_NEXT_TOKEN_ff(_Type1,Token1),
     'skip_until>'(Token1,Type,Token).

skip1(Token):-
    b_NEXT_TOKEN_ff(_,CurToken),
    skip1(Token,CurToken).

skip1(Token,Token):-true : true.
skip1(Token,_):-true :
    b_NEXT_TOKEN_ff(_,CurToken),
    skip1(Token,CurToken).

skip2(Token1,Token2):-
    b_NEXT_TOKEN_ff(_,CurToken),
    skip2(Token1,Token2,CurToken).

skip2(Token1,Token2,Token1):-true :
    b_NEXT_TOKEN_ff(_,CurToken),
    (CurToken==Token2 -> true;
     skip2(Token1,Token2,CurToken)).
skip2(Token1,Token2,_):-true :
    b_NEXT_TOKEN_ff(_,CurToken),
     skip2(Token1,Token2,CurToken).

read_next_key_token(KeyToken):-
    b_NEXT_TOKEN_ff(_, Token),
    (key_token(Token)->
     KeyToken=Token;
     read_next_key_token(KeyToken)).

read_int_or_id('+',Val):-true :
    b_NEXT_TOKEN_ff(_, Val).  % integer
read_int_or_id('-',Val):-true :
    b_NEXT_TOKEN_ff(_, Val1),
    Val is -Val1.
read_int_or_id(Token,Val):-true : Val=Token.
     
key_token(EndOfFile):-var(EndOfFile) : true.
key_token(domain):-true : true.
key_token(variable):-true : true.
key_token(relation):-true : true.
key_token(predicate):-true : true.
key_token(constraint):-true : true.
key_token(presentation):-true : true.


%%%%
tokenize([],Tokens):-true : Tokens=[].
tokenize([Code|Codes],Tokens):-true ?
     is_space(Code),!,
     tokenize(Codes,Tokens).
tokenize([Code|Codes],Tokens):-true ?
     is_delimeter(Code),!,
     char_code(Token,Code),
     Tokens=[Token|TokensR],
     tokenize(Codes,TokensR).
tokenize([Code|Codes],Tokens):-true :
     extract_token(Codes,Name,CodesR),
     name(Token,[Code|Name]),
     Tokens=[Token|TokensR],
     tokenize(CodesR,TokensR).

extract_token([],Name,CodesR):-true : Name=[],CodesR=[].
extract_token([Code|Codes],Name,CodesR):-true ?
     is_space(Code),!,
      Name=[],
      CodesR=Codes.
extract_token(Codes,Name,CodesR):-Codes=[Code|_] ?
      is_delimeter(Code),!,
      Name=[],
      CodesR=Codes.
extract_token([Code|Codes],Name,CodesR):-true :
      Name=[Code|NameR],
      extract_token(Codes,NameR,CodesR).


:-mode is_space(+).
is_space(0' ).
is_space(9).   % tab
is_space(10). 
is_space(13). 

:-mode is_delimeter(+).
is_delimeter(0'().
is_delimeter(0')).
is_delimeter(0',).
is_delimeter(0'.).
is_delimeter(0'|).

output_vars([]):-true : true.
output_vars([V|Vs]):-true : 
  (V=='_$dummy'->writename('_');writename('V'),writename(V)),
  (Vs==[]->true;
   writename(','),
   output_vars(Vs)).

output_vars_tuple(Tuple):-true : 
   writename('t('),
   output_vars_tuple_rest(Tuple).

output_vars_tuple_rest([V]):-true : 
  writename('V'),writename(V),writename(')').
output_vars_tuple_rest([V|Vs]):-true : 
  writename('V'),writename(V),writename(','),
  output_vars_tuple_rest(Vs).

output_constrs([]):-true : true.
output_constrs([Constr|Constrs]):-
    write(Constr),writename(','),nl,
    output_constrs(Constrs).

output_args([]):-true : true.
output_args([V|Vs]):-true : 
  output_arg(V),
  (Vs==[]->true;
   writename(','),
   output_args(Vs)).

output_arg('_$dummy'):-true : writename('_').
output_arg(Arg):-integer(Arg) : writename(Arg).
output_arg(Arg):-true : writename('V'),writename(Arg).

%%%%%
assoc_member(AName,AVal,[AName=AVal1|_]):-true : AVal=AVal1.
assoc_member(AName,AVal,[_|L]):-true : assoc_member(AName,AVal,L).
