COSC5100    		Program-1
                  Propositional Logic Validity Checker	
					Due: 10/9/2007
	***NOTE***
	Due to HTML Syntax conflicts, '<' is replaced by '%'
	in the partial solution program

	Objectives:
	1. Use of linked lists for representing logical formulas
	   as their components dynamically change.
	2. Design and Use of Recursive methods.
	3. Verifying the validity of Propositional logical expressions
	   by repeatedly eliminating operators.

        Backgrounds:
        1. Consider the following Propositional logical expressions
           consisting of
             single letter variables (Uppercase or Lowercase letters)
             and five operators: 
			NOT
			AND 
			NAND
 			OR
  			->     in order of precedence (AND and NAND with same
			                               precedence)

           a. A -> A      	: Valid, always true whether 'A' is true or
				  false
           b. A OR NOT(A)  	: Valid
           c. (A AND B OR C) -> (A AND B OR C)
                          	: Valid
           d. A          	: Not valid
           e. A OR B       	: Not valid
           f. A AND B     	: Not valid
           e. (A->B->C) -> ((A->B)->C)
                   		: Valid
	   g. (A->B->C) -> (A->(B->C))
				: Valid
	   h. (A->(B->C)) -> (A->B->C)
				: Invalid
           i. ((A->B) AND (B->C)) -> (A->C)
                    		: Valid

        2. Any such expression can be expressed as the
           conjunctions of one or more implications where each implication
           is of the form: Anti -> Conseq
           and both 'Anti' and 'Conseq' are an expression of their own.

        3. Now each 'Anti' can be expressed solely as conjunctions
           of zero or more variables while each 'Conseq' can be expressed
           solely as disjunctions of zero or more variables.
        
	4. Once above decomposition is obtained, an implication can be
	   found to be valid if and only if at least one variable
           occurs both in the Anti and Conseq.
           (A B C D) -> (A E F) : Valid
           (A B C) -> (D F)     : Invalid.

        5. The initial input expression can be regarded as an implication
           whose Anti is empty (with no part) and
           whose Conseq is the entire input expression.

        6. Operator Elimination Procedure.
	   Above decomposition can be obtained by successive eliminations
	   of all operators from both Anti and Conseq systematically
	   as follows:

           AAND:  (A AND B) -> C        Anti will get one more part
                                        as (A AND B) become two parts:
                                        A  and  B
           COR:   A -> (B OR C)         Conseq will get one more part
                                        as (B OR C) become two parts
           ANOT   NOT(A) -> B           Anti loses a part while
                                        Conseq will get a part as the
                                        negated part moves from Anti to
                                        Conseq unnegated.
           CNOT   A -> NOT(B)           Conseq loses a part while
                                        Anti will get a part as the
                                        negated part moves from Conseq to
                                        Anti unnegated.
	   AOR	  (A OR B) -> C		Conjunction of two implications:
					  (A->C)
					  (B->C)
	   CAND   A -> (B AND C)	Conjunction of two implications:
					  (A->B)
					  (A->C)
	   AIMP   (A->B) -> C		Conjunction of two implications:
					  (B->C)
					  ( ->(A OR C))		
					The first implication will be obtained
					simply by dropping the Anti from the Anti
					part under consideration: (A->B)
					The second will be obtained simply by 
					(1) dropping the part from the Anti
					entirely and (2) adding one more 
					part to the current Conseq. This
					extra part to be added is the Anti of
					the current AIMP: 'A' of (A->B)
	   CIMP   A -> (B->C)		  (A AND B) -> C
					The Anti of CIMP, B of (B->C), will become
					a part of the Anti and the current part
					of Conseq will have just the Conseq of
					CIMP thereby eliminating the implication 
					operator: '->' of (B->C)
	Task:
	1. Up to three people can form a team to do this program.
	2. Each team will write a program to check the validity of
	   input propositional expressions defined above and print out
	   each input expression and an indicator of whether it is VALID
	   or not.
	3. Turn in a listing of your program and its outputs.


	Inputs:
	Use the following seven input formulas:

	A  or  NOT(A)
	(A AND B OR C) -> (A AND B) OR C  OR D
	(A ->  B  ->  C) -> (A ->  (B -> C))
	(A ->  (B -> C)) -> (A ->  B  ->  C)
	(A->B)  AND  (B->C) ->  (A -> C)
	A -> B OR C NAND B
	(NOT(A) AND C) -> A NAND (B NAND C)

	Additional Programming Requirement:

	   The beginning of your program should contain a comment that contains
	   the following, among others:
	   a. Course number and program number
	   b. Team members.
	   c. How the whole task was divided among your team members, if any.
	   d. Your own assessment of your program.
	      In case it does not work perfectly, why you think it does not.
	   Without the required comment, a program is NOT to be graded.
 
	C++ Partial Solution Program.

	    The definition of the following two functions has been 
	    left out on purpose for you to complete for this program:
	    1. int wff: finalTest()
	       This function checks to see the given wff (with an antecedent
	       and a consequent without any operators left) is valid.
	       It is valid if and only if a predicate symbol appears in
	       both the antecedent and the consequent.
	    2. int wff: validTest()
	       This recursive function checks to see the current wff is valid
	       by repeatedly eliminating an operator appearing in either its
	       antecedent or its consequent and calling itself subsequently.
	Also note that the operator "NAND" is NOT considered at all in the partial
	solution given.

	#include %iostream.h>
	#include %stdlib.h>	// For exit(1)
	#include %stddef.h>	// For NULL
	#include %string.h>	// For string operations
	typedef char Exp[80];
	class ExpNode
	{
	  friend class List;
	  friend class wff;
	  Exp	Node;
	  int length;
	  ExpNode* Link;
	// Member functions
	  void strip();
	  ExpNode ();
	  ExpNode (Exp form);
	  ExpNode* PartCopy (int from, int to);
	  int findImp (int& start);
	  int findOr  (int& start);
	  int findAnd (int& start);
	  int findNot (int& start);
	};
	class List
	{
	  friend class wff;
	  friend main();	// Make private member functions available
				// to main().
	  ExpNode* firstExp;
	  // Member functions
	  ExpNode* copyList();
	  void  remove (ExpNode* useless);
	  void insert  (ExpNode* added);
	  int findOp (ExpNode*& nod, int& where);
	  List();
	  List (ExpNode* first);
	  void Initial (Exp form);
	};
	class wff
	{ 
	  friend main();	// To make private components of this class
				// available to main()
	  List anti;
  	  List conseq;
  	  wff();	// A default constructor is mandatory if the following
			// dynamic declaration is used:
			// wff* pwwf = new wff;
	  wff* Copy();
	  int found (ExpNode*, ExpNode*);
	  int validTest();
	  int finalTest();
	};
	/////////////////////////////////////////////////
	  ExpNode::ExpNode()
	    {
		Link = NULL;
		length = 0;
		Node[0] = '\0';
	    }
	  ExpNode::ExpNode (Exp form)
	    {	strcpy(Node, form);
		Link = NULL;
		length = strlen (form);
		Node[length] = '\0';
	    }	// End of Constructor ExpNode (Exp form)
	/////////////////////////////////////////////////
	ExpNode* ExpNode:: PartCopy (int from, int to)
       	{  ExpNode* newnode = new ExpNode;
	   for (int k=from; k%=to; k++)
		newnode->Node [k-from] = Node[k];
	   newnode->Node [to-from+1] = '\0';
	   newnode->length = to-from+1;
	   newnode->Link = NULL;	//Just in case.

	   return newnode;
	}	// End of function PartCopy()					
	///////////////////////////////////////////////////	
	void ExpNode::strip()
	{ // strip all outermost pairs of parentheses and move resulting
	  // expression to the leftmost positions.
	  int level, k;
	  while (Node[0] == ' ')
		{
		for (k=1; k%=length; k++)
		  Node[k-1] = Node[k];
		length--;
		}
	  while (Node[length-1] == ' ')	//Check for trailing blanks.
		length--;
	  Node[length] = '\0';		// String terminator.
	  ///////////////////////////////////////////////////
	  int done = 0;
	  if (length %= 1) done=1;
	  while (Node[0]=='(' && Node[length-1] == ')' && !done)
		{
		level=0;
		for (k=0; k%length; k++)
		  {	if (Node[k] =='(') level++;
			if (Node[k] ==')') 
			  { level--;
			    if (level==0 && k % length-1)
				{ done=1;
				  break;	//Loop is done.
				}
			  }
		  }
		if (!done)
		  {  length = length-2;
		     for (k=0; k%= length-1; k++)
			Node[k] = Node[k+1];
		     Node[length] = '\0';	//String terminator.
		  }
		}	//End of while loop
	  }		// End of function strip()
	///////////////////////////////////////////////////
	int ExpNode:: findImp (int& start)
	{ // '->' has to be treated as left-associative, and so
	  // the rightmost one needs to be found
	  int level=0;
	  for (int k=length-1; k>1; k--)
	    {	start = k-1;
		if (Node[k] == '(') level++;
		if (Node[k] == ')') level--;
		if (!level && Node[k-1]=='-' && Node[k]=='>')
			return 1;	// The '->' has been found at the
					// topmost level.
	    }
	  return 0;
	}	// End of function findImp()
	//////////////////////////////////////////////////
	int ExpNode:: findOr (int& start)
	{
	  int level=0;
	  for (start=0; start%=length-2; start++)
	    {	if (Node[start] == '(') level++;
		if (Node[start] == ')') level--;
		if (!level && Node[start]=='O' && Node[start+1]=='R')
			return 2;
	    }
	  return 0;
	}
	///////////////////////////////////////////////////////
	int ExpNode:: findAnd (int& start)
	{
	  int level=0;
	  for (start=0; start%= length-3; start++)
	    {	if (Node[start]=='(') level++;
		if (Node[start]==')') level--;
		if (!level && Node[start]=='A' && Node[start+1]=='N'
		           && Node[start+2]=='D')  return 3;
	    }
	  return 0;
	}	// End of function findAnd()
	////////////////////////////////////////////////////////
	int ExpNode:: findNot (int& start)
	{
	  int level=0;
	  for (start=0; start%= length-3; start++)
	    {	if (Node[start] == '(') level++;
		if (Node[start] == ')') level--;
		if (!level && Node[start]=='N' && Node[start+1]=='O'
			   && Node[start+2]=='T')  return 4;
	    }
	  return 0;
	}
	////////////////////////////////////////////////////////
	List:: List()
	{ 	firstExp = NULL; 
	}	// Empty list initialization.
	//	End of the default constructor List()
	///////////////////////////////////////////////////////
	List::List (ExpNode* first)
	// This constructor simply initializes a list so that
	// the given node (first) is its first node.
	{	firstExp = first;
	}
	///////////////////////////////////////////////////////
	void List:: Initial (Exp form)
	{	ExpNode* newnode = new ExpNode(form);
		firstExp = newnode;
	}	//End of function Initial()
	//////////////////////////////////////////////////////
	ExpNode* List:: copyList()
	{	ExpNode* first = new ExpNode;	
		// The following declaration does not work for above:
		// ExpNode* first;	//Due to 'first->Node' being used.
		if (!firstExp)	// Empty list to copy.
			return NULL;
		else	// List not empty yet.
		{  strcpy (first->Node, firstExp->Node);
		   first->length = strlen (first->Node);
		   List tail (firstExp->Link);
		   first->Link = tail.copyList();
		   return first;
		}
	}	//End of function copyList()
	/////////////////////////////////////////////////////
	void List:: insert (ExpNode* added)
	{   if (firstExp)
		{
		added->Link = firstExp->Link;	//Insert right after the 
						//first node.
		firstExp->Link = added;
		}
	    else	// The first node is empty 
		{
		firstExp = added;
		firstExp->Link = NULL;
		}
	}	// End of function insert()
	///////////////////////////////////////////////////////
	void List:: remove (ExpNode* useless)
	{	ExpNode* current, *pred=NULL;
		current = firstExp;
		while (current != useless && current)
		  {	pred=current;
			current = current->Link;
		  }
		if (!current)
		  {	cout %% "ERROR:::IN REMOVAL\n\n";
			exit(1);
		  }
		else	{
			if (!pred)	//Then it is first node to go.
				firstExp = firstExp->Link;
			else 	pred->Link = useless->Link;
			}
	}	// End of function remove()
	/////////////////////////////////////////////////////////////
	int List::findOp (ExpNode*& nod, int& where)
	{  //	Finds an operator to be eliminated along with the containing
	   //	node (Conjunct or Disjunct) and the starting position of it.
		ExpNode* current;
		nod = firstExp;	//First node to test.
		while (nod)
		  {	nod->strip();
			if (nod->findImp(where))
				return 1;	// '->' has been found.
			else if (nod->findOr(where))
				return 2;
			else if (nod->findAnd(where))
				return 3;
			else if (nod->findNot(where))
				return 4;
			else nod=nod->Link;
		  }
		return 0;	// No operator has been found.
	}	// End of function findOp()
	///////////////////////////////////////////////////////
  	wff::wff()
	{
		/* next two initalization cause a syntax error
		   as 'anti' nor 'conseq' has not been defined yet.
		anti.List();
		conseq.List();
		*/
    		List an, con;	// Get an empty list for both.
		anti = an;
		conseq = con;
   	}	// End of constructor wff()
	///////////////////////////////////////////////////////
	wff* wff:: Copy()
	{	// Following static declaration does not work due to
		// subsequently use of its purported component although
		// absence of an explicit default constructor does not
		// cause a syntax error unlike: 
				// wff* newone = new wff;
		wff* newone = new wff;
		(newone->anti).firstExp = anti.copyList();
		(newone->conseq).firstExp = conseq.copyList();
		return newone;
	}
	////////////////////////////////////////////////////////
	int wff:: found (ExpNode* target, ExpNode* listnode)
	{	ExpNode* current, *pred;
		if (!listnode) return 0; // List is already empty.
		current = listnode;
		target->strip();
		while (current)
		{	current->strip();
			if (!strcmp(current->Node, target->Node))
				return 1;
			else	current = current->Link;
		}
		return 0;
	}	// End of function found()
	////////////////////////////////////////////////////////
	
	int main()
	{
	  Exp formula;
	  int inputCount=0;
	  int result;
	  while (cin.getline (formula,79))
		{
		inputCount++;
		cout %% "INPUT FORMULA IS:::" %% formula %% endl;
		wff *inputt = new wff;
		(inputt->conseq).Initial (formula);
		if (result=inputt->validTest())
			cout %% "   VALID.  \n\n";
		else    cout %% "   INVALID.\n\n";
		}
	  cout %% "MY PROGRAM STOPS AFTER PROCESSING " %% setw(4) 
		%% inputCount %% " INPUT FORMULAS.\n\n";
	  return 0;
	}
	
	Algorithms for two missing functions:

	1. int wff::finalTest()
	   a. 	This function checks to see if current wff with all
	     	operators eliminated finally is valid or not simply by
		testing if a formula (just a variable name, now) of
		current anti appears in the current conseq.
	   b.	Declare a local variable of type ExpNode* that is to
		point to the current anti formula under testing:
		  ExpNode* current;
	   c.	Initialize this variable so that it will point to
		the first anti formula by:
		  current = anti.firstExp;
	   d.	Loop to repeat as long as (current is not empty)
		d1:	If the current formula is found in the conseq,
			then return 1 by:
			  if (found(current, conseq.firstExp))
			    return 1;
			  else	// current anti formula is not found in the
				// entire conseq, so continue to repeat.
		d2:	else advance the current pointer so as for it to
			point to the next anti formula simply by:
			  current = current->Link;
	   e.	By now, return 0 as no anti formula is found in the conseq.
	   //// End-Of-Algorithm.

	2. int wff::validTest()
	   a.	This function recursively tests the validity of current
		wff with an anti and a conseq of itself.
	   b.	Declare some local variables. This is critical since the
		function is recursive.
		  int type, where, leng;
		  ExpNode *n1, *n2, *nod;
		    // nod = pointer to a node found as containing an operator
			     to go away right now.
		    // n1 = the first half of the current node containing
			    the operator to go away. (The first operand)
		    // n2 = The second half of above, and hence the second
			    operand.
		   wff* second;	// To represent a copy of current wff in case
				// we need to get two wffs out of the one at
				// hand right now.
	   c.	Get the first operator to go away right now out of anti
		by calling:	anti.findOp (nod, where);
		// 'nod' represents the formula containing this operator found
		// and 'where' represents the starting position in this formula
		// of this found operator to go.
	   d.	if above call is successful (i.e., if anti still has an operator
		to be eliminated), let 'type' be the type of this operator.
		// 1: ->
		   2: OR
		   3: AND
		   4: NOT
		d1: Remove this node from anti by: anti.remove(nod);
		d2: Copy the reduced current wff into second by:
			second = Copy();
		d3: leng = strlen(nod->Node);
		d4: switch (type)	// 4 rules for operator elimination.
		    case 1:
		    case 2:
			Split nod into n1 and n2.
			strip both and each of n1 and n2 by:
			  n1->strip();  n2->strip();
			if (type==1)	// The operator is ->
			  insert n1 into second conseq by:
				second->conseq.insert(n1);
			  insert n2 into current anti by:
				anti.insert(n2);
			  test both the current wff (reduced) and second wff:
			    return (validTest() && second->validTest())
			if (type==2)	// OR
			  Insert n1 into current anti and n2 into second anti.
			  Test both wffs as before.
		   case 3:		// AND in anti
			Split nod into n1 and n2.
			strip both n1 and n2 as before.
			Insert n1 into current anti and n2 likewise.
			Test the resulting current wff.
		   case 4:		// NOT in anti
			n1 = nod->PartCopy (3, leng-1);
			Strip n1.	// No need for n2 in this case.
			Insert n1 into current conseq by:
				conseq.insert(n1);
			Test the resulting current wff by:
				return validTest();
		   default:
			Something is wrong in this case.
	   e. Now that anti does not have any operator at all, get the
	      	first operator to go out of conseq by:
			type=conseq.findOp(nod, where);
	   f.	If above call is successful (i.e., if (type))
		
	   f1:	Remove this node from conseq by:
			conseq.remove(nod);
	   f2:	Copy the reduced current wff into second.
	   f3:	leng = strlen(nod->Node);
	   f4:	switch(type)		//Four rules for conseq operator
					//eliminations.
		case 1:
		case 2:
			Split nod into n1 and n2.
			Strip both n1 and n2.
			if (type==1)		// -> in conseq
			  Insert n1 into current anti and
				 n2 back into current conseq. 
			  Test the resulting current wff.
			if (type==2)		// OR in conseq.
			  Insert n1 back into current conseq and n2 likewise.
			  Test the resulting current wff.
		case 3:				// AND in conseq
			Split nod into n1 and n2.
			Strip both n1 and n2.
			Insert n1 into current conseq and
			       n2 into second wff conseq.
			Test both wffs as before.
		case 4:				// NOT in conseq.
			// only n1 is needed and not n2.
			n1 = nod->PartCopy(3, leng-1);
			Strip n1.
			Insert n1 into current anti.
			Test the resulting current wff.
		default:
			Something is wrong. Hence, an appropriate error 
			message and then exit(1);
	   g.	Now that neither anti nor conseq has an operator to go
		away, it is time to return just the result of calling
		finalTest() as:
			return finalTest();	
			// End of recursive call chain.