| 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 |
| 11 # with the distribution. | 11 # with the distribution. |
| 12 # * Neither the name of Google Inc. nor the names of its | 12 # * Neither the name of Google Inc. nor the names of its |
| 13 # contributors may be used to endorse or promote products derived | 13 # contributors may be used to endorse or promote products derived |
| 14 # from this software without specific prior written permission. | 14 # from this software without specific prior written permission. |
| 15 # | 15 # |
| 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 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 from dfa import Dfa | 28 from dfa import Dfa |
| 29 import jinja2 |
| 29 | 30 |
| 30 class CodeGenerator: | 31 class CodeGenerator: |
| 31 debug = False | |
| 32 | 32 |
| 33 @staticmethod | 33 def __init__(self, rule_processor, use_mdfa, debug_print = False): |
| 34 def key_to_code(key): | |
| 35 code = 'if (' | |
| 36 first = True | |
| 37 for (kind, r) in key.range_iter(): | |
| 38 if kind == 'CLASS': # FIXME: add class checks | |
| 39 continue | |
| 40 assert kind == 'LATIN_1' | |
| 41 if not first: | |
| 42 code += ' || ' | |
| 43 if r[0] == r[1]: | |
| 44 code += 'yych == %s' % r[0] | |
| 45 elif r[0] == 0: | |
| 46 code += 'yych <= %s' % r[1] | |
| 47 elif r[1] == 255: # FIXME: this should depend on the char type maybe?? | |
| 48 code += 'yych >= %s' % r[0] | |
| 49 else: | |
| 50 code += '(yych >= %s && yych <= %s)' % (r[0], r[1]) | |
| 51 first = False | |
| 52 code += ')' | |
| 53 return code | |
| 54 | |
| 55 @staticmethod | |
| 56 def __terminate_code(value): | |
| 57 assert value == None | |
| 58 return 'PUSH_TOKEN(Token::EOS); return 0;' | |
| 59 | |
| 60 @staticmethod | |
| 61 def __terminate_illegal_code(value): | |
| 62 assert value == None | |
| 63 return 'PUSH_TOKEN(Token::ILLEGAL); return 1;' | |
| 64 | |
| 65 @staticmethod | |
| 66 def __skip_code(value): | |
| 67 assert value == None | |
| 68 return 'SKIP();' | |
| 69 | |
| 70 @staticmethod | |
| 71 def __push_line_terminator_code(value): | |
| 72 assert value == None | |
| 73 return 'PUSH_LINE_TERMINATOR();' | |
| 74 | |
| 75 @staticmethod | |
| 76 def __push_token_code(value): | |
| 77 assert value != None | |
| 78 return 'PUSH_TOKEN(Token::%s);' % value | |
| 79 | |
| 80 @staticmethod | |
| 81 def __code_code(value): | |
| 82 assert value != None | |
| 83 return '%s\n' % value | |
| 84 | |
| 85 @staticmethod | |
| 86 def __skip_and_terminate_code(value): | |
| 87 return 'SKIP(); --start_; ' + CodeGenerator.__terminate_code(value) | |
| 88 | |
| 89 def __init__(self, dfa, default_action): | |
| 90 self.__dfa = dfa | |
| 91 self.__start_node_number = dfa.start_state().node_number() | |
| 92 self.__default_action = default_action | |
| 93 # make this better | |
| 94 self.__action_code_map = { | |
| 95 "terminate" : self.__terminate_code, | |
| 96 "terminate_illegal" : self.__terminate_illegal_code, | |
| 97 "push_token" : self.__push_token_code, | |
| 98 "push_line_terminator" : self.__push_line_terminator_code, | |
| 99 "skip" : self.__skip_code, | |
| 100 "code" : self.__code_code, | |
| 101 "skip_and_terminate" : self.__skip_and_terminate_code, | |
| 102 } | |
| 103 | |
| 104 def __dfa_state_to_code(self, state): | |
| 105 # FIXME: add different check types (if, switch, lookup table) | |
| 106 # FIXME: add action + break / continue | |
| 107 # FIXME: add default action | |
| 108 code = '' | |
| 109 if self.__start_node_number == state.node_number(): | |
| 110 code += ''' | |
| 111 code_start: | |
| 112 ''' | |
| 113 | |
| 114 code += ''' | |
| 115 code_%s: | |
| 116 ''' % state.node_number() | |
| 117 | |
| 118 if CodeGenerator.debug: | |
| 119 code += ''' | |
| 120 fprintf(stderr, "state %s\\n"); | |
| 121 ''' % state.node_number() | |
| 122 | |
| 123 entry_action = state.action().entry_action() if state.action() else None | |
| 124 match_action = state.action().match_action() if state.action() else None | |
| 125 | |
| 126 if entry_action: | |
| 127 code += self.__action_code_map[entry_action[0]](entry_action[1]) | |
| 128 | |
| 129 if CodeGenerator.debug: | |
| 130 code += ''' | |
| 131 fprintf(stderr, "char at hand is %c (%d)\\n", yych, yych); | |
| 132 ''' | |
| 133 | |
| 134 for key, s in state.transitions().items(): | |
| 135 code += CodeGenerator.key_to_code(key) | |
| 136 code += ''' { | |
| 137 FORWARD(); | |
| 138 goto code_%s; | |
| 139 } | |
| 140 ''' % s.node_number() | |
| 141 | |
| 142 if match_action: | |
| 143 code += self.__action_code_map[match_action[0]](match_action[1]) | |
| 144 code += 'goto code_%s;\n' % self.__start_node_number | |
| 145 else: | |
| 146 code += 'goto default_action;\n' | |
| 147 return code | |
| 148 | |
| 149 def __process(self): | |
| 150 dfa = self.__dfa | |
| 151 default_action = self.__default_action | |
| 152 code = ''' | |
| 153 #include "lexer/even-more-experimental-scanner.h" | |
| 154 | |
| 155 namespace v8 { | |
| 156 namespace internal { | |
| 157 uint32_t EvenMoreExperimentalScanner::DoLex() { | |
| 158 YYCTYPE yych = *cursor_; | |
| 159 goto code_%s; | |
| 160 ''' % self.__start_node_number | |
| 161 def f(state, code): | |
| 162 code += self.__dfa_state_to_code(state) | |
| 163 return code | |
| 164 code = dfa.visit_all_states(f, code) | |
| 165 | |
| 166 default_action_code = '' | |
| 167 assert(default_action and default_action.match_action()) | |
| 168 action = default_action.match_action() | |
| 169 default_action_code = self.__action_code_map[action[0]](action[1]) | |
| 170 code += ''' | |
| 171 CHECK(false); goto code_start; | |
| 172 default_action:''' | |
| 173 if CodeGenerator.debug: | |
| 174 code += ''' | |
| 175 fprintf(stderr, "default action\\n"); | |
| 176 ''' | |
| 177 code += ''' | |
| 178 %s | |
| 179 FORWARD(); | |
| 180 goto code_%s; | |
| 181 return 0; | |
| 182 } | |
| 183 } | |
| 184 } | |
| 185 ''' % (default_action_code, self.__start_node_number) | |
| 186 return code | |
| 187 | |
| 188 @staticmethod | |
| 189 def rule_processor_to_code(rule_processor, use_mdfa): | |
| 190 if use_mdfa: | 34 if use_mdfa: |
| 191 dfa = rule_processor.default_automata().minimal_dfa() | 35 dfa = rule_processor.default_automata().minimal_dfa() |
| 192 else: | 36 else: |
| 193 dfa = rule_processor.default_automata().dfa() | 37 dfa = rule_processor.default_automata().dfa() |
| 194 return CodeGenerator(dfa, rule_processor.default_action).__process() | 38 self.__dfa = dfa |
| 39 self.__default_action = rule_processor.default_action |
| 40 self.__debug_print = debug_print |
| 41 |
| 42 def process(self): |
| 43 |
| 44 start_node_number = self.__dfa.start_state().node_number() |
| 45 |
| 46 dfa_states = [] |
| 47 self.__dfa.visit_all_states(lambda state, acc: dfa_states.append(state)) |
| 48 |
| 49 default_action = self.__default_action |
| 50 assert(default_action and default_action.match_action()) |
| 51 default_action = default_action.match_action() |
| 52 |
| 53 template_env = jinja2.Environment( |
| 54 loader = jinja2.PackageLoader('lexer_generator', '.'), |
| 55 undefined = jinja2.StrictUndefined) |
| 56 template = template_env.get_template('code_generator.jinja') |
| 57 |
| 58 return template.render( |
| 59 start_node_number = start_node_number, |
| 60 debug_print = self.__debug_print, |
| 61 default_action = default_action, |
| 62 dfa_states = dfa_states) |
| OLD | NEW |