protected IEnumerable <Proposition> ConvertFromAST(AST ast, Language.Symbol oper) { if (ast == null) { return(null); } List <Proposition> result = new List <Proposition>(); string type = ast.GetType().Name; if (type == "ASTOpBinary") { ASTOpBinary opBin = ast as ASTOpBinary; if (opBin.value == oper) { result.AddRange(ConvertFromAST(opBin.left, oper)); result.AddRange(ConvertFromAST(opBin.right, oper)); return(result); } } // else result.Add(Proposition.FromAST(ast)); return(result); }
// transitional constructor. public MultipleOperation(AST ast, Language.Symbol oper = Language.Symbol.INVALIDO) { if (oper == Language.Symbol.INVALIDO && ast.GetType().Name == "ASTOpBinary") { oper = (ast as ASTOpBinary).value; } m_props = new List <Proposition>(ConvertFromAST(ast, oper)); }
} // 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); }
/// <summary> /// Tokenization function /// </summary> /// <param name="expr">Logic expression to tokenize</param> /// <returns>If tokenization succedded. If not, see the erros in Errors attribute.</returns> public bool Tokenize(string expr = "") { if (expr != "") Expr = expr; int opened = 0; Error = new List<string>(); // Go through all the expression. for (int i = 0; i < expr.Length; i++) { // Get the symbol of the character in current position. char token = expr[i]; Language.Symbol symbol = Language.Lang.SymbolOf(token); if (symbol == Language.Symbol.INVALIDO) { // Symbol unknown. CreateError(ERR_UNKNOWNSYMBOL, token, i); continue; } bool isValid; // is the token valid to its position? string valid; // valid tokens for the token's position. if (Tokens.Count == 0) { // starting of the expression. // Token is a valid initial? isValid = Language.Lang.IsValidInitial(token); // Get the valid initial tokens set. valid = string.Join<Language.Symbol>(",", Language.Lang.Initial); } else { // middle of the expression. // Token as valid as a follower of the previous symbol? Language.Symbol previous = Tokens.Last().type; isValid = Language.Lang.Follows(symbol, previous); // Get the valid symbols for the previous one. valid = string.Join<Language.Symbol>(",", Language.Lang.Expected[previous]); } if (isValid) { // token detected as valid. if (symbol != Language.Symbol.VAZIO) // empty symbols/tokens are ignored. Tokens.Add(new Token(symbol, token)); // add the token to the extracted tokens list. } else { // Token is not valid to its position. CreateError(ERR_SYMBOL, new object[] { token, i, valid }); continue; } // Add or subtract the opening counting. if (symbol == Language.Symbol.ABERTURA) opened++; if (symbol == Language.Symbol.FECHAMENTO) opened--; } if (opened != 0) { // Opening and closing counts doesn't match. // Gets the exceding symbol/token and create error accordingly. char paren = opened < 1 ? ')' : '('; CreateError(ERR_PARENS, new object[] { Math.Abs(opened), paren }); } return Error.Count == 0; }
// Constructor. public ASTOpUnary(AST ast, Language.Symbol value) { this.value = value; this.ast = ast; }
// Constructor. public ASTOpBinary(AST left, AST right, Language.Symbol value) { this.left = left; this.right = right; this.value = value; }
// Construtor. public Token(Language.Symbol symbol, char value) { this.type = symbol; this.value = value; }