(* ----------------------------------------------------------------------------
 * $Id: MLOGIO.mi,v 1.2 1994/11/28 21:04:15 dolzmann Exp $
 * ----------------------------------------------------------------------------
 * Copyright (c) 1993 Universitaet Passau
 * ----------------------------------------------------------------------------
 * This file is part of MAS.
 * ----------------------------------------------------------------------------
 * $Log: MLOGIO.mi,v $
 * Revision 1.2  1994/11/28  21:04:15  dolzmann
 * New revision of the MASLOG system: New functions and bug fixes of old one.
 *
 * Revision 1.1  1993/12/17  17:12:15  dolzmann
 * MASLOG is divided into three parts. (MLOGBASE, MLOGIO, MASLOG)
 * Additional input procedures are added.
 *
 * ----------------------------------------------------------------------------
 *)

IMPLEMENTATION MODULE MLOGIO;
(* Maslog Input Output System Implementation Module. *)

(******************************************************************************
*				 M L O G I O				      *
*-----------------------------------------------------------------------------*
* Author:   Andreas Dolzmann                                                  *
* Language: MODULA II (mocka or mtc are possible.)                            *
* System:   Program for the computer algebra system MAS by Heinz Kredel.      *
* Project:  MASLOG                                                            *
* Remark:   Libraries maskern, maslisp, maslog are used.                      *
* Abstract: A package for the MAS computer algebra system by Heinz Kredel.    *
*           This package implements input and outputroutins for formulas      *
*	    in the format of the MASLOG library.                              *
******************************************************************************)

FROM MASELEM	IMPORT	GAMMAINT, MASEVEN, MASMAX, MASREM;
FROM MASSTOR	IMPORT	ADV, COMP, FIRST, INV, LENGTH, LIST, LIST1, LISTVAR,
			RED, SIL;
FROM MASERR	IMPORT	ERROR, confusion, fatal, harmless, severe, spotless;
FROM MASLISP	IMPORT	ENV;
FROM MASLISPU	IMPORT	Declare, PROCF0, PROCF1, PROCF3, PROCP1;
FROM MASBIOS	IMPORT	BKSP, BLINES, CREAD, CREADB, CWRITE, DIBUFF, DIGIT,
			LETTER, LISTS, MASORD, SWRITE;
FROM MASSYM	IMPORT	ATOM, UWRIT1, UWRITE;
FROM MASSYM2	IMPORT	ACOMP, ASSOCQ, ENTER, EXPLOD, GENSYM, SREAD, SREAD1,
			SYMBOL, SYWRIT;
FROM SACLIST	IMPORT	ADV2, ADV3, AREAD, AWRITE, CCONC, CINV, CLOUT, COMP2,
			CONC, EQUAL, LIST10, LIST2, LIST3, LIST4, LIST5,
			MEMBER, SECOND, THIRD;
FROM MLOGBASE	IMPORT	ANY, BOOL, EQUIV, ET, EXIST, FALSUM, FORALL,
			FORGARGS, FORGLVAR, FORGOP, FORISBOOLVAR, FORISLVAR,
			FORISVAR, FORMKBINOP, FORMKCNST, FORMKFOR, FORMKLVAR,
			FORMKQUANT, FORMKUNOP, FORMKVAR, FORPARGS, FORPBINOP,
			FORPBINOPA, FORPFOR, FORPLVAR, FORPQUANT, FORPQUANTA,
			FORPUNOP, FORPUNOPA, FORPVAR, FORPVARA, FORTST,
			FORVTENTER, FORVTGET, IMP, NON, REP, TVAR, VEL,
			VERUM, XOR;

CONST rcsidi = "$Id: MLOGIO.mi,v 1.2 1994/11/28 21:04:15 dolzmann Exp $";
CONST copyrighti = "Copyright (c) 1993 Universitaet Passau";

VAR ParserSyms: LIST; (* name table for the formula parser. *)

(******************************************************************************
*			   P R E T T Y   P R I N T                            *
******************************************************************************)

PROCEDURE FORPPRT(phi: LIST; bbpprt:PROCP1);
(* formula pretty print. phi is a formula; bbpprt a bb-procedure to write a
bb-formula to the output stream; phi is written formated to the output stream.
*)
	VAR op, red, arg, arg1, arg2, vars, qform, dummy, sort, name: LIST;
BEGIN
	IF phi = SIL THEN SWRITE("SIL"); RETURN; END;

	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM)
	THEN
		pprtop(op);
	ELSIF (op=VEL) OR (op=ET)
	THEN
		FORPARGS(red,arg,red);
		SWRITE("(");
		FORPPRT(arg,bbpprt);
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			pprtop(op);
			FORPPRT(arg,bbpprt)
		END;
		SWRITE(")");
	ELSIF op=NON
	THEN
		FORPUNOPA(red,arg);
		pprtop(op);
		SWRITE("(");
		FORPPRT(arg,bbpprt);
		SWRITE(")");
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR)
	THEN
		FORPBINOPA(red,arg1,arg2);
		SWRITE("(");
		FORPPRT(arg1,bbpprt);
		pprtop(op);
		FORPPRT(arg2,bbpprt);
		SWRITE(")");
	ELSIF (op=EXIST) OR (op=FORALL)
	THEN
		FORPQUANTA(red,vars,qform);
		SWRITE("(");
		pprtop(op);
		FORPPLVAR(vars);
		SWRITE(":");
		FORPPRT(qform,bbpprt);
		SWRITE(")");
	ELSIF op=TVAR
	THEN
		FORPPVAR(phi);
	ELSE
		bbpprt(phi);
	END;
END FORPPRT;

PROCEDURE pprtop(op: LIST);
(* pretty print operator. a symbol for an operator is written to the output
stream. *)
BEGIN
	IF (op=IMP)	THEN SWRITE(" => ");	RETURN;	END;
	IF (op=REP)	THEN SWRITE(" <= "); 	RETURN; END;
	IF (op=EQUIV)	THEN SWRITE(" <=> "); 	RETURN; END;
	IF (op=XOR)	THEN SWRITE(" <#> "); 	RETURN; END;
	IF (op=ET)	THEN SWRITE(" /\ "); 	RETURN; END;
	IF (op=VEL)	THEN SWRITE(" \/ "); 	RETURN; END;
	IF (op=NON)	THEN SWRITE("-- "); 	RETURN; END;
	IF (op=EXIST)	THEN SWRITE("EX "); 	RETURN; END;
	IF (op=FORALL)	THEN SWRITE("FA "); 	RETURN; END;
	IF (op=VERUM)	THEN SWRITE("TRUE"); 	RETURN; END;
	IF (op=FALSUM)	THEN SWRITE("FALSE"); 	RETURN; END;
END pprtop;

PROCEDURE FORPPVAR(var: LIST);
(* formula pretty print variable. var is a variable; var is formated written
to the output stream. *)
	VAR name, sort: LIST;
BEGIN
	FORPVAR(var,name,sort);
	CLOUT(FORVTGET(name));
	IF (sort<>ANY) AND (sort<>BOOL) THEN 
		SWRITE("{");
		CLOUT(FORVTGET(sort));
		SWRITE("}");
	END; 
(*	SWRITE("<");
	CLOUT(FORVTGET(name));
	SWRITE(":");
	CLOUT(FORVTGET(sort));
	SWRITE(">"); *)
END FORPPVAR;

PROCEDURE FORPPLVAR(lvar: LIST);
(* formula print lvar. L is an lvar object; lvar is formated written to the
output stream. *)
	VAR var, varlist: LIST;
BEGIN
	FORPLVAR(lvar,varlist);
	IF varlist=SIL THEN RETURN END; 
	FORPARGS(varlist,var,varlist);
	FORPPVAR(var);
	WHILE varlist <> SIL DO
		SWRITE(",");
		FORPARGS(varlist,var,varlist);
		FORPPVAR(var);
	END;
END FORPPLVAR;


(******************************************************************************
*			      T E X   W R I T E                               *
******************************************************************************)

PROCEDURE FORTEXW(phi: LIST; bbtexw:PROCP1);
(* formula tex write. phi is a formula; bbtexw a bb-procedure to write a
bb-formula in tex style to the outputstream; this procedure writes a formula
in tex style to the outputstream. *)
	VAR op, red, arg, arg1, arg2, vars, qform:  LIST;
BEGIN
	IF phi = SIL THEN SWRITE("SIL"); RETURN; END;
	FORPFOR(phi,op,red);
	IF (op=VERUM) OR (op=FALSUM)
	THEN
		BLINES(0);
		ptexsymbol(phi);
	ELSIF (op=ET) OR (op=VEL)
	THEN
		BLINES(0);
		FORPARGS(red,arg,red);
		SWRITE("(");
		FORTEXW(arg,bbtexw);
		WHILE red <> SIL DO
			FORPARGS(red,arg,red);
			SWRITE(" ");
			ptexsymbol(op);
			SWRITE(" ");
			FORTEXW(arg,bbtexw)
		END;
		SWRITE(")");
	ELSIF op=NON
	THEN
		BLINES(0);
		SWRITE("(");
		ptexsymbol(op);
		FORPUNOPA(red,arg);
		FORTEXW(arg,bbtexw);
		SWRITE(")");
	ELSIF (op=EXIST) OR (op=FORALL)
	THEN
		BLINES(0);
		FORPQUANTA(red,vars,qform);
		SWRITE("(");
		ptexsymbol(op);
		FORTEXWLVAR(vars);
		SWRITE("(");
		FORTEXW(qform,bbtexw);
		SWRITE("))");
	ELSIF (op=IMP) OR (op=REP) OR (op=EQUIV) OR (op=XOR)
	THEN
		BLINES(0);
		FORPBINOPA(red,arg1,arg2);
		SWRITE("(");
		FORTEXW(arg1,bbtexw);
		ptexsymbol(op);
		FORTEXW(arg2,bbtexw);
		SWRITE(")");
	ELSIF (op=TVAR)
	THEN
		BLINES(0);
		FORTEXWVAR(phi);
	ELSE
		BLINES(0);
		bbtexw(phi);
	END;
END FORTEXW;

PROCEDURE FORTEXWVAR(var: LIST);
(* formula tex write variable. var is a variable; this procedure writes var in
tex style to the output stream. *)
	VAR name, sort: LIST;
BEGIN
(*	BLINES(0);
	FORPVAR(var,name,sort);
	SWRITE("\mbox{");
	CLOUT(FORVTGET(name));
	SWRITE("}:\mbox{");
	CLOUT(FORVTGET(sort));
	SWRITE("}"); *)

	FORPVAR(var,name,sort);
	CLOUT(FORVTGET(name));
	IF (sort<>ANY) AND (sort<>BOOL) THEN 
		SWRITE("{");
		CLOUT(FORVTGET(sort));
		SWRITE("}");
	END; 
END FORTEXWVAR;


PROCEDURE FORTEXWLVAR(lvar: LIST);
(* tex write list of varaiables. lvar is an lvar object; this procedure writes
all variables in lvar in tex style to the outputstream. *)
	VAR var, red, sort, name: LIST;
BEGIN
	FORPLVAR(lvar,red);
	ADV(red,var,red);
	FORTEXWVAR(var);
	WHILE red <> SIL DO
		ADV(red,var,red);
		SWRITE(", ");
		FORTEXWVAR(var);
	END;
END FORTEXWLVAR;

PROCEDURE ptexsymbol(sym: LIST);
(* print tex symbol. sym is predifened MASLOG symbol; writes sym in tex style
to the output stream. *)
BEGIN
	IF sym=VERUM	THEN SWRITE("\mbox{TRUE}");	RETURN; END;
	IF sym=FALSUM	THEN SWRITE("\mbox{FALSE}");	RETURN; END;
	IF sym=NON	THEN SWRITE("\lnot");		RETURN; END;
	IF sym=ET	THEN SWRITE("\land");		RETURN; END;
	IF sym=VEL	THEN SWRITE("\lor");		RETURN; END;
	IF sym=IMP	THEN SWRITE("\Rightarrow");	RETURN; END;
	IF sym=REP	THEN SWRITE("\Leftarrow");	RETURN; END;
	IF sym=EQUIV	THEN SWRITE("\iff");		RETURN; END;
	IF sym=XOR	THEN SWRITE("\oplus");		RETURN; END;
	IF sym=EXIST	THEN SWRITE("\exists ");	RETURN; END;
	IF sym=FORALL	THEN SWRITE("\forall " );	RETURN; END;
	SWRITE("\mbox{???}"); RETURN;
END ptexsymbol;

(******************************************************************************
*                    R E A D   P R E F I X   F O R M U L A                    *
******************************************************************************)

PROCEDURE FORPREAD(bbread: PROCF0):LIST;
(* formula prefix read. bbread is a bb-procedure to read a bb.formula from 
the input stream. FORPREAD reads a formula in prefix notation from the 
input stream and returns the read formula. *)
	VAR c:GAMMAINT;
	VAR result, args, sym, info, noargs, key: LIST;
BEGIN
	c:=CREADB();
	IF c=70 (* c=MASORD("(") *)  THEN
		result:=FORPREAD(bbread);
		c:=CREADB();
		IF c<>MASORD(")") THEN
			DIBUFF();
			ERROR(severe,") expected");
			BKSP();
		END;
		RETURN result;
	ELSIF c=85 (* c=MASORD("[") *) THEN
		BKSP();
		result:=atomicread(bbread);
		RETURN result;
	ELSE
		BKSP();
		key:=KEYREAD();
		result:=upcase(key);
		info:=ASSOCQ(result,ParserSyms);
		IF info=SIL THEN 		(* treat as a variable. *)
			RETURN FORRDVARA(key,BOOL);
		ELSE
			info:=FIRST(info);
			sym:=FIRST(info);
			noargs:=SECOND(info);	(* number of arguments *)
			IF noargs=0 THEN 
				RETURN FORMKCNST(sym);
			ELSIF noargs=-1 THEN
				args:=multiarg(bbread);
				RETURN FORMKFOR(sym,args);
			ELSIF noargs=1 THEN
				args:=onearg(bbread);
				RETURN FORMKUNOP(sym,args);
			ELSIF noargs=-2 THEN
				args:=FORRDQUANTA(bbread);
				RETURN FORMKQUANT(sym,FIRST(args),
					SECOND(args));
			ELSIF noargs=2 THEN
				args:=twoargs(bbread);
				RETURN FORMKBINOP(sym,FIRST(args),
					SECOND(args));
			ELSE 
				ERROR(severe,"FORPREAD: unknown noarg");
				RETURN SIL;
			END;
		END;
	END;	
END FORPREAD;

PROCEDURE FORRDVAR():LIST;
(* formula read variable. A description of a variable is read from the input 
stream. *)
	VAR c: GAMMAINT;
	VAR name, sort, sname, ssort:LIST;
BEGIN
	name:=SREAD1();
	IF NOT isvarname(name) THEN
		DIBUFF();
		ERROR(severe,"not valid as a variable name");
	END;
	sname:=FORVTENTER(name);
	c:=CREAD();
	IF c=91 (* c=MASORD("{") *) THEN 	(* { read sort of variable. *)
		sort:=SREAD1();
		IF NOT isvarname(sort) THEN
			DIBUFF();
			ERROR(severe,"not valid as a sort name");
		END;
		ssort:=FORVTENTER(sort);
		c:=CREADB();
		IF c<>92 (* c<>MASORD("}") *) THEN
			DIBUFF();
			ERROR(severe,"} expected");
			BKSP();
		END;
	ELSE
		BKSP();
		ssort:=ANY;
	END;		
	RETURN FORMKVAR(sname,ssort);
END FORRDVAR;

PROCEDURE FORRDVARA(name,sdefault:LIST):LIST;
(* formula read variable arguments. name is a name of a variable. If the next
string in the input stream is a sort name then the sort name is read otherwise
sdefault is taken as a sort name. The complete description of the variable is 
returned.  *)
	VAR c: GAMMAINT;
	VAR  sort, sname,ssort: LIST;
BEGIN
	IF NOT isvarname(name) THEN
		DIBUFF();
		ERROR(severe,"not valid as a variable name");
	END;
	sname:=FORVTENTER(name);
	c:=CREAD();
	IF c=91 (* c=MASORD("{") *) THEN 	(* read sort of variable. *)
		sort:=SREAD1();
		IF NOT isvarname(sort) THEN
			DIBUFF();
			ERROR(severe,"not valid as a sort name");
		END;		
		ssort:=FORVTENTER(sort);
		c:=CREADB();
		IF c<>92 (* c<>MASORD("}") *) THEN
			DIBUFF();
			ERROR(severe,"} expected");
			BKSP();
		END;
	ELSE
		BKSP();
		ssort:=sdefault;
	END;		
	RETURN FORMKVAR(sname,ssort);
END FORRDVARA;

PROCEDURE FORRDLVAR():LIST;
(* formula read list of variables. One variable or a list of variables are 
read from the input stream. A LVAR-object is returned. *)
	VAR c: GAMMAINT;
	VAR var, vlist: LIST;
BEGIN
	c:=CREADB();
	IF LETTER(c) THEN
		BKSP();
		var:=FORRDVAR();
		RETURN FORMKLVAR(LIST1(var));
	ELSIF c=70 (* c=MASORD("(") *) THEN		(* read a list *)
		vlist:=SIL;
		c:=CREADB();
		WHILE c<>71 (* MASORD(")") *) DO
			BKSP();
			var:=FORRDVAR();
			vlist:=COMP(var,vlist);
			c:=CREADB();
			IF c=63 (* c=MASORD(",") *) THEN c:=CREADB(); END;
		END;
		RETURN FORMKLVAR(INV(vlist));
	ELSE
		DIBUFF();
		ERROR(severe,") expected");
		BKSP();
		RETURN SIL;
	END;
END FORRDLVAR; 

PROCEDURE FORRDQUANTA(bbread: PROCF0):LIST;
(* formula read quantifier arguments. 
The arguments of  a quantifier is read from the input stream. A list is 
returned. The first element of the list is the list of bound variables of
the quantifier (as an LVAR-object). The second element of the list is the 
bound formula. *)
	VAR c:GAMMAINT;
	VAR varlist, phi: LIST;
BEGIN
	c:=CREADB();
	IF c<>70 (* c<>MASORD("(") *) THEN
		DIBUFF();
		ERROR(severe,"( expected");
		BKSP();
		RETURN SIL;
	END;
	varlist:=FORRDLVAR();
	c:=CREADB();
	IF c<>63 (* c<>MASORD(",") *) THEN BKSP(); END;
	phi:=FORPREAD(bbread);
	c:=CREADB();
	IF c<>71 (* c<>MASORD(")") *) THEN
		DIBUFF();
		ERROR(severe,") expected");
		BKSP();
		RETURN LIST2(varlist,phi);
	END;
	RETURN LIST2(varlist,phi);
END FORRDQUANTA;

PROCEDURE onearg(bbread:PROCF0):LIST;
(* one argument. One argument is read from the input stream and is returned. *)
	VAR c: GAMMAINT;
	VAR arg: LIST;
BEGIN
	c:=CREADB();
	IF c<>70 (* c<>MASORD("(") *) THEN
		DIBUFF();
		ERROR(severe,"( expected");
		BKSP();
		RETURN SIL;
	END;
	arg:=FORPREAD(bbread);
	c:=CREADB();
	IF c<>71 (* c<>MASORD(")" *) THEN
		DIBUFF();
		ERROR(severe,") expected");
		BKSP();
		RETURN arg;
	END;
	RETURN arg;
END onearg;

PROCEDURE twoargs(bbread:PROCF0):LIST;
(* two arumgents. Two arguments are read from the input stream and are 
returned. *)
	VAR c: GAMMAINT;
	VAR arg, result: LIST;
	VAR i:INTEGER;
BEGIN
	c:=CREADB();
	IF c<>70 (* c<>MASORD("(") *) THEN
		DIBUFF();
		ERROR(severe,"( expected");
		BKSP();
		RETURN SIL;
	END;
	result:=SIL;
	FOR i:=1 TO 2 DO
		arg:=FORPREAD(bbread);
		result:=COMP(arg,result);
		c:=CREADB();
		IF c<>63 (* c<>MASORD(",") *) THEN BKSP(); END;
	END;
	c:=CREADB();
	IF c<>71 (* c<>MASORD(")") *) THEN 
		DIBUFF();
		ERROR(severe,") expected");
		BKSP();
	END;
	RETURN INV(result);
END twoargs;	

PROCEDURE multiarg(bbread:PROCF0):LIST;
(* multi arguments. bbread is a bb-procedure to read a bb-formula from the
input stream. A list of arguments is read from the input stream and is
returned. *)
	VAR c: GAMMAINT;
	VAR arg, result: LIST;
BEGIN
	c:=CREADB();
	IF c<>70 (* c<>MASORD("(") *) THEN
		DIBUFF();
		ERROR(severe,"( expected");
		BKSP();
		RETURN SIL;
	END;
	c:=CREADB();
	result:=SIL;
	WHILE c<>71 (* MASORD(")") *) DO
		BKSP();
		arg:=FORPREAD(bbread);
		result:=COMP(arg,result);
		c:=CREADB();
		IF c=63 (* c=MASORD(",") *) THEN c:=CREADB(); END;
	END;
	RETURN INV(result);
END multiarg;

PROCEDURE atomicread(bbread:PROCF0):LIST;
(* atomic read. bbread is a bb-procedure to read a bb-formula from the
input stream. A bb-formula is read from the input stream. *)
	VAR c:GAMMAINT;
	VAR result:LIST;
BEGIN
	c:=CREADB(); (* ignore [ *)
	result:=bbread();
	c:=CREADB();
	IF c<>87 (* c<>MASORD("]") *) THEN
		DIBUFF();
		ERROR(severe,"] expected");
		BKSP();
	END;
	RETURN result;
END atomicread;


PROCEDURE KEYREAD(): LIST;
(*key read. A keyword or a symbol for a keyword is read. A keyword is a string
of letters ore a string of special characters. The keyword or the symbol is 
also terminated by the characters "()[]{}".
The read keyword is returned a a CLIST.
This procedure is based on the procedure SREAD1 from the module MASSYM2 *)
	VAR  C, L: LIST;
	VAR end:LIST;
BEGIN
	L:=SIL; 
	C:=CREADB();
	IF LETTER(C) THEN
		REPEAT 
			L:=COMP(C,L);
			C:=CREAD();
		UNTIL NOT DIGIT(C) AND NOT LETTER(C);
	ELSE
		REPEAT 
			L:=COMP(C,L);
			C:=CREAD();
		UNTIL ((C=70) OR (C=71) OR (C=72) OR (C=85) OR (C=87) OR 
			(C=91) OR (C=92) OR DIGIT(C) OR LETTER(C) );
	END;
	BKSP; 
	L:=INV(L);
	RETURN(L); 
END KEYREAD;


PROCEDURE InitParser();
(* Initialize the internal data structures for the formula parsers
FORPREAD and FORIREAD. 
ParserSyms is a global name table for the parser. It has the format of a 
ASSOC-list. The first entry in the ASSOC-list is the representation of a
symbol. The second entry is a list which describes the symbol. The first 
entry of this list is the internal representation of the symbol, the second
entry describes the arity of the symbol, and the third entry is the priority
of the symbol. *)
BEGIN
	ParserSyms:=SIL;
	LISTVAR(ParserSyms);
	ParserSyms:=COMP2( LISTS("T"),	    LIST3(VERUM,   0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("TRUE"),   LIST3(VERUM,   0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("VERUM"),  LIST3(VERUM,   0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("FALSE"),  LIST3(FALSUM,  0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("F"),      LIST3(FALSUM,  0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("FALSUM"), LIST3(FALSUM,  0,-1), ParserSyms);
	ParserSyms:=COMP2( LISTS("ET"),     LIST3(ET,     -1, 2), ParserSyms);
	ParserSyms:=COMP2( LISTS("AND"),    LIST3(ET,     -1, 2), ParserSyms);
	ParserSyms:=COMP2( LISTS("/\"),     LIST3(ET,     -1, 2), ParserSyms);
	ParserSyms:=COMP2( LISTS("OR"),     LIST3(VEL,    -1, 3), ParserSyms);
	ParserSyms:=COMP2( LISTS("VEL"),    LIST3(VEL,    -1, 3), ParserSyms);
	ParserSyms:=COMP2( LISTS("\/"),     LIST3(VEL,    -1, 3), ParserSyms);
	ParserSyms:=COMP2( LISTS("NOT"),    LIST3(NON,     1, 1), ParserSyms);
	ParserSyms:=COMP2( LISTS("NOTT"),   LIST3(NON,     1, 1), ParserSyms);
	ParserSyms:=COMP2( LISTS("NON"),    LIST3(NON,     1, 1), ParserSyms);
	ParserSyms:=COMP2( LISTS("~"),      LIST3(NON,     1, 1), ParserSyms);
	ParserSyms:=COMP2( LISTS("--"),     LIST3(NON,     1, 1), ParserSyms);
	ParserSyms:=COMP2( LISTS("FORALL"), LIST3(FORALL, -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("ALL"),    LIST3(FORALL, -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("FA"),     LIST3(FORALL, -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("EX"),	    LIST3(EXIST,  -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("EXIST"),  LIST3(EXIST,  -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("EXISTS"),  LIST3(EXIST,  -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("E"),      LIST3(EXIST,  -2, 6), ParserSyms);
	ParserSyms:=COMP2( LISTS("EQUIV"),  LIST3(EQUIV,   2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("<===>"),  LIST3(EQUIV,   2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("<=>"),    LIST3(EQUIV,   2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("IMP"),    LIST3(IMP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("IMPL"),   LIST3(IMP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("===>"),   LIST3(IMP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("==>"),    LIST3(IMP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("=>"),     LIST3(IMP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("REP"),    LIST3(REP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("REPL"),   LIST3(REP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("<==="),   LIST3(REP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("<=="),    LIST3(REP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("<="),     LIST3(REP,     2, 4), ParserSyms);
	ParserSyms:=COMP2( LISTS("XOR"),    LIST3(XOR,     2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("ANTIV"),  LIST3(XOR,     2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("+"),      LIST3(XOR,     2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("<=/=>"),  LIST3(XOR,     2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("</>"),    LIST3(XOR,     2, 5), ParserSyms);
	ParserSyms:=COMP2( LISTS("<#>"),    LIST3(XOR,     2, 5), ParserSyms);
END InitParser;

PROCEDURE upcase(clist:LIST):LIST;
(* upcase character list. clist is a character list. 
All letters in clist are converted to upper case. The result is returned. *)
	VAR c:GAMMAINT;
	VAR result:LIST;
BEGIN
	result:=SIL;
	WHILE clist<>SIL DO
		ADV(clist,c,clist);
		IF LETTER(c) AND MASEVEN(c) THEN
			result:=COMP(c+1,result);
		ELSE
			result:=COMP(c,result);
		END;
	END;
	RETURN INV(result);
END upcase;

(******************************************************************************
*                     R E A D   I N F I X   F O R M U L A                     *
******************************************************************************)

PROCEDURE FORIREAD(bbread:PROCF0):LIST;
(* formula infix read. bbread is a bb-procedure to read a bb.formula from the 
input stream. This procedure reads a formula in infix notation 
from the input stream and returns the read formula. *)
	VAR c: GAMMAINT;
	VAR result, info, sym, noargs, args, key, dummy: LIST;
	VAR opstack, argstack: LIST;
	VAR parlevel: LIST; (*parenthesis level*)
	VAR expectop: BOOLEAN; (* expect operator symbol. If expectop is true 
				  then the next symbol must be an operator. *)
	VAR exitifparl0: BOOLEAN; 
BEGIN
	(* to do; correct use of exitifparl0
	          poping unary operation from operator stack, if an arguments 
	          is pushed on the argument stack. *)

	opstack:=SIL;
	argstack:=SIL;
	expectop:=FALSE;
	parlevel:=0;
	c:=CREADB();
	BKSP();
(*	IF c=MASORD("(") THEN 
		exitifparl0:=TRUE;
	ELSE
		exitifparl0:=FALSE;
	END; *)
exitifparl0:=FALSE;
	LOOP
		c:=CREADB();
		IF c=70 (* c=MASORD("(") *)  THEN
			parlevel:=parlevel+1; 
			push(LIST3(70,-99,99),opstack);			
			IF expectop THEN 
				DIBUFF();
				ERROR(severe,"operator expected");
			END;
		ELSIF c=71 (* c=MASORD(")") *) THEN
			IF parlevel<=0 THEN
				DIBUFF();
				ERROR(severe,"incorrect parenthesis");
			END;
			IF NOT expectop THEN 
				DIBUFF();
				ERROR(severe,"argument expected")
			END;
			parlevel:=parlevel-1;
			gensubformula(99,opstack,argstack);
			pop(dummy,opstack);
			IF FIRST(dummy)<>70 THEN
				DIBUFF();
				ERROR(severe,"incocrect parenthesis");
			END;
			IF exitifparl0 THEN EXIT; END;
		ELSIF c=85 (* c=MASORD("[") *) THEN
			IF expectop THEN
				DIBUFF();
				ERROR(severe,"operator expected");
			END;
			expectop:=TRUE; 
			BKSP();
			result:=atomicread(bbread);
			push(result,argstack);
		ELSIF c=75 (* c=MASORD("#") *) THEN 
			IF expectop THEN 
				DIBUFF();
				ERROR(severe,"operator expected");
			END; 
			push(rdmasvar(),argstack);
			expectop:=TRUE;
		ELSIF c=62 (* c=MASORD(".") *) THEN 
			EXIT;
		ELSE
			BKSP();
			key:=KEYREAD();
			result:=upcase(key);
			info:=ASSOCQ(result,ParserSyms);
			IF info=SIL THEN 	(* treat as a variable. *)
				IF expectop THEN 
					DIBUFF();
					ERROR(severe,"operator expected");
				END;
				push(FORRDVARA(key,BOOL),argstack);
				expectop:=TRUE; 
			ELSE				
				info:=FIRST(info);			
				sym:=FIRST(info);
				noargs:=SECOND(info); (* number of arguments *)
				IF noargs=0 THEN
					IF expectop THEN 
						DIBUFF();
						ERROR(severe,"operator expected");
					END;
					expectop:=TRUE;
					push(FORMKCNST(sym),argstack);
				ELSIF noargs=1 THEN 
					IF expectop THEN 
						DIBUFF();
						ERROR(severe,"operator expected")
					END;
					pushop(info,opstack,argstack);
				ELSIF noargs=2 THEN 
					IF NOT expectop THEN 
						DIBUFF();
						ERROR(severe,"argument expected");
					END;
					pushop(info,opstack,argstack);
					expectop:=FALSE;
				ELSIF noargs=-1 THEN 
					IF NOT expectop THEN 
						DIBUFF();
						ERROR(severe,"argument expected");
					END;
					pushop(info,opstack,argstack);
					expectop:=FALSE;
				ELSIF noargs=-2 THEN
					IF expectop THEN 
						DIBUFF();
						ERROR(severe,"operator expected");
					END;				 
					rdquanta(info,
						opstack,argstack,bbread);
				ELSE
					ERROR(severe,"parity not valid");
					pushop(info,opstack,argstack);
				END;
			END
		END;
	END;
	IF parlevel>0 THEN 
		DIBUFF();
		ERROR(severe,"incorrect parenthesis");
	END;
	RETURN genformula(opstack,argstack);
END FORIREAD;

PROCEDURE pushop(op:LIST;VAR opstack, argstack:LIST);
(* push operator. Op is a list which describes an operator. opstack, argstack
are the internal stacks of the parser. An operator is pushed to the 
opstack. Subformuls are generated if it is possible. *)
	VAR sym, noargs, prio, lastop, lastsym, lastnoargs, lastprio:LIST;
	VAR phi:LIST;
BEGIN
	IF opstack=SIL THEN push(op,opstack); RETURN; END;
	sym:=FIRST(op);
	noargs:=SECOND(op); (* number of arguments *)
	prio:=THIRD(op);
	lastop:=FIRST(opstack);
	lastsym:=FIRST(lastop);
	lastnoargs:=SECOND(lastop);
	lastprio:=THIRD(lastop);
	IF prio<lastprio THEN
		push(op,opstack);
		RETURN;
	ELSIF prio>lastprio THEN
		gensubformula(prio,opstack,argstack);
		push(op,opstack);
	ELSIF prio=lastprio THEN
		IF noargs=1 THEN
			push(op,opstack);
		ELSIF (noargs>1) THEN
			gensubformula(prio,opstack,argstack);
			push(op,opstack);
		ELSIF (noargs=-1) AND (sym=lastsym) THEN
			push(op,opstack);
		ELSIF (noargs=-1) AND (sym<>lastsym) THEN
			gensubformula(prio,opstack,argstack);
			push(op,opstack);
		ELSIF noargs=-2 THEN
			IF lastnoargs=-2 THEN 
				push(op,opstack);
			ELSE 
				gensubformula(prio,opstack,argstack);
				push(op,opstack);
			END;
		ELSE
			DIBUFF();
			ERROR(severe,"INTERNAL ERROR (pushop): wrong noargs ");
		END;	
	(* ELSE  impossible *)
	END;
END pushop;

PROCEDURE push(elem:LIST; VAR stack:LIST);
(* push. push the element elem to the stack stack. *)
BEGIN
	stack:=COMP(elem,stack);
END push;

PROCEDURE pop(VAR elem, stack:LIST);
(* pop. pop the elem elem from the stack stack.  *)
BEGIN
	IF stack=SIL THEN
		ERROR(fatal,"POP: pop to empty stack");
		elem:=SIL;
		RETURN;
	ELSE
		ADV(stack,elem,stack);
		RETURN;
	END;
END pop;

PROCEDURE pop2(VAR elem1,elem2,stack:LIST);
(* pop two elements. pop two elements elem1 and elem2 from the stack stack. *)
BEGIN
	IF (stack=SIL) OR (RED(stack)=SIL) THEN
		ERROR(fatal,"POP2: pop to empty stack");
		elem1:=SIL;
		elem2:=SIL;
		RETURN;
	ELSE
		ADV2(stack,elem1,elem2,stack);
		RETURN;
	END;
END pop2;

PROCEDURE gensubformula(prio:LIST;VAR opstack,argstack:LIST);
(* generate subformula. Generate a subformula in respect to the stacks 
opstack and argstack. The provedure terminates, if either opstack is empty
or the priority of the top of the opstack is lower (i.e prio has a numeric
lower value than the priority of the top of the stack opstack.) than prio. *)
	VAR lastop, lastsym, lastnoargs, lastprio, result: LIST;
	VAR arg, arg1, arg2: LIST;
BEGIN
	WHILE (opstack<>SIL) AND (THIRD(FIRST(opstack))<=prio) 
		AND (FIRST(FIRST(opstack))<>70) DO
		pop(lastop,opstack);
		lastsym:=FIRST(lastop);
		lastnoargs:=SECOND(lastop);
		lastprio:=THIRD(lastop);
		IF lastnoargs=1 THEN 
			pop(arg,argstack);
			push(FORMKUNOP(lastsym,arg),argstack);
		ELSIF lastnoargs=2 THEN
			pop2(arg2,arg1,argstack);
			push(FORMKBINOP(lastsym,arg1,arg2),argstack);
		ELSIF lastnoargs=-1 THEN
			aanop(lastsym,opstack,argstack);
		ELSIF lastnoargs=-2 THEN
			pop2(arg2,arg1,argstack);
			push(FORMKQUANT(lastsym,arg1,arg2),argstack);
		ELSE
			DIBUFF();
			ERROR(severe,"INTERNAL ERROR (gensubf): wrong noargs");
		END; 
	END;
END gensubformula;

PROCEDURE genformula(VAR opstack,argstack:LIST):LIST;
(* generate formula. The stacks opstack and argstack are taked down. The 
resulting formula is returned. *)
	VAR result:LIST;
BEGIN
	IF opstack=SIL THEN 
		IF argstack=SIL THEN RETURN VERUM; END;
		ADV(argstack,result,argstack);
	ELSE
		gensubformula(99,opstack,argstack);
		ADV(argstack,result,argstack);
	END;
	RETURN result;
END genformula;

PROCEDURE aanop(lastsym:LIST;VAR opstack,argstack:LIST);
(* arbitrary argument number operation. An operator vel or et is taken from 
the opstack. *)
	VAR arg,arg1,arg2, arglist, op: LIST;
BEGIN	
	arglist:=SIL;
	pop2(arg2,arg1,argstack);
	arglist:=LIST2(arg1,arg2);
	WHILE (opstack<>SIL) AND (FIRST(FIRST(opstack))=lastsym) DO
		ADV(opstack,op,opstack);
		ADV(argstack,arg,argstack);
		arglist:=COMP(arg,arglist);
	END;
	push(FORMKFOR(lastsym,arglist),argstack);
	RETURN;
END aanop;

PROCEDURE rdvlist():LIST;
(* formula read list of variables. One variable or a list of variables are 
read from the input stream. *)
	VAR c: GAMMAINT;
	VAR var, vlist: LIST;
BEGIN
	vlist:=SIL;
	c:=CREADB();
	WHILE (c<>79) AND (c<>70) (* MASORD(":") MASORS("("). *) DO
		BKSP();
		var:=FORRDVAR();
		vlist:=COMP(var,vlist);
		c:=CREADB();
		IF c=63 (* c=MASORD(",") *) THEN c:=CREADB(); END;
	END;
	IF c=70 THEN BKSP(); END;
	RETURN FORMKLVAR(INV(vlist));
END rdvlist; 

PROCEDURE rdquanta(quant:LIST; VAR opstack, argstack:LIST;bbread:PROCF0);
(* formula read quantifier arguments. quant is a symbol for a quantifier,
opstack and argstack are the internal stacks of the parser. 
The symbol quant is pushed to the opstack, a list of variables is read 
from the input stream and is pushed to the argstack. *)
	VAR c:GAMMAINT;
	VAR varlist,phi,vars,alist:LIST;
BEGIN
	c:=CREADB();
	IF c=70 THEN
		BKSP();
		alist:=FORRDQUANTA(bbread);
		vars:=FIRST(alist);
		phi:=SECOND(alist);
		push(FORMKQUANT(quant,vars,phi),argstack);
		RETURN;
	END;
	BKSP();
	varlist:=rdvlist();
	pushop(quant,opstack,argstack);
	push(varlist,argstack);
END rdquanta;

PROCEDURE rdmasvar():LIST; 
(* read mas variable. The next symbol s of the input stream is read and the 
value of the mas interpreter variable with name s is returned. *)
	VAR s: LIST;
	VAR V,var,val: LIST;
BEGIN
	V:=ENV;
	s:=SREAD();
	WHILE (V<>SIL) DO
		ADV2(V,var,val,V);
		IF var=s THEN RETURN val END; 
	END;
	DIBUFF();
	ERROR(severe,"not defined as a mas variable"); 
	RETURN VERUM;
END rdmasvar;

PROCEDURE isvarname(name:LIST):BOOLEAN;
(* is variable name. name is a CLIST. returns true if the first character 
of name is a letter and all following charaters are letters or digits. *)
	VAR c: LIST;
BEGIN
	IF name=SIL THEN RETURN FALSE; END;
	ADV(name,c,name);
	IF NOT LETTER(c) THEN RETURN FALSE; END;
	WHILE name<>SIL DO 
		ADV(name,c,name);
		IF NOT(LETTER(c) OR DIGIT(c)) THEN RETURN FALSE; END;
	END;
	RETURN TRUE;
END isvarname; 

(******************************************************************************
*                                   M A I N                                   *
******************************************************************************)

BEGIN
	InitParser();
END MLOGIO.