public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return(false); } ASTOpUnary other = obj as ASTOpUnary; return(this.value == other.value && this.ast.Equals(other.ast)); }
private void Extract(AST astInCNF) { switch (astInCNF.GetType().Name) { case "ASTProp": char letter = (astInCNF as ASTProp).value; m_content.Add(new Component(letter)); break; case "ASTOpUnary": ASTOpUnary astNeg = astInCNF as ASTOpUnary; if (astNeg.ast.GetType().Name != "ASTProp") { // In CNF form, the negation can only refers to a simple proposition. throw new Exception("Error creating a CnfOr : In CNF form, the negation can only refers to a simple proposition."); } letter = (astNeg.ast as ASTProp).value; m_content.Add(new Component(letter, true)); break; case "ASTOpBinary": ASTOpBinary opBin = astInCNF as ASTOpBinary; switch (opBin.value) { case Language.Symbol.OU: // Form (A|B). Extract(opBin.left); Extract(opBin.right); break; case Language.Symbol.E: // Form (A&B). case Language.Symbol.IMPLICA: // Form (P->Q). case Language.Symbol.EQUIVALE: // Form (P<->Q). throw new Exception("Error creating a CnfOr : In CNF form, OR formulas can't contain other operators than OR."); } break; } }
/// <summary> /// Parsing recursive implementation. /// </summary> /// <param name="precede">does precedence must be considered in this recursive call?</param> /// <returns>the resulting AST node.</returns> AST Walk(bool precede = false) { // Increment the global index. m_idx++; if (m_idx >= Tokens.Count) { return(null); } // Read the current index's token value. Token token = Tokens[m_idx]; AST ast = null; switch (token.type) { case Language.Symbol.PROP: // a propositional letter. ast = new ASTProp(token.value); break; case Language.Symbol.NAO: // negation operation. ast = new ASTOpUnary(Walk(true), token.type); break; case Language.Symbol.E: // conjunction operation. case Language.Symbol.OU: // disjunction operation. ast = new ASTOpBinary(m_current, Walk(true), token.type); break; case Language.Symbol.IMPLICA: // implication operation. case Language.Symbol.EQUIVALE: // double implication operation. // double implication has lesser precedence over single implication. bool bi = token.type == Language.Symbol.EQUIVALE; // must continue to parse? bool forward = // we continue parsing if... m_implFlag == 0 || // ... there is no implications awaiting or ... (m_implFlag == 2 && !bi); // ... a double implication awaits and the current is a single implication. if (forward) { // must continue the parsing. // save current implication flag value... int implications = m_implFlag; // and update the global value. m_implFlag = bi ? 2 : 1; // enter another recursion. ast = new ASTOpBinary(m_current, Walk(false), token.type); // did the last recursive call finished precedence analysis? if (m_implFlag == 0) { precede = false; } // restore previous (saved) implication flag value. m_implFlag = implications; } else { // must not continue and must return to the last call. m_idx--; ast = m_current; precede = true; m_implFlag = 0; break; } break; case Language.Symbol.ABERTURA: // opening expression symbol. // enter a new recursive call, as an AST node must come from the parenthesis' content analysis. while (Walk(precede) != null) { ast = m_current; } break; case Language.Symbol.FECHAMENTO: // closing expression symbol. return(null); } // update current AST node. m_current = ast; // continue the processing as long as there are tokens and no precedence. if (!precede && m_idx < Tokens.Count) { Walk(); } return(m_current); }
} // Extractor class #endregion Inner classes #region Public functions /// <summary> /// Convert the formula to conjuntive normal form. /// </summary> /// <param name="ast">original abstract syntatic tree representinf the formula.</param> /// <returns>formula in CNF.</returns> public static AST Convert(AST ast) { if (ast == null) { return(ast); } switch (ast.GetType().Name) { case "ASTProp": return(ast); case "ASTOpBinary": ASTOpBinary opBin = ast as ASTOpBinary; switch (opBin.value) { case Language.Symbol.E: // Form (P&Q). AST left = Convert(opBin.left); AST right = Convert(opBin.right); return(new ASTOpBinary(left, right, Language.Symbol.E)); case Language.Symbol.OU: // Form (P|Q). left = Convert(opBin.left); right = Convert(opBin.right); return(Distribute(left, right)); case Language.Symbol.IMPLICA: // Form (P->Q). Equivalent to (~P|Q) return(Convert( new ASTOpBinary( new ASTOpUnary(opBin.left, Language.Symbol.NAO), opBin.right, Language.Symbol.OU) )); case Language.Symbol.EQUIVALE: // Form (P<->Q). Equivalent to (P&Q)|(~P&~Q). left = new ASTOpBinary(opBin.left, opBin.right, Language.Symbol.E); right = new ASTOpBinary( new ASTOpUnary(opBin.left, Language.Symbol.NAO), new ASTOpUnary(opBin.right, Language.Symbol.NAO), Language.Symbol.E ); return(Convert(new ASTOpBinary(left, right, Language.Symbol.OU))); } break; case "ASTOpUnary": AST p = (ast as ASTOpUnary).ast; switch (p.GetType().Name) { case "ASTProp": // Form ~P ... return ~P return(ast); case "ASTOpUnary": // Form ~(~P) - double negation ... return Convert(P) return(Convert((p as ASTOpUnary).ast)); case "ASTOpBinary": opBin = (ASTOpBinary)p; Language.Symbol op = opBin.value; if (op != Language.Symbol.E && op != Language.Symbol.OU) { // Not yet in CNF. AST pInNcf = Convert(p); return(Convert(new ASTOpUnary(pInNcf, Language.Symbol.NAO))); } AST left = new ASTOpUnary(opBin.left, Language.Symbol.NAO); AST right = new ASTOpUnary(opBin.right, Language.Symbol.NAO); Language.Symbol deMorganOp = Language.Symbol.INVALIDO; if (opBin.value == Language.Symbol.E) { // Form ~(P&Q): from DeMorgan's Law, return Convert(~P|~Q) deMorganOp = Language.Symbol.OU; } else if (opBin.value == Language.Symbol.OU) { // Form ~(P|Q): from DeMorgan's Law, return Convert(~P&~Q) deMorganOp = Language.Symbol.E; } return(Convert(new ASTOpBinary(left, right, deMorganOp))); } break; } return(null); }
public NegationProposition(ASTOpUnary ast) : base(ast) { }
// transitional constructor. public UnaryOperation(ASTOpUnary ast) { P = Proposition.FromAST(ast.ast); }