def mine_grammar(self): grammar = extend_grammar(self.QUERY_GRAMMAR) grammar["<action>"] = [self.action] query = "" for field in self.fields: field_symbol = new_symbol(grammar, "<" + field + ">") field_type = self.fields[field] if query != "": query += "&" query += field_symbol if isinstance(field_type, str): field_type_symbol = "<" + field_type + ">" grammar[field_symbol] = [field + "=" + field_type_symbol] if field_type_symbol not in grammar: # Unknown type grammar[field_type_symbol] = ["<text>"] else: # List of values value_symbol = new_symbol(grammar, "<" + field + "-value>") grammar[field_symbol] = [field + "=" + value_symbol] grammar[value_symbol] = field_type grammar["<query>"] = [query] # Remove unused parts for nonterminal in unreachable_nonterminals(grammar): del grammar[nonterminal] assert is_valid_grammar(grammar) return grammar
def mine_state_grammar(self, grammar={}, state_symbol=None): grammar = extend_grammar(self.GUI_GRAMMAR, grammar) if state_symbol is None: state_symbol = self.new_state_symbol(grammar) grammar[state_symbol] = [] alternatives = [] form = "" submit = None for action in self.mine_state_actions(): if action.startswith("submit"): submit = action elif action.startswith("click"): link_target = self.new_state_symbol(grammar) grammar[link_target] = [self.UNEXPLORED_STATE] alternatives.append(action + '\n' + link_target) elif action.startswith("ignore"): pass else: # fill(), check() actions if len(form) > 0: form += '\n' form += action if submit is not None: if len(form) > 0: form += '\n' form += submit if len(form) > 0: form_target = self.new_state_symbol(grammar) grammar[form_target] = [self.UNEXPLORED_STATE] alternatives.append(form + '\n' + form_target) alternatives += [self.FINAL_STATE] grammar[state_symbol] = alternatives # Remove unused parts for nonterminal in unreachable_nonterminals(grammar): del grammar[nonterminal] assert is_valid_grammar(grammar) return grammar
def duplicate_context(grammar, symbol, expansion=None, depth=float('inf')): """Duplicate an expansion within a grammar. In the given grammar, take the given expansion of the given symbol (if expansion is omitted: all symbols), and replace it with a new expansion referring to a duplicate of all originally referenced rules. If depth is given, limit duplication to `depth` references (default: unlimited) """ orig_grammar = extend_grammar(grammar) _duplicate_context(grammar, orig_grammar, symbol, expansion, depth, seen={}) # After duplication, we may have unreachable rules; delete them for nonterminal in unreachable_nonterminals(grammar): del grammar[nonterminal]
def make_grammar(num_symbols=3, num_alts=3): terminals = list(string.ascii_lowercase) grammar = {} name = None for _ in range(num_symbols): nonterminals = [k[1:-1] for k in grammar.keys()] name, expansions = \ make_rule(nonterminals, terminals, num_alts) grammar[name] = expansions grammar[START_SYMBOL] = [name] # Remove unused parts for nonterminal in unreachable_nonterminals(grammar): del grammar[nonterminal] assert is_valid_grammar(grammar) return grammar
def replace_symbol(grammar, old_symbol, new_symbol): """Return a grammar in which all occurrences of `old_symbol` are replaced by `new_symbol`""" new_grammar = {} for symbol in grammar: new_expansions = [] for expansion in grammar[symbol]: new_expansion_string = exp_string(expansion).replace(old_symbol, new_symbol) if len(exp_opts(expansion)) > 0: new_expansion = (new_expansion_string, exp_opts(expansion)) else: new_expansion = new_expansion_string new_expansions.append(new_expansion) new_grammar[symbol] = new_expansions # Remove unused parts for nonterminal in unreachable_nonterminals(new_grammar): del new_grammar[nonterminal] return new_grammar
def set_arguments(self, args): self._ebnf_grammar["<arguments>"] = [" " + args] # Delete rules for previous arguments for nonterminal in unreachable_nonterminals(self._ebnf_grammar): del self._ebnf_grammar[nonterminal]