| OLD | NEW |
| 1 # Copyright 2013 the V8 project authors. All rights reserved. | 1 # Copyright 2013 the V8 project authors. All rights reserved. |
| 2 # Redistribution and use in source and binary forms, with or without | 2 # Redistribution and use in source and binary forms, with or without |
| 3 # modification, are permitted provided that the following conditions are | 3 # modification, are permitted provided that the following conditions are |
| 4 # met: | 4 # met: |
| 5 # | 5 # |
| 6 # * Redistributions of source code must retain the above copyright | 6 # * Redistributions of source code must retain the above copyright |
| 7 # notice, this list of conditions and the following disclaimer. | 7 # notice, this list of conditions and the following disclaimer. |
| 8 # * Redistributions in binary form must reproduce the above | 8 # * Redistributions in binary form must reproduce the above |
| 9 # copyright notice, this list of conditions and the following | 9 # copyright notice, this list of conditions and the following |
| 10 # disclaimer in the documentation and/or other materials provided | 10 # disclaimer in the documentation and/or other materials provided |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 import ply.yacc as yacc | 28 import ply.yacc as yacc |
| 29 from automaton import Action | 29 from automaton import Action |
| 30 from rule_lexer import RuleLexer | 30 from rule_lexer import RuleLexer |
| 31 from regex_parser import RegexParser | 31 from regex_parser import RegexParser |
| 32 from nfa_builder import NfaBuilder | 32 from nfa_builder import NfaBuilder |
| 33 from dfa import Dfa | 33 from dfa import Dfa |
| 34 from transition_keys import TransitionKey | 34 from transition_keys import TransitionKey, KeyEncoding |
| 35 | 35 |
| 36 class RuleParserState: | 36 class RuleParserState: |
| 37 | 37 |
| 38 def __init__(self): | 38 def __init__(self, encoding): |
| 39 self.aliases = {} | 39 self.aliases = {} |
| 40 self.character_classes = {} | 40 self.character_classes = {} |
| 41 self.current_state = None | 41 self.current_state = None |
| 42 self.rules = {} | 42 self.rules = {} |
| 43 self.transitions = set() | 43 self.transitions = set() |
| 44 self.encoding = encoding |
| 44 | 45 |
| 45 def parse(self, string): | 46 def parse(self, string): |
| 46 return RuleParser.parse(string, self) | 47 return RuleParser.parse(string, self) |
| 47 | 48 |
| 48 class RuleParser: | 49 class RuleParser: |
| 49 | 50 |
| 50 tokens = RuleLexer.tokens | 51 tokens = RuleLexer.tokens |
| 51 __rule_precedence_counter = 0 | 52 __rule_precedence_counter = 0 |
| 52 __keyword_transitions = set(['continue']) | 53 __keyword_transitions = set(['continue']) |
| 53 | 54 |
| 54 def __init__(self): | 55 def __init__(self): |
| 55 self.__state = None | 56 self.__state = None |
| 56 | 57 |
| 57 def p_statements(self, p): | 58 def p_statements(self, p): |
| 58 'statements : aliases rules' | 59 'statements : aliases rules' |
| 59 | 60 |
| 60 def p_aliases(self, p): | 61 def p_aliases(self, p): |
| 61 '''aliases : alias_rule aliases | 62 '''aliases : alias_rule aliases |
| 62 | empty''' | 63 | empty''' |
| 63 | 64 |
| 64 def p_alias_rule(self, p): | 65 def p_alias_rule(self, p): |
| 65 'alias_rule : IDENTIFIER EQUALS composite_regex SEMICOLON' | 66 'alias_rule : IDENTIFIER EQUALS composite_regex SEMICOLON' |
| 66 state = self.__state | 67 state = self.__state |
| 67 assert not p[1] in state.aliases | 68 assert not p[1] in state.aliases |
| 68 graph = p[3] | 69 graph = p[3] |
| 69 state.aliases[p[1]] = graph | 70 state.aliases[p[1]] = graph |
| 70 if graph[0] == 'CLASS' or graph[0] == 'NOT_CLASS': | 71 if graph[0] == 'CLASS' or graph[0] == 'NOT_CLASS': |
| 71 classes = state.character_classes | 72 classes = state.character_classes |
| 72 assert not p[1] in classes | 73 assert not p[1] in classes |
| 73 classes[p[1]] = TransitionKey.character_class(graph, classes) | 74 encoding = state.encoding |
| 75 classes[p[1]] = TransitionKey.character_class(encoding, graph, classes) |
| 74 | 76 |
| 75 def p_rules(self, p): | 77 def p_rules(self, p): |
| 76 '''rules : state_change transition_rules rules | 78 '''rules : state_change transition_rules rules |
| 77 | empty''' | 79 | empty''' |
| 78 | 80 |
| 79 def p_state_change(self, p): | 81 def p_state_change(self, p): |
| 80 'state_change : GRAPH_OPEN IDENTIFIER GRAPH_CLOSE' | 82 'state_change : GRAPH_OPEN IDENTIFIER GRAPH_CLOSE' |
| 81 state = self.__state | 83 state = self.__state |
| 82 state.current_state = p[2] | 84 state.current_state = p[2] |
| 83 assert state.current_state | 85 assert state.current_state |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 253 parser.__state = None | 255 parser.__state = None |
| 254 assert parser_state.transitions <= set(parser_state.rules.keys()) | 256 assert parser_state.transitions <= set(parser_state.rules.keys()) |
| 255 | 257 |
| 256 class RuleProcessor(object): | 258 class RuleProcessor(object): |
| 257 | 259 |
| 258 def __init__(self, parser_state): | 260 def __init__(self, parser_state): |
| 259 self.__automata = {} | 261 self.__automata = {} |
| 260 self.__process_parser_state(parser_state) | 262 self.__process_parser_state(parser_state) |
| 261 | 263 |
| 262 @staticmethod | 264 @staticmethod |
| 263 def parse(string): | 265 def parse(string, encoding_name): |
| 264 parser_state = RuleParserState() | 266 parser_state = RuleParserState(KeyEncoding.get(encoding_name)) |
| 265 RuleParser.parse(string, parser_state) | 267 RuleParser.parse(string, parser_state) |
| 266 return RuleProcessor(parser_state) | 268 return RuleProcessor(parser_state) |
| 267 | 269 |
| 268 def automata_iter(self): | 270 def automata_iter(self): |
| 269 return iter(self.__automata.items()) | 271 return iter(self.__automata.items()) |
| 270 | 272 |
| 271 def default_automata(self): | 273 def default_automata(self): |
| 272 return self.__automata['default'] | 274 return self.__automata['default'] |
| 273 | 275 |
| 274 class Automata(object): | 276 class Automata(object): |
| 275 | 277 |
| 276 def __init__(self, builder, graph): | 278 def __init__(self, builder, graph): |
| 277 self.__builder = builder | 279 self.__builder = builder |
| 278 self.__graph = graph | 280 self.__graph = graph |
| 279 self.__nfa = None | 281 self.__nfa = None |
| 280 self.__dfa = None | 282 self.__dfa = None |
| 281 self.__minimial_dfa = None | 283 self.__minimial_dfa = None |
| 282 | 284 |
| 283 def nfa(self): | 285 def nfa(self): |
| 284 if not self.__nfa: | 286 if not self.__nfa: |
| 285 self.__nfa = self.__builder.nfa(self.__graph) | 287 self.__nfa = self.__builder.nfa(self.__graph) |
| 286 return self.__nfa | 288 return self.__nfa |
| 287 | 289 |
| 288 def dfa(self): | 290 def dfa(self): |
| 289 if not self.__dfa: | 291 if not self.__dfa: |
| 290 (start, dfa_nodes) = self.nfa().compute_dfa() | 292 (start, dfa_nodes) = self.nfa().compute_dfa() |
| 291 self.__dfa = Dfa(start, dfa_nodes) | 293 self.__dfa = Dfa(self.nfa().encoding(), start, dfa_nodes) |
| 292 return self.__dfa | 294 return self.__dfa |
| 293 | 295 |
| 294 def minimal_dfa(self): | 296 def minimal_dfa(self): |
| 295 if not self.__minimial_dfa: | 297 if not self.__minimial_dfa: |
| 296 self.__minimial_dfa = self.dfa().minimize() | 298 self.__minimial_dfa = self.dfa().minimize() |
| 297 return self.__minimial_dfa | 299 return self.__minimial_dfa |
| 298 | 300 |
| 299 def __process_parser_state(self, parser_state): | 301 def __process_parser_state(self, parser_state): |
| 300 rule_map = {} | 302 rule_map = {} |
| 301 builder = NfaBuilder() | 303 builder = NfaBuilder(parser_state.encoding, parser_state.character_classes) |
| 302 builder.set_character_classes(parser_state.character_classes) | |
| 303 assert 'default' in parser_state.rules | 304 assert 'default' in parser_state.rules |
| 304 def process(subgraph, v): | 305 def process(subgraph, v): |
| 305 graphs = [] | 306 graphs = [] |
| 306 continues = 0 | 307 continues = 0 |
| 307 for graph, precedence, action in v['regex']: | 308 for graph, precedence, action in v['regex']: |
| 308 (entry_action, match_action, transition) = action | 309 (entry_action, match_action, transition) = action |
| 309 if entry_action or match_action: | 310 if entry_action or match_action: |
| 310 action = Action(entry_action, match_action, precedence) | 311 action = Action(entry_action, match_action, precedence) |
| 311 graph = NfaBuilder.add_action(graph, action) | 312 graph = NfaBuilder.add_action(graph, action) |
| 312 if not transition: | 313 if not transition: |
| (...skipping 19 matching lines...) Expand all Loading... |
| 332 for k, v in parser_state.rules.items(): | 333 for k, v in parser_state.rules.items(): |
| 333 if k == 'default': continue | 334 if k == 'default': continue |
| 334 process(k, v) | 335 process(k, v) |
| 335 process('default', parser_state.rules['default']) | 336 process('default', parser_state.rules['default']) |
| 336 # build the automata | 337 # build the automata |
| 337 for rule_name, graph in rule_map.items(): | 338 for rule_name, graph in rule_map.items(): |
| 338 self.__automata[rule_name] = RuleProcessor.Automata(builder, graph) | 339 self.__automata[rule_name] = RuleProcessor.Automata(builder, graph) |
| 339 # process default_action | 340 # process default_action |
| 340 default_action = parser_state.rules['default']['default_action'] | 341 default_action = parser_state.rules['default']['default_action'] |
| 341 self.default_action = Action(None, default_action[1]) if default_action else
None | 342 self.default_action = Action(None, default_action[1]) if default_action else
None |
| OLD | NEW |