def isMacroCall(self,callsite_index): if self.macro_inspector is None: return False if self.macro_inspector.project_dir is None: return False print "Checking Macro Call..." print "UPPER:",self.l[callsite_index] print "CALLINFO:",self.l[callsite_index+1] for m in re.finditer(Syntax.lt+Syntax.identifier+Syntax.water+r"\(",self.l[callsite_index].codestr): funcname=m.group().rstrip("(").strip() if Syntax.isKeyWord(funcname): continue #Note that the second argument of getExpanded is the line_num of the call site code. #So should be callsite_index+1 print "Find Macro Call:",self.l[callsite_index] filename=self.l[callsite_index].get_func_call_info().get_file_name() linenum=self.l[callsite_index].get_linenum() print filename,linenum expanded_str=self.macro_inspector.getExpanded(filename,linenum) if expanded_str is None: return False print "expanded str:",expanded_str if "temp = (((abfd)->xvec->_bfd_check_format[(int) ((abfd)->format)]) (abfd));" in expanded_str: print "Find IT!" call_patttern=Syntax.lt+Syntax.identifier+Syntax.water+r"[\)\]]*"+Syntax.water+r"\(" for m in re.finditer(call_patttern,expanded_str): if ']' in m.group(): return True cleaner=''.join(m.group().split()) clean=cleaner.rstrip('(').rstrip(')') if not Syntax.isKeyWord(clean) and not Syntax.isLibFuncName(m.group(1)): return True return False
def isMacroCall(self,callsite,filename,callinfo): if self.macro_inspector is None: return False if self.macro_inspector.project_dir is None: return False for m in re.finditer(Syntax.lt+Syntax.identifier+Syntax.water+r"\(",callsite.codestr): funcname=m.group().rstrip("(").strip() if Syntax.isKeyWord(funcname): continue #Note that the second argument of getExpanded is the line_num of the call site code. #So should be callsite_index+1 #filename=callsite.get_func_call_info().get_file_name() linenum=callsite.get_linenum() expanded_str=self.macro_inspector.getExpanded(filename,linenum) if expanded_str is None: return False call_patttern=Syntax.lt+Syntax.identifier+Syntax.water+r"[\)\]]*"+Syntax.water+r"\(" for m in re.finditer(call_patttern,expanded_str): if ']' in m.group(): return True cleaner=''.join(m.group().split()) clean=cleaner.rstrip('(').rstrip(')') if not Syntax.isKeyWord(clean) and not Syntax.isLibFuncName(m.group(1)): return True return False
def isLeftPropagate(self,v,codestr): declare_pat=Syntax.declaration_left_propagate_pattern(v) variable_pat=Syntax.variable_left_propagate_pattern(v) print "Left Propagation Pattern:\n",declare_pat,'\n',variable_pat vp_m=re.search(variable_pat,codestr) if vp_m: return vp_m else: dp_m=re.search(declare_pat,codestr) if dp_m: return dp_m else: return None
def handleReturnAssgin(self,job_trace_index,i,accesspattern,var): if i+2+1<len(self.l) and isinstance(self.l[i+1],FunctionCallInfo) and isinstance(self.l[i+2],LineOfCode): if self.l[i+1].get_func_name().split("::")[-1].strip() in self.l[i].codestr or self.isMacroCall(i): indexes=self.slice_same_func_lines(i+2, job_trace_index) count=0 print "accesspattern:",accesspattern for idx in indexes[::-1]: print "Line Under Check:", aIndex, "#",self.l[aIndex] if 'return ' in self.l[idx].codestr: self.TG.linkExpandEdges(job_trace_index,idx,"return dependency:"+var.simple_access_str()) #self.TG.linkTraverseEdges(i,idx,"ref:"+var.simple_access_str()) start=re.search(r'return\s*',self.l[idx].codestr).span()[1] rightpart=self.l[idx].codestr[start:].strip().rstrip(';').strip() if Syntax.isUniqueNonLibCall(rightpart): jobs=self.handleReturnAssgin(job_trace_index,idx,accesspattern,var) return self.taintUp(jobs) else: variable_pat=re.compile('^'+Syntax.variable+'$') m=variable_pat.match(rightpart) if m: rfl,p=accesspattern return self.taintUp([TaintJob(idx,TaintVar(rightpart,p,rfl))]) else: taint_v_strs = Filter.expression2vars(rightpart) jobs=map(lambda x : TaintJob(idx,x),[TaintVar(tv,[]) for tv in taint_v_strs]) return self.taintUp(jobs) count+=1 if count == 3:break return [] print "Fatal Error! the malformed call detail lines after return value assignment!" print 1/0
def indent(indentLevel): if not isinstance(indentLevel, int) or indentLevel < 1: raise Exception("Indent level must be a positive integer.") syntax = Syntax() return syntax.indent * indentLevel
def getDefs(self,pairs,indexes,uppdefindex=-1): if indexes==[]:#BUG:please check this situation return [] if uppdefindex==-1: uppdefindex=indexes[0]-1 defs=[] for index,v,left_propa,up,low in pairs[::-1]: if isinstance(self.l[index],LineOfCode) and index<=uppdefindex:continue #note that the index of downward tainting param pointer should be set to the first code line #Or it will be aborted as it matched the "=". if indexes[low-1]<=uppdefindex:continue for i in indexes[up:low][::-1]: print "getDefs():Checking Def:",self.l[i] access=v.accessStr() if re.search(access, self.l[i].codestr): maybe_def=True else: maybe_def=False pointerstr=v.pointerStr() if pointerstr is not None: if re.search(pointerstr, self.l[i].codestr): maybe_def=True if maybe_def: def_type=self.matchDefinitionType(i,v) #if def_type==Syntax.FOR or def_type==Syntax.NORMAL_ASSIGN or def_type==Syntax.OP_ASSIGN or def_type==Syntax.INC or def_type==Syntax.RAW_DEF or def_type==Syntax.SYS_LIB_DEF:#ASSIGN if def_type!=Syntax.NODEF: defs.append((i,v)) print "Find the 100% definition." break elif self.likeArgDef(v,self.l[i].codestr): print "Check Possible Definitions:",self.l[i] if isinstance(self.l[i+1],FunctionCallInfo): if Syntax.isPossibleArgumentDefinition(self.l[i],v): defs.append((i,v)) print "Yes,it is Possible Definitions." print "But just possible,maybe 10%. We should continue search at least another 100% definition for assurance." elif self.likeArgDef(v,self.l[i].codestr): print "Check Possible Definitions:",self.l[i] if isinstance(self.l[i+1],FunctionCallInfo): if Syntax.isPossibleArgumentDefinition(self.l[i],v): defs.append((i,v)) print "Yes,it is Possible Definitions." print "But just possible,maybe 10%. We should continue search at least another 100% definition for assurance." defs.sort(key=lambda x:x[0],reverse=True)#index reversed order return defs
def macro_call_right_str(self,upperIndex): filename=self.l[upperIndex].get_func_call_info().get_file_name() linenum=self.l[upperIndex].get_linenum() print filename,linenum expanded_str=self.macro_inspector.getExpanded(filename,linenum) print "expanded str:",expanded_str if "temp = (((abfd)->xvec->_bfd_check_format[(int) ((abfd)->format)]) (abfd));" in expanded_str: print "Find It!" call_patttern=Syntax.lt+Syntax.identifier+Syntax.water+r"[\)\]]*"+Syntax.water+r"\(" for m in re.finditer(call_patttern,expanded_str): print "matched candidate function name:",m.group(1) if not Syntax.isKeyWord(m.group(1)) and not Syntax.isLibFuncName(m.group(1)): span=m.span() #FIX ME this is wrong when handling cases like: MAZE(a,b)-->'call1(a)+call2(b)". #Then when handling the second call site, it returns 'a' as the detected argument. return expanded_str[span[1]:] print "Fatal Error treat 'sizeof' as a function call or other ERROR!! Please check the macro_call_right_str()" x=1/0
def __parseNameRequirementsPredicates(self, planningDomainFile): #~ Predicates are defined in the usual PDDL way: #~ (:predicates #~ (C ?x) #~ (P ?x ?y) #~ ... #~ ) syntax = Syntax() #~ A concept is composed by a name and only one variable, e.g. C ?x #~ We remove the variable and replace it with the keyword "Concept" pddlConcept = Group(syntax.allowed_word.setResultsName("predicateName") + syntax.variable.setParseAction(replaceWith("Concept")).setResultsName("predicateType")) #~ A role is composed by a name and exactly two variables, e.g. P ?x ?y #~ We remove the first variable and replace it with the keyword "Role" #~ while we remove completely the second pddlRole = Group(syntax.allowed_word.setResultsName("predicateName") + \ syntax.variable.setParseAction(replaceWith('Role')).setResultsName("predicateType") + \ syntax.variable.setParseAction().suppress() ) #~ We put pddlVariable.setParseAction() in order to remove the effect of the previous pddlVariable.setParseAction(replaceWith('Role')) #~ If we fail to do so, then all the times we use self.variable, it will be substituted by the word "Role" #~ A PDDL Predicate is either concepts or roles pddlPredicate = pddlConcept ^ pddlRole pddlPredicates = syntax.leftPar + syntax.pddlPredicatesTag.suppress() + Group(OneOrMore(syntax.leftPar + pddlPredicate + syntax.rightPar)).setResultsName("predicates") + syntax.rightPar pddlDomain = StringStart() + \ syntax.leftPar + syntax.pddlDefineTag + \ syntax.leftPar + syntax.pddlDomainTag + \ syntax.pddlDomainName.setResultsName("domainName") + \ syntax.rightPar + \ syntax.pddlRequirements.suppress() + \ pddlPredicates + \ Regex("(.*\r*\n*)*\)\r*\n*").suppress() #~ Parse the file result = pddlDomain.parseFile(planningDomainFile) self.__domainName = result["domainName"] #Save the domain name #~ Save the concepts and roles for predicate in result["predicates"]: #~ If a predicate has the same name as a keyword (e.g., "exists", "not", etc.), raise an Exception if str(predicate["predicateName"]) in syntax.keywords: raise Exception("It is not possible to use the word \"" + str(predicate["predicateName"]) + "\" as a name for a predicate, as it is a keyword.") if predicate["predicateType"][0] == "Concept": self.__concepts.add(str(predicate["predicateName"])) self.__conceptsParse = self.__conceptsParse ^ Literal(str(predicate["predicateName"])) else: self.__roles.add(str(predicate["predicateName"])) self.__rolesParse = self.__rolesParse ^ Literal(str(predicate["predicateName"]))
def __parseAssertion(self, assertionToParse, conceptList, roleList, individualList): syntax = Syntax() #~ If assertionToParse is a string, we parse it by considering the parenthesis that close every expression #~ and analyse the resulting pyparsing.ParseResults. #~ If axiomToParse is already a pyparsing.ParseResults (or a list, or a tuple), then we analise it directly. if isinstance(assertionToParse, str): raise Exception("Sorry, at the moment we can't parse assertions that are passed as a string.\n" + assertionToParse) #~ If assertionToParse is either a ParseResults, tuple, or list, then it must have #~ 2 or 3 elements, and all of them must be strings. #~ Also, if it has 2 elements, then the first element must be in conceptList (if specified), #~ while if it has 3 elements, it must be in roleList (if specified) if len(assertionToParse) < 2 or len(assertionToParse) > 3: raise Exception("An assertion must be formed of 2 elements (in case of an assertion involving a concept), or 3 (in case of a role).\n" + \ "The following assertion has instead " + str(len(assertionToParse)) + " elements:\n" + \ str(assertionToParse)) if not all(isinstance(element, str) for element in assertionToParse): raise Exception("The element composing an assertion to parse must be all strings.\n" + str(assertionToParse)) if len(assertionToParse) == 2: if not self.__checkConcept(assertionToParse[0], conceptList): raise Exception("The term used in the assertion is not a valid concept.\n" + str(assertionToParse)) if not self.__checkIndividual(assertionToParse[1], individualList): raise Exception("The individual used in the assertionis not a individual.\n" + str(assertionToParse)) #~ Save the elements self.__term = assertionToParse[0] self.__individual1 = assertionToParse[1] elif len(assertionToParse) == 3: if not self.__checkRole(assertionToParse[0], roleList): raise Exception("The term used in the assertion is not a valid concept.\n" + str(assertionToParse)) if not self.__checkIndividual(assertionToParse[1], individualList): raise Exception("The individual used in the assertionis not a individual.\n" + str(assertionToParse)) if not self.__checkIndividual(assertionToParse[2], individualList): raise Exception("The individual used in the assertionis not a individual.\n" + str(assertionToParse)) #~ Save the elements self.__term = assertionToParse[0] self.__individual1 = assertionToParse[1] self.__individual2 = assertionToParse[2] else: #~ Something is wrong. raise Exception("Something went wrong with the analisys of the following assertion.\n" + str(assertionToParse))
def __checkConcept(self, term, conceptList): #~ Checks if term is a valid concept. #~ term must not be a reserved keyword, #~ and must be in conceptList #~ Returns True if it is valid, False otherwise if not isinstance(term, str): raise Exception("The term passed to the function __checkConcept must be a string: " + str(type(term))) syntax = Syntax() #~ The term can't be a reserved keyword if term in syntax.keywords: return False if not term in conceptList: return False return True
def __parseProblem(self, planningProblemFile): #~ The parsing is divided in parts: #~ - retrieve the domain name and check that the requirements and the predicates are ok. If not, raise an exception. #~ From the predicates we create the list of concepts and roles; #~ - read the file again to retrieve the axioms, the condition-action rules, and the actions. syntax = Syntax() #~ The domain specified in the problem must be the same name specified in the domain parsed before. #~ For this reason we put Literal(self.__domainName) pddlProblem = StringStart() + \ syntax.leftPar + syntax.pddlDefineTag + \ syntax.leftPar + syntax.pddlProblemTag + syntax.pddlProblemName.setResultsName("problemName") + syntax.rightPar + \ syntax.leftPar + syntax.pddlProblemDomainTag + Literal(self.__domainName) + syntax.rightPar + \ syntax.leftPar + syntax.pddlProblemObjectsTag + Group(OneOrMore(syntax.pddlProblemObject)).setResultsName("problemObjects") + syntax.rightPar + \ syntax.leftPar + syntax.pddlProblemInitTag + Group(OneOrMore(nestedExpr())).setResultsName("problemAssertions") + syntax.rightPar + \ syntax.leftPar + syntax.pddlProblemGoalTag + nestedExpr().setResultsName("problemGoal") + syntax.rightPar + \ syntax.rightPar + \ StringEnd() #~ Parse the file result = pddlProblem.parseFile(planningProblemFile) self.__problemName = result["problemName"] #Save the problem name #~ Save the individuals. #~ In PDDL they are reffered to as objects. for obj in result["problemObjects"]: self.__individuals.add(obj) #~ Save the assertions. for assertion in result["problemAssertions"]: self.__assertions.add(Assertion(assertion, self.__concepts, self.__roles, self.__individuals)) #~ Save the goal query. self.__goalQuery = ECQ(result["problemGoal"][0], self.__concepts, self.__roles, self.__individuals) #~ Check that the goal query is boolean if len(self.__goalQuery.freeVars()) > 0: raise Exception("The goal query must be boolean.")
def matchDefinitionType(self,i,var): codestr=self.l[i].codestr if var.v=='i': print "GotIt!!" access=var.accessStr() print "Checking Definition Type for:",access print "codestr:",codestr if Syntax.isForStatement(codestr,access): return Syntax.FOR if Syntax.isIncDef(var.v, codestr): return Syntax.INC #inc operation detection must be before the assignment. #because when detecting variable (i) in case such as: "for (int i=-1;i<m;i++){", #INC result must be returned as ForJobGenerator is only called in handle branch of INC operation #in "lastModification" and "CheckingArgDefinition" function. #This weird behavior need be fixed in future. normal_assginment=Syntax.normal_assignment_pattern(access) match=re.search(normal_assginment,codestr) if match: rightstr=codestr[match.span()[1]:].rstrip(';') if Syntax.isUniqueNonLibCall(rightstr): if i+2+1<len(self.l) and isinstance(self.l[i+1],FunctionCallInfo) and isinstance(self.l[i+2],LineOfCode): if self.l[i+1].get_func_name().split("::")[-1].strip() in self.l[i].codestr: return Syntax.RETURN_VALUE_ASSIGN elif self.isMacroCall(i): return Syntax.RETURN_VALUE_ASSIGN return Syntax.NORMAL_ASSIGN op_assignment=Syntax.op_assignment_pattern(access) if re.search(op_assignment,codestr): return Syntax.OP_ASSIGN raw_definition=r"^\s*\{\s*[A-Za-z_][A-Za-z0-9_]+\s+(\*\s*)*([A-Za-z_][A-Za-z0-9_]+\s*,\s*)*"+var.v+"\s*;" if re.search(raw_definition, codestr): print "We got the raw definition!",codestr return Syntax.RAW_DEF if Syntax.isLibArgDef(var,codestr): return Syntax.SYS_LIB_DEF return Syntax.NODEF
def __parseAxiom(self, axiomToParse, conceptList, roleList): #~ (isA above :topC ) #~ (isA above (not (exists (inverse next )) ) ) #~ (isA (exists next ) (not (exists reachable-floor) ) ) #~ (isA next (not reachable-floor)) #~ (funct (inverse next )) syntax = Syntax() #~ If axiomToParse is a string, we parse it by considering the parenthesis that close every expression #~ and analyse the resulting pyparsing.ParseResults. #~ If axiomToParse is already a pyparsing.ParseResults (or a list, or a tuple), then we analise it directly. result = None if isinstance(axiomToParse, str): raise Exception("Sorry, at the moment we can't parse axioms that are passed as a string.\n" + axiomToParse) elif isinstance(axiomToParse, (ParseResults, tuple, list)): result = axiomToParse if isinstance(result[0], str) and result[0] == syntax.isA: #~ We have either a positive or negative axiom, for sure not a functional one #~ Parse the first term if isinstance(result[1], str): #~ The first term is either an atomic concept A or atomic role P if not (self.__checkConcept(result[1], conceptList) or self.__checkRole(result[1], roleList)): raise Exception("The term \"" + result[1] + "\" is not valid, it can't be used to build the following axiom:\n" + str(result)) self.__leftTerm = result[1] elif isinstance(result[1], (ParseResults, tuple, list)): if isinstance(result[1][0], str) and result[1][0] == syntax.exists: if isinstance(result[1][1], str): #~ It's the term: exists P if not self.__checkRole(result[1][1], roleList): #~ The term is in neither lists raise Exception("The term \"" + result[1][1] + "\" used for the following axiom is not a valid role.\n" + str(result)) self.__leftTerm = result[1][1] self.__leftTermExists = True elif isinstance(result[1][1], (ParseResults, tuple, list)) and \ isinstance(result[1][1][0], str) and result[1][1][0] == syntax.inverse and \ isinstance(result[1][1][1], str): #~ It's the term: exists P^- if not self.__checkRole(result[1][1][1], roleList): #~ The term is in neither lists raise Exception("The term \"" + result[1][1][1] + "\" used for the following axiom is not a valid role.\n" + str(result)) self.__leftTerm = result[1][1][1] self.__leftTermExists = True self.__leftTermInverse = True else: #~ Something is wrong. raise Exception("The left term of the following axiom was not recognized as a valid one.\n" + str(result)) elif isinstance(result[1][0], str) and result[1][0] == syntax.inverse and \ isinstance(result[1][1], str): #~ It's the term: P^- if not self.__checkRole(result[1][1], roleList): #~ The term is in neither lists raise Exception("The term \"" + result[1][1] + "\" used for the following axiom is not a valid role.\n" + str(result)) self.__leftTerm = result[1][1] self.__leftTermInverse = True else: #~ Something is wrong. raise Exception("The left term of the following axiom was not recognized as a valid one.\n" + str(result)) else: #~ Something is wrong. raise Exception("The left term of the following axiom was not recognized as a valid one.\n" + str(result)) #~ Parse the second term if isinstance(result[2], str): #~ The second term is either an atomic concept A or atomic role P if not (self.__checkConcept(result[2], conceptList) or self.__checkRole(result[2], roleList)): raise Exception("The term \"" + result[2] + "\" is not valid, it can't be used to build the following axiom:\n" + str(result)) if self.__checkConcept(self.__leftTerm, conceptList) and self.__checkRole(result[2], roleList): raise Exception("The term \"" + result[2] + "\" is a role, while \"" + self.__leftTerm + "\" is a concept.\nIt can't be used to build the following axiom:\n" + str(result)) if not self.__leftTermExists and \ self.__checkRole(self.__leftTerm, roleList) and \ not self.__checkRole(result[2], roleList): raise Exception("The term \"" + result[2] + "\" is not a role, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2] elif isinstance(result[2], (ParseResults, tuple, list)): if isinstance(result[2][0], str) and result[2][0] == syntax.exists: if isinstance(result[2][1], str): #~ It's the term: exists P if not self.__checkRole(result[2][1], roleList): raise Exception("The term \"" + result[2][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2][1] self.__rightTermExists = True elif isinstance(result[2][1], (ParseResults, tuple, list)) and \ isinstance(result[2][1][0], str) and result[2][1][0] == syntax.inverse and \ isinstance(result[2][1][1], str): #~ It's the term: exists P^- if not self.__checkRole(result[2][1][1], roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2][1][1] self.__rightTermExists = True self.__rightTermInverse = True else: #~ Something is wrong. raise Exception("The right term of the following axiom was not recognized as a valid one.\n" + str(result)) elif isinstance(result[2][0], str) and result[2][0] == syntax.inverse and \ isinstance(result[2][1], str): #~ It's the term: P^- if not self.__checkRole(result[2][1], roleList): raise Exception("The term \"" + result[2][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTermTerm = result[2][1] self.__rightTermInverse = True elif isinstance(result[2][0], str) and result[2][0] == syntax.neg: #~ The axiom is a disjunction self.__disjoint = True if isinstance(result[2][1], str): #~ The second term is either an atomic concept A or atomic role P if not (self.__checkConcept(result[2][1], conceptList) or self.__checkRole(result[2][1], roleList)): raise Exception("The term \"" + result[2][1] + "\" is not valid, it can't be used to build the following axiom:\n" + str(result)) if (self.__checkConcept(self.__leftTerm, conceptList) or \ (self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList))) and \ not self.__checkConcept(result[2][1], conceptList): raise Exception("The term \"" + result[2][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) if self.__checkRole(self.__leftTerm, roleList) and not self.__checkRole(result[2][1], roleList): raise Exception("The term \"" + result[2][1] + "\" is not a role, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2][1] elif isinstance(result[2][1], (ParseResults, tuple, list)): if isinstance(result[2][1][0], str) and result[2][1][0] == syntax.exists: if isinstance(result[2][1][1], str): #~ It's the term: exists P if not self.__checkRole(result[2][1][1], roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2][1][1] self.__rightTermExists = True elif isinstance(result[2][1][1], (ParseResults, tuple, list)) and \ isinstance(result[2][1][1][0], str) and result[2][1][1][0] == syntax.inverse and \ isinstance(result[2][1][1][1], str): #~ It's the term: exists P^- if not self.__checkRole(result[2][1][1][1], roleList): raise Exception("The term \"" + result[2][1][1][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1][1][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTerm = result[2][1][1][1] self.__rightTermExists = True self.__rightTermInverse = True else: #~ Something is wrong. raise Exception("The right term of the following axiom was not recognized as a valid one.\n" + str(result)) elif isinstance(result[2][1][0], str) and result[2][1][0] == syntax.inverse and \ isinstance(result[2][1][1], str): #~ It's the term: P^- if not self.__checkRole(result[2][1][1], roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) #~ If the first term is either P or P^-, then we raise an Exception if not self.__leftTermExists and self.__checkRole(self.__leftTerm, roleList): raise Exception("The term \"" + result[2][1][1] + "\" is not a concept, while \"" + self.__leftTerm + "\" is.\nIt can't be used to build the following axiom:\n" + str(result)) self.__rightTermTerm = result[2][1][1] self.__rightTermInverse = True else: #~ Something is wrong. raise Exception("The right term of the following axiom was not recognized as a valid one.\n" + str(result)) else: #~ Something is wrong. raise Exception("The right term of the following axiom was not recognized as a valid one.\n" + str(result)) else: #~ Something is wrong. raise Exception("The right term of the following axiom was not recognized as a valid one.\n" + str(result)) elif isinstance(result[0], str) and result[0] == syntax.funct: #~ It's a functionality axiom self.__functionality = True #~ Parse the first term if isinstance(result[1], str): #~ The first term is an atomic role P if not self.__checkRole(result[1], roleList): raise Exception("The term \"" + result[1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) self.__leftTerm = result[1] elif isinstance(result[1], (ParseResults, tuple, list)) and \ isinstance(result[1][0], str) and result[1][0] == syntax.inverse and \ isinstance(result[1][1], str): #~ The first term is: P^- if not self.__checkRole(result[1][1], roleList): raise Exception("The term \"" + result[1][1] + "\" is not a valid role, it can't be used to build the following axiom:\n" + str(result)) self.__leftTerm = result[1][1] self.__leftTermInverse = True else: #~ Something is wrong. raise Exception("The following functionality axiom was not recognized as a valid one.\n" + str(result)) else: #~ Something is wrong. raise Exception("The axiom was not recognized as a valid one.\n" + str(result))
def __parseQuery(self, queryToParse, conceptList, roleList, individualList): syntax = Syntax() #~ If queryToParse is a string, we parse it by considering the parenthesis that close every expression #~ and analyse the resulting pyparsing.ParseResults. #~ If queryToParse is already a pyparsing.ParseResults, then we analise it directly. result = None if isinstance(queryToParse, str): parser = StringStart() + nestedExpr() + StringEnd() result = parser.parseString(queryToParse) #~ We consider only the first element of result, since, if it is a valid list, #~ then result is a nested list, and thus result[0] is the actual list we #~ are interested in. result = result[0] elif isinstance(queryToParse, (ParseResults, tuple, list)): result = queryToParse #~ The expressions used to build an ECQ can be: #~ - "(not ECQ)" #~ - "(exists (vars) ECQ)" #~ - "(and ECQ list)" #~ - "(mko-eq var1 var2)" #~ - "(mko UCQ)" #~ - ":True" #~ We check the first element (result[0]), #~ which has to be a special word identifying which type of expression is used if result[0] == syntax.true: #~ The expression must be "(:True)", thus result must contain exactly 1 element if len(result) != 1: raise Exception("The expression \"(" + syntax.true + ")\" must contain only the keyword " + syntax.true + ".") #~ Set the current ECQ as True self.__trueQuery = True elif result[0] == syntax.neg: #~ The expression must be "(not ECQ)", thus result must contain exactly 2 elements if len(result) != 2: raise Exception( "The expression \"(not ECQ )\" must contain only one ECQ.") self.__ecqs.add( ECQ(result[1], conceptList, roleList, individualList)) #~ Set the current ECQ as negated self.__negated = True elif result[0] == syntax.exists: #~ The element result[1] must contain the existential variables, #~ while result[2] the inner ECQ. #~ result must contain exactly 3 elements if len(result) != 3: raise Exception( "The expression \"(exists (Vars) (ECQ) )\" must contain only a set of existential variables and one ECQ." ) self.__ecqs.add( ECQ(result[2], conceptList, roleList, individualList)) # Add the ECQ #~ Check that variables are syntactically valid (i.e. "?"+ a valid string) #~ and add them to self.__existentialVars varName = (StringStart() + syntax.variable.setResultsName("varName") + StringEnd()).leaveWhitespace() for varString in result[1]: var = Variable(varName.parseString(varString)[0]) #~ Check that var is a free variable in the inner ECQ, otherwise raise an Exception for ecq in self.__ecqs: if not (var in ecq.freeVars()): raise Exception("The variable " + str(var) + " does not appear in the inner ECQ.") self.__existentialVars.add(var) elif result[0] == syntax.queryAnd: #~ The list must contain "and" plus at least two inner ECQs, #~ starting from element result[1]. if len(result) <= 2: raise Exception( "The expression \"(and ... )\" must contain at least 2 internal ECQs." ) for counter in range(1, len(result)): self.__ecqs.add( ECQ(result[counter], conceptList, roleList, individualList)) #~ Check that all the inner ECQs have the same free variables #~ for check in combinations(self.__ecqs, 2): #~ print(check) #~ if check[0].freeVars() != check[1].freeVars(): #~ raise Exception("The ECQs have different free variables in them!\n"+str(check[0])+"\n"+str(check[1])) elif result[0] == syntax.mkoEq: #~ This represent an equality assertion. It must contain exactly 2 variable #~ (thus, considering 'mko-eq', the lenght can't be more than 3). if len(result) != 3: raise Exception( "An equality assertion must contain exactly 2 variables. " + str(len(result[1:])) + " provided instead: " + str(result[1:])) #~ Check that variables are syntactically valid (i.e. "?"+ a valid string) #~ and add them to self.__existentialVars varName = (StringStart() + syntax.variable.setResultsName("varName") + StringEnd()).leaveWhitespace() self.__equalityVar1 = Variable(varName.parseString(result[1])[0]) self.__equalityVar2 = Variable(varName.parseString(result[2])[0]) #~ The variables have to be different from each other, we don't #~ accept an equality of the type (= ?x ?x). #~ If this is the case, we raise an Exception. if self.__equalityVar1 == self.__equalityVar2: raise Exception("The variables provided in the equality statement are the same. Please adjust/remove the atom: (= ?" + \ str(result[1]) + " ?" + str(result[2]) + ")") elif result[0] == syntax.mko: #~ This represent an UCQ inside a minimal knowledge operator. #~ An UCQ must be contained between parenthesis ( ), like: #~ (mko (...)) #~ even if the UCQ is a single atom, so result is like: #~ ['mko', [...]] #~ thus result can't contain more than two elements. if len(result) > 2: raise Exception( "A minimal knowledge operator axiom should contain only an UCQ between parenthesys \"()\"." ) self.__ucq = UCQ(result[1], conceptList, roleList, individualList) else: raise Exception("No valid word found: " + str(result[0])) #~ Find the freeVars of the current ECQ. #~ To do so, we collect all the free vars appearing in the inner ECQs, #~ or in the UCQ, and remove the one that are set as existential #~ in the current ECQ. #~ If the current ECQ is an equality, we consider the variables involved #~ as free variables. for ecq in self.__ecqs: self.__freeVars.update(ecq.freeVars()) if not self.__ucq is None: self.__freeVars.update(self.__ucq.freeVars()) if isinstance(self.__equalityVar1, Variable): self.__freeVars.add(self.__equalityVar1) if isinstance(self.__equalityVar2, Variable): self.__freeVars.add(self.__equalityVar2) self.__freeVars = self.__freeVars.difference(self.__existentialVars)
def __parseAxiomsRulesActions(self, planningDomainFile): #~ The functions parse the following elements: #~ - axioms #~ - condition-action rules #~ - actions #~ The possible axioms, as defined in DL-Lite, are (here written in PDDL-EKab syntax): #~ (isA pddlBasicRole pddlGeneralRole) #~ (isA pddlBasicConcept pddlGeneralConcept) #~ (funct pddlBasicRole) #~ The possible terms participating in axioms are, instead: #~ pddlAtomicRole := nome del ruolo definito in predicates #~ pddlBasicRole := pddlAtomicRole | (inverse pddlAtomicRole) #~ pddlGeneralRole := pddlBasicRole | (not pddlBasicRole) #~ pddlAtomicRole := nome del concetto definito in predicates #~ pddlBasicConcept := pddlAtomicRole | (exists pddlBasicRole) #~ pddlGeneralConcept := pddlBasicConcept | (not pddlBasicConcept) | (existsQualified pddlBasicRole pddlBasicConcept) | topC #~ #~ The parser divides immediately the axioms in: positive axioms, negative axioms, and functionality axioms syntax = Syntax() pddlAtomicRole = self.__rolesParse pddlAtomicConcept = self.__conceptsParse pddlBasicRole = pddlAtomicRole ^ Group((syntax.leftPar + Literal(syntax.inverse) + pddlAtomicRole + syntax.rightPar)) pddlBasicConcept = pddlAtomicConcept ^ Group((syntax.leftPar + Literal(syntax.exists) + pddlBasicRole + syntax.rightPar)) pddlGeneralConcept = syntax.topC ^ \ Group((syntax.leftPar + Literal(syntax.existsQualified) + pddlBasicConcept + pddlBasicRole + syntax.rightPar)) ^ \ pddlBasicConcept #~ pddlGeneralRole = Group((self.leftPar + "not" + pddlBasicRole + self.rightPar)) ^ \ #~ pddlBasicRole pddlAxiomPos = Group(\ Empty().setParseAction(replaceWith("AxiomPos")) + \ Group(((syntax.isA + pddlBasicConcept + pddlGeneralConcept) ^ (syntax.isA + pddlBasicRole + pddlBasicRole))) \ ) pddlAxiomNeg = Group( \ Empty().setParseAction(replaceWith("AxiomNeg")) + \ Group(((syntax.isA + pddlBasicConcept + syntax.leftPar + Literal(syntax.neg).suppress() + pddlBasicConcept + syntax.rightPar) ^ \ (syntax.isA + pddlBasicRole + syntax.leftPar + Literal(syntax.neg).suppress() + pddlBasicRole + syntax.rightPar)) \ )) pddlAxiomFunct = Group(Empty().setParseAction(replaceWith("AxiomFunct")) + Literal(syntax.funct).suppress() + pddlBasicRole) #~ pddlAxioms = syntax.leftPar + syntax.pddlAxiomsTag + \ #~ Group(OneOrMore(syntax.leftPar + (pddlAxiomPos ^ pddlAxiomNeg ^ pddlAxiomFunct) + syntax.rightPar)).setResultsName("axioms") + syntax.rightPar pddlAxioms = syntax.leftPar + syntax.pddlAxiomsTag + \ Group(OneOrMore(nestedExpr())).setResultsName("axioms") + syntax.rightPar #~ A condition-action rule has the form of: #~ ECQ -> action name #~ This, in the PDDL-EKab sytax is expressed as: #~ (:rule rule-name #~ :condition ECQ #~ :action action-name #~ ) pddlRuleName = syntax.allowed_word.setResultsName("ruleName") # Rule name pddlRuleCondition = syntax.pddlRuleConditionTag + nestedExpr().setResultsName("ruleCondition") pddlRuleAction = syntax.pddlRuleActionTag + syntax.allowed_word.setResultsName("ruleAction") pddlRule = Group(syntax.leftPar + syntax.pddlRuleTag + pddlRuleName + pddlRuleCondition + pddlRuleAction + syntax.rightPar) pddlRules = Group(ZeroOrMore(pddlRule)).setResultsName("rules") #~ An action has the form of: #~ name (input parameters): { list of effects } #~ Each effect has the form: #~ ECQ ~> add F+, del F- #~ where F+ and F- are a set of atomic effects. #~ This, in the PDDL-EKab sytax is expressed as: #~ (:action action-name #~ :parameters ( list of variables ) #~ :effects ( #~ :condition ECQ #~ :add (atoms list) #~ :remove (atoms list) #~ ) #~ ... #~ ( #~ :condition ECQ #~ :add (atoms list) #~ :delete (atoms list) #~ ) #~ ) pddlActionName = syntax.allowed_word.setResultsName("actionName") pddlActionParameters = Literal(":parameters").suppress() + syntax.leftPar + Group(ZeroOrMore(syntax.variable)).setResultsName("actionParameters") + syntax.rightPar pddlActionEffectCondition = syntax.pddlActionEffectConditionTag + nestedExpr().setResultsName("effectCondition") pddlActionEffectAdd = syntax.pddlActionEffectAddTag + nestedExpr().setResultsName("effectAdd") pddlActionEffectDel = syntax.pddlActionEffectDelTag + nestedExpr().setResultsName("effectDelete") pddlActionEffect = Group(syntax.leftPar + pddlActionEffectCondition + pddlActionEffectAdd + syntax.rightPar) ^ \ Group(syntax.leftPar + pddlActionEffectCondition + pddlActionEffectDel + syntax.rightPar) ^ \ Group(syntax.leftPar + pddlActionEffectCondition + pddlActionEffectAdd + pddlActionEffectDel + syntax.rightPar) pddlActionEffects = syntax.pddlActionEffectsTag + Group(OneOrMore(pddlActionEffect)).setResultsName("actionEffects") pddlAction = Group(syntax.leftPar + syntax.pddlActionTag + pddlActionName + pddlActionParameters + pddlActionEffects + syntax.rightPar) pddlActions = Group(ZeroOrMore(pddlAction)).setResultsName("actions") #~ The section (:predicates ...) is matched by the Regex expression: #~ Regex("\(\s*\:predicates\s*\r*\n*(\s*\(.*\)\s*\r*\n*)*\s*\)").suppress() pddlDomain = StringStart() + \ syntax.leftPar + syntax.pddlDefineTag + \ syntax.leftPar + syntax.pddlDomainTag + \ Literal(self.__domainName).suppress() + syntax.rightPar + \ syntax.pddlRequirements.suppress() + \ Regex("\(\s*\:predicates\s*\r*\n*(\s*\(.*\)\s*\r*\n*)*\s*\)").suppress() + \ pddlAxioms + \ pddlRules + \ pddlActions + \ syntax.rightPar + \ StringEnd() #~ Parse the file try: result = pddlDomain.parseFile(planningDomainFile) except ParseException as x: print ("Line {e.lineno}, column {e.col}:\n'{e.line}'".format(e=x)) raise #~ #~ Analyse the axioms #~ for axiomParse in result["axioms"]: axiom = Axiom(axiomParse, self.__concepts, self.__roles) if axiom.disjoint(): self.__axiomsNeg.add(axiom) elif axiom.functionality(): self.__axiomsFunct.add(axiom) else: self.__axiomsPos.add(axiom) #~ #~ Analyse the rules #~ for rule in result["rules"]: #~ Check that no other action has the same name for otherRule in result["rules"]: if rule != otherRule and str(rule["ruleName"]) == str(otherRule["ruleName"]): raise Exception("There are two rule with the same name: " + str(rule["ruleName"])) #~ Create the ECQ ruleCond = ECQ(rule["ruleCondition"][0], self.__concepts, self.__roles, self.__individuals) #~ We need to check that the terms used in the rules are present in the #~ TBox vocabulary (thus, in the predicate section) if not ruleCond.concepts().issubset(self.__concepts): raise Exception("The following rule is using terms that are not concepts in the predicates: (:" + str(rule["ruleName"]) + " ... )\n" \ "Terms that are not concepts: " + str(ruleCond.concepts().difference(self.__concepts))) if not ruleCond.roles().issubset(self.__roles): raise Exception("The following rule is using terms that are not roles in the predicates: (:" + str(rule["ruleName"]) + " ... )\n" \ "Terms that are not roles: " + str(ruleCond.roles().difference(self.__roles))) #~ Check that the action called exists found = False for action in result["actions"]: if str(rule["ruleAction"]) == str(action["actionName"]): found = True if not found: raise Exception("The rule (:" + str(rule["ruleName"]) + " ... ) is calling an action ("+ str(rule["ruleAction"]) + " ... ) that is not specified after.") #~ Save the rule self.__rules.add((str(rule["ruleName"]), ruleCond, str(rule["ruleAction"]))) #~ #~ Analyse the actions #~ for action in result["actions"]: #~ Check that no other action has the same name for otherAction in result["actions"]: if action != otherAction and str(action["actionName"]) == str(otherAction["actionName"]): raise Exception("There are two actions with the same name: " + str(action["actionName"])) #~ Save the parameters in a tuple actionParameters = tuple([Variable(parameter) for parameter in action["actionParameters"]]) #~ Every action can be called only by one rule, and #~ the free variables of the rule condition must be a subset of #~ the parameters of the action. counter = 0 for rule in self.__rules: if str(action["actionName"]) == rule[2]: #~ Increase the counter counter += 1 #~ Check the free variables if not rule[1].freeVars().issubset(actionParameters): raise Exception("The rule " + rule[0] + " calls the action " + str(action["actionName"]) + \ ", but the free variables of its condition (" + str(rule[1].freeVars()) + \ ") are not a subset of the parameters of the action (" + str(actionParameters) + ").") #~ Check that only one rule calls the action if counter != 1: raise Exception("There are " + str(counter) + " rules that call the action " + str(action["actionName"]) +". There must be 1!") #~ Analyze each effect effects = [] # Temporary list for the effects for effect in action["actionEffects"]: #~ Create the ECQ of the effect effectCond = ECQ(effect["effectCondition"][0], self.__concepts, self.__roles, self.__individuals) #~ We need to check that the terms used in the effect condition are present in the #~ TBox vocabulary (thus, in the predicate section) if not effectCond.concepts().issubset(self.__concepts): raise Exception("The following action is using terms that are not concepts in the predicates: (:" + str(action["actionName"]) + " ... )\n" \ "Terms that are not concepts: " + str(effectCond.concepts().difference(self.__concepts))) if not effectCond.roles().issubset(self.__roles): raise Exception("The following action is using terms that are not roles in the predicates: (:" + str(action["actionName"]) + " ... )\n" \ "Terms that are not roles: " + str(effectCond.roles().difference(self.__roles))) effectConcepts = set() #Set used to save the concepts that appear in the effects, for check purposes effectRoles = set() #Set used to save the roles that appear in the effects, for check purposes effectVars = set() #Set used to save the variables that appear in the effects, for check purposes effectAdd = [] # Temporary list for the addition effects if "effectAdd" in effect.keys(): for atomicEffect in effect["effectAdd"][0]: atom = QueryAtom(atomicEffect, self.__concepts, self.__roles, self.__individuals) if atom.atomType() == "role": effectRoles.add(atom.term()) if isinstance(atom.var1(), Variable): effectVars.add(atom.var1()) if isinstance(atom.var2(), Variable): effectVars.add(atom.var2()) elif atom.atomType() == "concept": effectConcepts.add(atom.term()) if isinstance(atom.var1(), Variable): effectVars.add(atom.var1()) else: raise Exception("An atomic effect can be only about a concept or a role. The following atom is not valid: " + str(atom)) effectAdd.append(atom) # Add the effect to the list effectDel = [] # Temporary list for the deletion effects if "effectDelete" in effect.keys(): for atomicEffect in effect["effectDelete"][0]: atom = QueryAtom(atomicEffect, self.__concepts, self.__roles, self.__individuals) if atom.atomType() == "role": effectRoles.add(atom.term()) if isinstance(atom.var1(), Variable): effectVars.add(atom.var1()) if isinstance(atom.var2(), Variable): effectVars.add(atom.var2()) elif atom.atomType() == "concept": effectConcepts.add(atom.term()) if isinstance(atom.var1(), Variable): effectVars.add(atom.var1()) else: raise Exception("An atomic effect can be only about a concept or a role. The following atom is not valid: " + str(atom)) effectDel.append(atom) # Add the effect to the list #~ We need to check that the terms used in the atomic effects are present in the #~ TBox vocabulary (thus, in the predicate section) if not effectConcepts.issubset(self.__concepts): raise Exception("The following action is using terms that are not concepts in the predicates: (:" + str(action["actionName"]) + " ... )\n" \ "Terms that are not concepts: " + str(effectConcepts.difference(self.__concepts))) if not effectRoles.issubset(self.__roles): raise Exception("The following action is using terms that are not roles in the predicates: (:" + str(action["actionName"]) + " ... )\n" \ "Terms that are not roles: " + str(effectRoles.difference(self.__roles))) #~ We need to check that the variables used in the atomic effects are present either #~ in the ECQ of the effect, or in the parameters of the action. if not effectVars.issubset(effectCond.freeVars().union(actionParameters)): raise Exception("The following action is using variables in the atomic effects that do not appear among the free variables of the effect's condition: (:" + str(action["actionName"]) + " ... )\n" \ "Variables that do not appear in the condition: " + str(effectVars.difference(effectCond.freeVars()))) #~ Save the analyzed effect as a tuple effects.append(tuple((effectCond,tuple(effectAdd),tuple(effectDel)))) #~ Save the action self.__actions.add( tuple((str(action["actionName"]),actionParameters,tuple(effects))) )
def __rewriteUCQ(query, posAxioms): if not isinstance(query, UCQ): raise Exception( "The function __rewriteUCQ can work only with objects of the class UCQ(). It was instead passed a " + str(type(query))) #~ Algorithm PerfectRef(q, T) #~ Input: UCQ q, DL-LiteA TBox T #~ Output: UCQ pr #~ #~ pr := q; #~ repeat #~ pr' := pr; #~ for each CQ q' ∈ pr' do #~ for each atom g in q' do #~ for each PI α in T do #~ if α is applicable to g then #~ pr := pr ∪{q?[g/gr(g,α)] }; #~ #~ for each pair of atoms g1,g2 in q? do #~ if g1 and g2 unify then #~ pr := pr ∪ {anon(reduce(q?,g1,g2))}; #~ until pr' = pr; #~ return pr syntax = Syntax() #~ Implement the line: #~ pr := q; rewrittenUCQ = set(query.cqs()) #~ for cq in query.cqs(): #~ rewrittenUCQ.add(cq) #~ Implement the line: #~ repeat while True: #~ Implement the line: #~ pr' := pr; rewrittenUCQold = set(rewrittenUCQ) #~ for cq in rewrittenUCQ: #~ rewrittenUCQold.add(cq) #~ Implement the line: #~ for each CQ q' ∈ pr' do for cq in rewrittenUCQold: #~ Implement the line: #~ for each atom g in q' do #~ for each PI α in T do for (atom, axiom) in itertools.product(cq.queryAtoms(), posAxioms): #~ print("Checking axiom: " + str(axiom)) #~ Implement the line: #~ if α is applicable to g then #~ pr := pr ∪{q'[g/gr(g,α)] }; newAtom = __applyAxiom(atom, axiom) if not newAtom is None: #~ Calculate q'[g/gr(g,α)] newAtoms = [ ] # The atoms that compose the rewritten cq for atomTemp in cq.queryAtoms( ): # We copy all the query atoms, and just substitute the rewritten one if atomTemp == atom: # We check if it is the atom that was rewritten newAtoms.append( newAtom) # We add the rewritten atom else: newAtoms.append(atomTemp) logger.info("for axiom in posAxioms:") logger.info(str(cq)) logger.info(str(cq.queryAtoms())) logger.info(str(atom)) logger.info(str(axiom)) logger.info(str(newAtom)) logger.info(str(newAtoms)) logger.info(" ") #~ If the __applyAxiom function added a NDNSVariable() to newAtom, #~ then we have to add it to the existential variables of the rewritten CQ ndnsVar = NDNSVariable() if ndnsVar in newAtom.freeVars(): newExistentialVars = set([ndnsVar]) if len(cq.existentialVars()) > 0: newExistentialVars.update(cq.existentialVars()) rewrittenUCQ.add( CQ( { "queryAtoms": newAtoms, "existentialVars": newExistentialVars }, conceptList, roleList, individualList)) else: #~ Calculate the new existential vars set, because it could be the case that we #~ substitute a role with a concept, in which case we may reduce the number of #~ existential vars. #~ Example: #~ - we start with (exists ( ?_ ?x_1 ) (and (hasPersonalInfo ?x_1 ?_) (FullName ?x_1) ) ) #~ - we apply the axiom (isA Employee (exists hasPersonalInfo)) #~ - we substitute (hasPersonalInfo ?x_1 ?_) with (Employee ?x_1) #~ - ?_ is not an existential var anymore newExistentialVars = set() for var in cq.existentialVars(): for atom in newAtoms: if var in atom.freeVars(): newExistentialVars.add(var) rewrittenUCQ.add( CQ( { "queryAtoms": newAtoms, "existentialVars": newExistentialVars }, conceptList, roleList, individualList)) #~ Implement the line: for each pair of atoms g1,g2 in q' do for (atom1, atom2) in itertools.combinations(cq.queryAtoms(), 2): #~ Implement the line: #~ if g1 and g2 unify then #~ pr := pr ∪{anon(reduce(q',g1,g2))}; newCQ = __anon(__reduce(cq, atom1, atom2), cq.freeVars()) #~ print("Old CQ: " + str(cq)) #~ print("New CQ: " + str(newCQ)) if not newCQ is None: rewrittenUCQ.add(newCQ) logger.info("rewrittenUCQ:") logger.info(rewrittenUCQ) logger.info(" ") #~ Implement the line: #~ until pr' = pr; if rewrittenUCQold == rewrittenUCQ: break #~ We have to substitutes each instance of NDNSVariable() #~ with a proper variable Variable(). #~ NDNSVariable() instances can appear only in the CQs which #~ have existential variables. rewrittenUCQ_wo_NDNSVariables = set() for cq in rewrittenUCQ: if any([ isinstance(var, NDNSVariable) for var in cq.existentialVars() ]): cq_wo_NDNSVariables_existentialVars = set( ) # Temporary set in which the vars that substitute the NDNSVariable are saved cq_wo_NDNSVariables = set( ) # Temporary set in which we save the query atoms that contain the changed NDNSVariables counter = 0 # Used to generate uniquely named variables #~ Check if among the query atoms the NDNSVariable is used for queryAtom in cq.queryAtoms(): newVar1 = None newVar2 = None if isinstance(queryAtom.var1(), NDNSVariable): #~ We need to change it. #~ Create a uniquely named variable newVar1 = Variable(syntax.ndnsVariable + str(counter)) #~ Increase the counter counter += 1 #~ Save the new variable in the set substituteVars cq_wo_NDNSVariables_existentialVars.add(newVar1) else: newVar1 = queryAtom.var1() if isinstance(queryAtom.var2(), NDNSVariable): #~ We need to change it. #~ Create a uniquely named variable newVar2 = Variable(syntax.ndnsVariable + str(counter)) #~ Increase the counter counter += 1 #~ Save the new variable in the set substituteVars cq_wo_NDNSVariables_existentialVars.add(newVar2) else: newVar2 = queryAtom.var2() #~ Create a new queryAtom where the NDNSVariable is #~ changed with the new one, and save it in cqs_wo_NDNSVariables. if newVar2 is None: cq_wo_NDNSVariables.add( QueryAtom([queryAtom.term(), newVar1], conceptList, roleList, individualList)) else: cq_wo_NDNSVariables.add( QueryAtom([queryAtom.term(), newVar1, newVar2], conceptList, roleList, individualList)) #~ Update cq_wo_NDNSVariables_existentialVars by adding other #~ existential vars, but not NDNSVariable. for var in cq.existentialVars(): if not isinstance(var, NDNSVariable): cq_wo_NDNSVariables_existentialVars.add(var) #~ Save the cq in rewrittenUCQ_wo_NDNSVariables rewrittenUCQ_wo_NDNSVariables.add( CQ( { "queryAtoms": cq_wo_NDNSVariables, "existentialVars": cq_wo_NDNSVariables_existentialVars }, conceptList, roleList, individualList)) else: #~ The cq doesn't use any NDNSVariable. We copy it in rewrittenUCQ_wo_NDNSVariables rewrittenUCQ_wo_NDNSVariables.add(cq) #~ Implement the line: #~ return pr rewrittenUCQ = list(rewrittenUCQ_wo_NDNSVariables) if len(rewrittenUCQ) > 1: rewrittenUCQ.insert(0, syntax.queryOr) #~ print("Fine __rewriteUCQ") #~ print(str(list(rewrittenUCQ))) #~ print("---------------------------\n") return rewrittenUCQ
def toADL(self, domainOutputFilePath, problemOutputFilePath): """The function toADL translates an input eKab to a PDDL-ADL planning problem.""" #~ An ADL planning problem written in PDDL is composed by two parts, #~ the domain file and the problem file. #~ We start by creating the domain file, which contains the following sections: #~ (domain domain name) #~ (:requirements :adl) #~ (:predicates predicates list) #~ (:action action name #~ :parameters ( parameters ) #~ :precondition precondition Query #~ :effect effects #~ ) #~ ... more actions #~ #~ An ADL action is the merge of an eKab condition/action rule with #~ the related called action. #~ An ADL action is formed as follow: #~ (:action action name #~ :parameters ( parameters ) #~ :precondition precondition Query #~ :effect effects #~ ) #~ where: #~ - parameters are the parameters of the eKab action #~ - the precondition query is the rule's condition, to which we #~ add the negated boolean predicates CheckConsistency and Error #~ - the effect of the action is the conjunction of the effects of #~ the eKab action, plus the boolean predicate CheckConsistency #~ #~ The problem file contains the following sections: #~ (define (problem problem name) #~ (:domain domain name) #~ (:objects individuals list) #~ (:init membership assertions list + (not (CheckConsistency)) + (not (Error)) ) #~ (:goal #~ rewritten goal query #~ ) syntax = Syntax() indentLevel = 1 #~ Check if domainOutputFilePath is a proper file path if not isinstance(domainOutputFilePath, str): raise Exception( "The file path for the planning domain must be a string! Type provided: " + str(type(domainOutputFilePath))) if domainOutputFilePath[-5:] != ".pddl": raise Exception( "The file for the planning domain must have a .pddl extension!" ) #~ Check if domainOutputFilePath is already a file. #~ If yes, ask for permission to overwrite it. if os.path.isfile(domainOutputFilePath): while True: print("The specified file (" + domainOutputFilePath + ") already exists. Overwrite it?") answer = input("Y/n: ") if answer == "Y" or answer == "y": break elif answer == "N" or answer == "n": print("OK. The translation to ADL will halt here.") return 0 else: print( "Answer not recognized. Please type either \"Y\" or \"n\"." ) #~ Check if problemOutputFilePath is a proper file path if not isinstance(problemOutputFilePath, str): raise Exception( "The file path for the planning problem must be a string! Type provided: " + str(type(problemOutputFilePath))) if problemOutputFilePath[-5:] != ".pddl": raise Exception( "The file for the planning problem must have a .pddl extension!" ) #~ Check if problemOutputFilePath is already a file. #~ If yes, ask for permission to overwrite it. if os.path.isfile(problemOutputFilePath): while True: print("The specified file (" + problemOutputFilePath + ") already exists. Overwrite it?") answer = input("Y/n: ") if answer == "Y" or answer == "y": break elif answer == "N" or answer == "n": print("OK. The translation to ADL will halt here.") return 0 else: print( "Answer not recognized. Please type either \"Y\" or \"n\"." ) #~ Open the file for the domain domainOutputFile = open(domainOutputFilePath, "wt") #~ Write "(define" domainOutputFile.write("(define\n") #~ Write the domain name domainOutputFile.write( indent(indentLevel) + "(domain " + self.__ekab.domainName() + ")\n") #~ Write "(:requirements :adl)" domainOutputFile.write(indent(indentLevel) + "(:requirements :adl)\n") #~ Write the predicates list domainOutputFile.write(indent(indentLevel) + "(:predicates\n") indentLevel += 1 for concept in self.__ekab.concepts(): domainOutputFile.write( indent(indentLevel) + "(" + str(concept) + " ?x )\n") for role in self.__ekab.roles(): domainOutputFile.write( indent(indentLevel) + "(" + str(role) + " ?x ?y )\n") #~ Add the boolean predicates CheckConsistency and Error domainOutputFile.write( indent(indentLevel) + "(" + syntax.ADLCheckConsistency + ")\n") domainOutputFile.write( indent(indentLevel) + "(" + syntax.ADLError + ")\n") #~ Close the :predicates section indentLevel -= 1 domainOutputFile.write(indent(indentLevel) + ")\n") #~ Write the actions #~ We use the rewritten actions for action in self.__ekab.actionsRewritten(): #~ Find the related rewritten rule relatedRule = None for rule in self.__ekab.rulesRewritten(): if rule[2] == action[0]: relatedRule = rule break if relatedRule is None: #~ The action has no related rule, and this can't be raise Exception("The action " + action[0] + " has no related rule, and this can't be.") #~ Write the action name domainOutputFile.write( indent(indentLevel) + "(:action " + action[0] + "\n") indentLevel += 1 #~ Write the action's parameters. #~ parameters are the parameters of the eKab action domainOutputFile.write(indent(indentLevel) + ":parameters ( ") for param in action[1]: domainOutputFile.write(str(param) + " ") domainOutputFile.write(")\n") #~ Write the action's precondition. #~ The precondition query is the rule's condition, to which we #~ add the negated boolean predicates CheckConsistency and Error domainOutputFile.write( indent(indentLevel) + ":precondition ( and\n") domainOutputFile.write( indent(indentLevel + 1) + "(not (" + syntax.ADLCheckConsistency + "))\n") domainOutputFile.write( indent(indentLevel + 1) + "(not (" + syntax.ADLError + "))\n") domainOutputFile.write(relatedRule[1].toADL(indentLevel + 1)) domainOutputFile.write(indent(indentLevel) + ")\n") # Close the precondition #~ Write the effects of the action domainOutputFile.write(indent(indentLevel) + ":effect ( and\n") indentLevel += 1 domainOutputFile.write( indent(indentLevel) + "(" + syntax.ADLCheckConsistency + ")\n") #~ For each effect in the eKab action, we create a conditional ADL effect for effect in action[2]: domainOutputFile.write( indent(indentLevel) + "(when\n" + effect[0].toADL(indentLevel + 1)) domainOutputFile.write(indent(indentLevel + 1) + "(and\n") #~ Add the add effects for addEff in effect[1]: domainOutputFile.write(addEff.toADL(indentLevel + 2)) #~ Add the del effects for delEff in effect[2]: domainOutputFile.write( indent(indentLevel + 2) + "(not " + delEff.toADL(0)[:-1] + ")\n") #~ domainOutputFile.write(indent(indentLevel+2) + ")\n") # Close not domainOutputFile.write(indent(indentLevel + 1) + ")\n") # Close and domainOutputFile.write(indent(indentLevel) + ")\n") # Close when indentLevel -= 1 domainOutputFile.write(indent(indentLevel) + ")\n") # Close the effect indentLevel -= 1 domainOutputFile.write(indent(indentLevel) + ")\n") # Close the action #~ Add the special action to check consistency domainOutputFile.write( indent(indentLevel) + "(:action " + syntax.ADLCheckConsistencyAction + "\n") indentLevel += 1 #~ The action has no parameters, since queryUnsatRewritten is a boolean query domainOutputFile.write(indent(indentLevel) + ":parameters ( )\n") #~ Write the action's precondition. #~ The precondition query is conjunction of #~ the boolean predicate CheckConsistency and the negated Error domainOutputFile.write(indent(indentLevel) + ":precondition ( and\n") domainOutputFile.write( indent(indentLevel + 1) + "(" + syntax.ADLCheckConsistency + ")\n") domainOutputFile.write( indent(indentLevel + 1) + "(not (" + syntax.ADLError + "))\n") domainOutputFile.write(indent(indentLevel) + ")\n") # Close the precondition #~ Write the effects of the action, which are two: #~ - one has as precondition queryUnsatRewritten, and, if Ture, set Error to True #~ - the other simply set to False CheckConsistency domainOutputFile.write(indent(indentLevel) + ":effect ( and\n") indentLevel += 1 domainOutputFile.write( indent(indentLevel) + "(not (" + syntax.ADLCheckConsistency + "))\n") domainOutputFile.write( indent(indentLevel) + "(when\n" + self.__ekab.queryUnsatRewritten().toADL(indentLevel + 1)) domainOutputFile.write( indent(indentLevel + 1) + "(" + syntax.ADLError + ")\n") domainOutputFile.write(indent(indentLevel) + ")\n") # Close when indentLevel -= 1 domainOutputFile.write(indent(indentLevel) + ")\n") # Close the effect indentLevel -= 1 domainOutputFile.write(indent(indentLevel) + ")\n") # Close the action domainOutputFile.write(")") # Close define #~ Close the file domainOutputFile.close() #~ ----------------------------------------------------------- #~ Open the file for the domain problemOutputFile = open(problemOutputFilePath, "wt") #~ Write "(define (problem problem name)" problemOutputFile.write("(define (problem " + self.__ekab.problemName() + " )\n") #~ Write the domain name problemOutputFile.write( indent(indentLevel) + "(:domain " + self.__ekab.domainName() + ")\n") #~ Write the individuals list problemOutputFile.write( indent(indentLevel) + "(:objects\n" + indent(indentLevel + 1)) for individual in self.__ekab.individuals(): problemOutputFile.write(str(individual) + " ") problemOutputFile.write("\n" + indent(indentLevel) + ")\n") # Close :objects #~ Write the membership assertions list problemOutputFile.write(indent(indentLevel) + "(:init\n") for assertion in self.__ekab.assertions(): problemOutputFile.write(assertion.toADL(indentLevel + 1)) #~ Add (not (CheckConsistency)) and (not (Error)) problemOutputFile.write( indent(indentLevel + 1) + "(not (" + syntax.ADLCheckConsistency + "))\n") problemOutputFile.write( indent(indentLevel + 1) + "(not (" + syntax.ADLError + "))\n") problemOutputFile.write(indent(indentLevel) + ")\n") # Close :init #~ Write the goal problemOutputFile.write(indent(indentLevel) + "(:goal\n") problemOutputFile.write(indent(indentLevel + 1) + "(and\n") problemOutputFile.write( indent(indentLevel + 2) + "(not (" + syntax.ADLCheckConsistency + "))\n") problemOutputFile.write( indent(indentLevel + 2) + "(not (" + syntax.ADLError + "))\n") #~ Check if the goal query is a conjunction of ECQs or a CQ. #~ If this is the case, then we need to remove the additional "(and ..." in which #~ the translated query in ADL will come with, as we already have added one. #~ Failing to do so, will raise an error in FastDownward: #~ AssertionError: Condition not normalized: ... if len(self.__ekab.goalQueryRewritten().ecqs()) > 1: #~ It is a conjunction of ECQs #~ We add the single inner ECQs translated to ADL for ecq in self.__ekab.goalQueryRewritten().ecqs(): problemOutputFile.write(ecq.toADL(indentLevel + 2)) elif self.__ekab.goalQueryRewritten().ucq() is not None and \ len(self.__ekab.goalQueryRewritten().ucq().cqs()) == 1: #~ We have a single CQ for cq in self.__ekab.goalQueryRewritten().ucq().cqs(): if len(cq.existentialVars()) == 0 and len(cq.queryAtoms()) > 1: #~ It is a single CQ with no existential vars and more than one atom for atom in cq.queryAtoms(): problemOutputFile.write(atom.toADL(indentLevel + 2)) else: problemOutputFile.write(cq.toADL(indentLevel + 2)) else: problemOutputFile.write( self.__ekab.goalQueryRewritten().toADL(indentLevel + 2)) problemOutputFile.write(indent(indentLevel + 1) + ")\n") # Close and problemOutputFile.write(indent(indentLevel) + ")\n") # Close :goal problemOutputFile.write(")") # Close define #~ Close the file problemOutputFile.close()
def findAllReferences(self, var, indexrange, left_propa): visited=set() pairs=set() if indexrange==[]:return [] indexrange.sort() V=set([(indexrange[0],var,left_propa,0,len(indexrange))]) if left_propa: for temp_lb in range(0,len(indexrange)): temp_index=indexrange[temp_lb] print var.pointerStr() print temp_index,self.l[temp_index] m=re.search(r'(?<![A-Za-z0-9_])'+var.pointerStr()+r"\s*=(?!=)",self.l[temp_index].codestr) if m: result=Syntax.isPossibleArgumentDefinition(self.l[temp_index],var) leftpart=m.group()[:-1].strip() rfl,pat=var.matchAccessPattern(leftpart) if rfl>0 or result is not None: lb=temp_lb+1 else: lb=temp_lb V=set([(indexrange[0],var,left_propa,0,lb)]) break count=0 while len(V)>0: A=set() for index,v,left_p,upperbound,lowerbound in V: #if not v.pointerStr():continue #lp=Syntax.left_ref_propagate_pattern(v) rp=Syntax.right_ref_propagate_pattern(v) print "Continue Check bellow the first found assignment:",self.l[index] for idx in range(upperbound,lowerbound): aIndex=indexrange[idx] if left_p and aIndex<index: print "pass(accelerate)",v.simple_access_str() elif aIndex in visited: print "pass(accelerate)",v.simple_access_str() elif re.search(r"[^=]=[^=]",self.l[aIndex].codestr) is None: print "pass",v.simple_access_str() visited.add(aIndex) else: print "Line Under Check:",self.l[aIndex] if "&hdr;" in self.l[aIndex].codestr: print "Find IT!" match=self.isLeftPropagate(v,self.l[aIndex].codestr) if match is not None: m_left_propgate=match print "find left propagate:",self.l[aIndex] array=m_left_propgate.group().split("=") leftpart=array[0].split()[-1].lstrip("*") rightpart=array[1].strip() rightvar=rightpart.rstrip(";").strip() if rightvar[0]=="(": stack=[] i=1 while i<len(rightvar): if rightvar[i]=="(": stack.append("(") elif rightvar[i]==")": if len(stack)>0: stack.pop() else: rightvar=rightvar[i+1:].strip().lstrip("(").rstrip(")").strip() break i+=1 rfl,pat=v.matchAccessPattern(rightvar) if "*"==pat[-1] or "->" in pat[-1] and aIndex>index: if rfl<=0:rfl=1 q=TaintVar(leftpart,pat,rfl,True)#Note that we should take ref_len in to consideration. lb=lowerbound if idx+1<lowerbound: for temp_lb in range(idx+1,lowerbound): temp_index=indexrange[temp_lb] print v.pointerStr() print q.pointerStr() print temp_index,self.l[temp_index] if re.search(q.pointerStr()+r"\s*[^=]=[^=]",self.l[temp_index].codestr): result=Syntax.isPossibleArgumentDefinition(self.l[temp_index],q) if result is not None: lb=temp_lb+1 else: lb=temp_lb break pairs.add((aIndex,q,True,idx+1,lb)) A.add((aIndex,q,True,idx+1,lb)) visited.add(aIndex) elif rp: print rp m_right_propgate=re.search(rp,self.l[aIndex].codestr) if m_right_propgate: array=m_right_propgate.group().split("=") leftpart=array[0].strip() rightpart=array[1].strip() rightvar=rightpart.rstrip(";").strip() rfl,pat=v.matchAccessPattern(leftpart) # BUG if look downward if rfl==0: print "HEY" if left_p and rfl>0:#v is KILLED here! Skip the following index range, and inform other left propagation lowerbound=indexrange.index(aIndex) #Stop find other references #Because it's killed here. LOWER statements that use it is meaningless break if "*"==pat[-1] or "->" in pat[-1] and aIndex>=index: if rfl<=0:rfl=1 q=TaintVar(rightvar,pat,rfl,True)#Note that we should take ref_len in to consideration. print aIndex,self.l[aIndex] print q print v pairs.add((aIndex,q,False,upperbound,lowerbound)) A.add((aIndex,q,False,upperbound,lowerbound)) visited.add(aIndex) count+=1 V=A pairs=list(pairs) print "refrences list-------" for pair in pairs: print pair[0],pair[1],pair[2],pair[3],pair[4] pairs.sort(lambda x,y:cmp(x[0],y[0])) return pairs
def __rewriteECQ(query, posAxioms): #~ Possible ECQs: #~ - True #~ - ["not", ECQ] #~ - ["exists", [vars], ECQ] #~ - ["and", ECQ, ... , ECQ] #~ - ["mko-eq", var1, var2] #~ - ["mko", UCQ] if not isinstance(query, ECQ): raise Exception( "The function __rewriteECQ can work only with objects of the class ECQ(). It was instead passed a " + str(type(query))) syntax = Syntax() if query.isTrue(): #~ Return the keyword True return [syntax.true] elif query.isNegated(): #~ ["not", ECQ] if len(query.ecqs()) != 1: raise Exception( "Something is wrong. A negated ECQ (\"(not ECQ)\") can contain only one internal ECQ, while here there are " + len(query.ecqs()) + ".") for ecq in query.ecqs(): return [syntax.neg, __rewriteECQ(ecq, posAxioms)] elif len(query.existentialVars()) > 0: #~ ["exists", [vars], ECQ] if len(query.ecqs()) != 1: raise Exception( "Something is wrong. An existential ECQ (\"(exists (vars) ECQ)\") can contain only a list of existential variables, and one internal ECQ" ) for ecq in query.ecqs(): return [ syntax.exists, [str(var) for var in query.existentialVars()], __rewriteECQ(ecq, posAxioms) ] elif len(query.ecqs()) > 0: #~ ["and", ECQ, ... , ECQ] rewrittenEcq = [syntax.queryAnd] for ecq in query.ecqs(): rewrittenEcq.append(__rewriteECQ(ecq, posAxioms)) return rewrittenEcq elif isinstance(query.equalityVar1(), Variable) and isinstance( query.equalityVar2(), Variable): #~ ["mko-eq", var1, var2] eqEcq = [ syntax.mkoEq, str(query.equalityVar1()), str(query.equalityVar2()) ] return eqEcq elif not query.ucq() is None: #~ ["mko", UCQ] return [syntax.mko, __rewriteUCQ(query.ucq(), posAxioms)] else: #~ If I reach this point, something went wrong raise Exception( "Something went wrong in the query rewriting of the query:\n" + str(self))
def __applyAxiom(queryAtom, axiom): """ The function checks if, given a query atom and axiom, we can apply the axiom and thus genereate a new "rewritten" query atom. We follow the table reported in Fig. 12 of [Calvanese2009]. The table is: Atom g | Axiom alpha | gr(g, alpha) --------|-------------------------------|---------------- A(x) | A1 isA A | A1(x) A(x) | exists P isA A | P(x,_) A(x) | exists P^- isA A | P(_,x) P(x,_) | A isA exists P | A(x) P(x,_) | exists P1 isA exists P | P1(x,_) P(x,_) | exists P1^- isA exists P | P1(_,x) P(_,y) | A isA exists P^- | A(y) P(_,y) | exists P1 isA exists P^- | P1(y,_) P(_,y) | exists P1^- isA exists P^- | P1(_,y) P(x,y) | P1 isA P , P1^- isA P^- | P1(x,y) P(x,y) | P1 isA P^- , P1^- isA P | P1(y,x) """ syntax = Syntax() #~ Check if the axiom involves, in the right side, the term used in the atom if queryAtom.term() == axiom.rightTerm(): if not axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable): #~ We have one of the following situations: #~ A1 isA A #~ P1 isA P if queryAtom.var2() is None: #~ Return A1(x) return QueryAtom( [axiom.leftTerm(), queryAtom.var1()], conceptList, roleList, individualList) elif isinstance(queryAtom.var2(), Variable): #~ Return P1(x,y) return QueryAtom( [axiom.leftTerm(), queryAtom.var1(), queryAtom.var2()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable): #~ We have the following situations: #~ exists P isA A #~ Return P(x,_) return QueryAtom( [axiom.leftTerm(), queryAtom.var1(), NDNSVariable()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable): #~ We have the following situations: #~ exists P^- isA A #~ Return P(_,x) return QueryAtom( [axiom.leftTerm(), NDNSVariable(), queryAtom.var1()], conceptList, roleList, individualList) elif not axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ A isA exists P #~ Return A(x) return QueryAtom( [axiom.leftTerm(), queryAtom.var1()], conceptList, roleList, individualList) elif not axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ axiom.rightTermExists() and \ axiom.rightTermInverse() and \ not isinstance(queryAtom.var2(), NDNSVariable) and \ isinstance(queryAtom.var1(), NDNSVariable): #~ We have the following situations: #~ A isA exists P^- #~ Return A(y) return QueryAtom( [axiom.leftTerm(), queryAtom.var2()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ exists P1 isA exists P #~ Return P1(x,_) return QueryAtom( [axiom.leftTerm(), queryAtom.var1(), NDNSVariable()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ axiom.leftTermInverse() and \ axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ exists P1^- isA exists P #~ Return P1(_,x) return QueryAtom( [axiom.leftTerm(), NDNSVariable(), queryAtom.var1()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ axiom.rightTermExists() and \ axiom.rightTermInverse() and \ not isinstance(queryAtom.var2(), NDNSVariable) and \ isinstance(queryAtom.var1(), NDNSVariable): #~ We have the following situations: #~ exists P1 isA exists P^- #~ Return P1(y,_) return QueryAtom( [axiom.leftTerm(), queryAtom.var2(), NDNSVariable()], conceptList, roleList, individualList) elif axiom.leftTermExists() and \ axiom.leftTermInverse() and \ axiom.rightTermExists() and \ axiom.rightTermInverse() and \ not isinstance(queryAtom.var2(), NDNSVariable) and \ isinstance(queryAtom.var1(), NDNSVariable): #~ We have the following situations: #~ exists P1^- isA exists P^- #~ Return P1(_,y) return QueryAtom( [axiom.leftTerm(), NDNSVariable(), queryAtom.var2()], conceptList, roleList, individualList) elif not axiom.leftTermExists() and \ axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ not isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ P1^- isA P^- #~ Return P1(x,y) return QueryAtom( [axiom.leftTerm(), queryAtom.var1(), queryAtom.var2()], conceptList, roleList, individualList) elif not axiom.leftTermExists() and \ not axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ not isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ P1 isA P^- #~ Return P1(y,x) return QueryAtom( [axiom.leftTerm(), queryAtom.var2(), queryAtom.var1()], conceptList, roleList, individualList) elif not axiom.leftTermExists() and \ axiom.leftTermInverse() and \ not axiom.rightTermExists() and \ not axiom.rightTermInverse() and \ not isinstance(queryAtom.var1(), NDNSVariable) and \ not isinstance(queryAtom.var2(), NDNSVariable): #~ We have the following situations: #~ P1^- isA P #~ Return P1(y,x) return QueryAtom( [axiom.leftTerm(), queryAtom.var2(), queryAtom.var1()], conceptList, roleList, individualList) #~ else: #~ Something is wrong #~ raise Exception("Something went wrong analyzing the axiom " + str(axiom)) #~ If the code reach this point, it means the axiom couldn't be applied return None
def lastModification(self,job): if job.trace_index==13050:#1293: print "FInd you!" if job.trace_index==0: return [] if isinstance(self.l[job.trace_index], FunctionCallInfo): return None#The input should not be a job in FunctionCallInfo if job.trace_index==1:#begin if job.var.v in self.l[job.trace_index-1].param_list: self.TG.linkInnerEdges(job.trace_index,job.trace_index-1,job.var.simple_access_str()) return [] indexes=self.up_slice(job) if len(indexes)>0: pairs=self.findAllReferences(job.var,indexes,False) pairs.append((indexes[0]-1,job.var,False,0,len(indexes))) #(aIndex,q,True,idx+1,lb) defs=self.getDefs(pairs,indexes) for d,v in defs: print "In list definition:",d,self.l[d] for d,v in defs: def_type=self.matchDefinitionType(d,v) if def_type==Syntax.FOR: self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) jobs=Syntax.generate_for_jobs(d, self.l[d].codestr, v) return list(set(jobs)) if def_type==Syntax.INC:#INC self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) return [TaintJob(d,v)] elif def_type==Syntax.RAW_DEF:#RAW_DEF self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) return [] elif def_type==Syntax.NORMAL_ASSIGN: self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) assign_handler=AssignmentHandler(self.l,self.TG) jobs=assign_handler.getJobs(v,d,indexes) return jobs elif def_type==Syntax.OP_ASSIGN: self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) assign_handler=AssignmentHandler(self.l,self.TG) jobs=assign_handler.getJobs(v,d,indexes) jobs.append(TaintJob(d, v)) return jobs elif def_type == Syntax.RETURN_VALUE_ASSIGN: self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) jobs=self.handleReturnAssignDirect(job.trace_index,d,v) return jobs elif def_type==Syntax.SYS_LIB_DEF: self.TG.linkInnerEdges(job.trace_index,d,v.simple_access_str()) jobs= Syntax.handle_sys_lib_def(d,v,self.l[d].codestr) return list(set(jobs)) else: #job.traceIndex-->l.index(line) #f(t->q) variable:t syntax:*(t->q) #track the access variable t->q #truncate the outter syntax (->q,*) minus ( ->q)= (*) #use new syntax to checkArgDef----- var:t->q,syntax:* #---------------- result=Syntax.isPossibleArgumentDefinition(self.l[d],v) if result is not None: rfl,p,childnum,callee,arg=result if "->headindex" in p and "header_read"==callee: print callee jobs,b=self.checkArgDef(d,job.trace_index,job.trace_index,p,rfl,childnum,callee) if b: return jobs if len(indexes)>0: i=indexes[0]-1 else: i=job.trace_index-1 #l[i] must be an instance of FunctionCallInfo if i==0:#begin if job.var.v in self.l[i].param_list: self.TG.linkInnerEdges(job.trace_index,i,job.var.simple_access_str()) return [] elif self.l[i].get_func_name().split("::")[-1].strip() in self.l[i-1].codestr and self.l[i]==self.l[job.trace_index].get_func_call_info():#call point if job.var.v in self.l[i].param_list: self.TG.linkInnerEdges(job.trace_index,i,job.var.simple_access_str()) return [TaintJob(i,job.var)] return [] elif self.isMacroCall(i-1): if job.var.v in self.l[i].param_list: self.TG.linkInnerEdges(job.trace_index,i,job.var.simple_access_str()) return [TaintJob(i,job.var)] return [] return []
def __indent(indentLevel): syntax = Syntax() return syntax.indent*indentLevel
def __parseQuery(self, queryToParse, conceptList, roleList, individualList, inequalitiesAllowed): syntax = Syntax() result = None if isinstance(queryToParse, CQ): #~ We directly add the CQ to self.__cqs and exit self.__cqs.add(queryToParse) #~ Find the freeVars of the current UCQ. #~ To do so, we collect all the free vars appearing in the inner UCQs. self.__freeVars.update(queryToParse.freeVars()) return 0 #~ If queryToParse is a string, we parse it by considering the parenthesis that close every expression #~ and analyse the resulting pyparsing.ParseResults. #~ If queryToParse is already a pyparsing.ParseResults, then we analise it directly. elif isinstance(queryToParse, str): parser = StringStart() + nestedExpr() + StringEnd() result = parser.parseString(queryToParse) #~ We consider only the first element of result, since, if it is a valid list, #~ then result is a nested list, and thus result[0] is the actual list we #~ are interested in. result = result[0] elif isinstance(queryToParse, (ParseResults, tuple, list)): result = queryToParse if result[0] == syntax.queryOr: #~ The list must contain "or" plus at least two inner UCQs, #~ starting from element result[1]. if len(result) <= 2: raise Exception( "The expression \"(or ... )\" must contain at least 2 internal UCQs." ) for cq in result[1:]: if isinstance(cq, CQ): self.__cqs.add(cq) else: self.__cqs.add( CQ(cq, conceptList, roleList, individualList, inequalitiesAllowed=self.__inequalitiesAllowed)) #~ Check that all the inner UCQs have the same free variables for check in combinations(self.__cqs, 2): if check[0].freeVars() != check[1].freeVars(): raise Exception( "The UCQs have different free variables in them!\n" + str(check[0]) + "\n" + str(check[1])) else: #~ No specific keyword is used, thus it must be a CQ if len(result) == 1 and isinstance(result[0], CQ): #~ We directly add the CQ to self.__cqs and exit self.__cqs.add(result[0]) #~ Find the freeVars of the current UCQ. #~ To do so, we collect all the free vars appearing in the inner UCQs. self.__freeVars.update(result[0].freeVars()) return 0 else: self.__cqs.add( CQ(result, conceptList, roleList, individualList, inequalitiesAllowed=self.__inequalitiesAllowed)) #~ Find the freeVars of the current UCQ. #~ To do so, we collect all the free vars appearing in the inner UCQs. for cq in self.__cqs: self.__freeVars.update(cq.freeVars())
def checkArgDef(self,callsiteIndex,beginIndex,lowerBound,p,rfl,childnum,callee): if p==[] or isinstance(self.l[callsiteIndex+1],LineOfCode):#Abort non-pointer variable. return [],False #Note: funciton name and callee name may not be equal as there exist macro and function pointer #e.g. nread = abfd->iovec->bread (abfd, ptr, size); indexes=self.slice_same_func_lines(callsiteIndex+2,lowerBound)#PlUS TWO("callsiteIndex+2")means #start from the first line of callee function. params=self.l[callsiteIndex+1].get_param_list().split(",") if len(params)-1<childnum: skip_va_arg_nums=childnum-len(params) res=self.check_va_arg_style(skip_va_arg_nums,indexes) if not res: print "BAD arg-->param number match!" print 1/0 varname,indexes=res var= TaintVar(varname,p,rfl) else: #FIX ME following part should change for va_arg case #----------------------------------------------------------------------------------------# varname=params[int(childnum)].split("=")[0] #handle "=" cases like: #args_callback_command (name=0xbfffeb26 "swfdump0.9.2log/exploit_0_0", val=val@entry=0x0) at swfdump.c:200 print self.l[callsiteIndex+1] var=TaintVar(varname,p,rfl) #---------------------------------------------------------------------------------------# pairs=self.findAllReferences(var,indexes,True) pairs.append((callsiteIndex+1,var,True,0,len(indexes))) defs=self.getDefs(pairs,indexes) for d,v in defs: print "%%%",self.l[d] for d,v in defs: #BUG def_type=self.matchDefinitionType(d,v) if def_type==Syntax.FOR: self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) jobs=Syntax.generate_for_jobs(d, self.l[d].codestr, v) return self.taintUp(jobs),True if def_type==Syntax.INC:#INC self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) jobs.append(TaintJob(d,v)) jobs=list(set(jobs)) return self.taintUp(jobs),True elif def_type==Syntax.RAW_DEF:#RAW_DEF self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) return [],True elif def_type==Syntax.NORMAL_ASSIGN: self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) assign_handler=AssignmentHandler(self.l,self.TG) jobs=assign_handler.getJobs(v,d,indexes) return self.taintUp(jobs),True elif def_type==Syntax.OP_ASSIGN: self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) assign_handler=AssignmentHandler(self.l,self.TG) jobs=assign_handler.getJobs(v,d,indexes) jobs.append(TaintJob(d, v)) return self.taintUp(jobs),True elif def_type == Syntax.RETURN_VALUE_ASSIGN: self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) jobs=self.handleReturnAssignDirect(beginIndex,d,v) return jobs elif def_type==Syntax.SYS_LIB_DEF: self.TG.linkCrossEdges(beginIndex,d,v.simple_access_str()) jobs= Syntax.handle_sys_lib_def(d,v,self.l[d].codestr) return self.taintUp(jobs),True else: #job.traceIndex-->l.index(line) #f(t->q) variable:t syntax:*(t->q) #track the access variable t->q #truncate the outter syntax (->q,*) minus ( ->q)= (*) #use new syntax to checkArgDef----- var:t->q,syntax:* #---------------- result=Syntax.isPossibleArgumentDefinition(self.l[d],v) if result is not None: rfl,p,childnum,callee,arg=result jobs,b=self.checkArgDef(d,beginIndex,lowerBound,p,rfl,childnum,callee) if b: return self.taintUp(jobs),True return [],False
# 载入源代码 lexical.load_source(open('test.c').read()) # 执行词法分析 lexical_success = lexical.execute() # 打印结果 print('词法分析是否成功:\t', lexical_success) if lexical_success: lexical_result = lexical.get_result() print() print('词法分析结果:') for i in lexical_result: print(i.type, i.str, i.line) print() # 开始执行语法分析 syntax = Syntax() syntax.put_source(lexical_result) syntax_success = syntax.execute() print('语法分析和语义分析是否成功\t', syntax_success) if syntax_success: print() print('语义分析结果:\t') print('三地址代码:\t') i = -1 for code in syntax.get_result().root.code: i += 1 print(i, ' \t', code) else: print('错误原因:\t', syntax.get_error().info, syntax.get_error().line, '行') else: print('错误原因:\t', lexical.get_error().info)