Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2013 The Chromium Authors. All rights reserved. | 2 # Copyright 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Generates a syntax tree from a Mojo IDL file.""" | 6 """Generates a syntax tree from a Mojo IDL file.""" |
| 7 | 7 |
| 8 | 8 |
| 9 import sys | 9 import sys |
| 10 import os.path | 10 import os.path |
| 11 | 11 |
| 12 | |
| 13 # Try to load the ply module, if not, then assume it is in the third_party | 12 # Try to load the ply module, if not, then assume it is in the third_party |
| 14 # directory. | 13 # directory. |
| 15 try: | 14 try: |
| 16 # Disable lint check which fails to find the ply module. | 15 # Disable lint check which fails to find the ply module. |
| 17 # pylint: disable=F0401 | 16 # pylint: disable=F0401 |
| 18 from ply import lex | 17 from ply import lex |
| 19 from ply import yacc | 18 from ply import yacc |
| 20 except ImportError: | 19 except ImportError: |
| 21 module_path, module_name = os.path.split(__file__) | 20 module_path, module_name = os.path.split(__file__) |
| 22 third_party = os.path.join( | 21 third_party = os.path.join( |
| 23 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') | 22 module_path, os.pardir, os.pardir, os.pardir, os.pardir, 'third_party') |
| 24 sys.path.append(third_party) | 23 sys.path.append(third_party) |
| 25 # pylint: disable=F0401 | 24 # pylint: disable=F0401 |
| 26 from ply import lex | 25 from ply import lex |
| 27 from ply import yacc | 26 from ply import yacc |
| 28 | 27 |
| 28 from .mojo_lexer import Lexer | |
| 29 | |
| 29 | 30 |
| 30 def ListFromConcat(*items): | 31 def ListFromConcat(*items): |
| 31 """Generate list by concatenating inputs""" | 32 """Generate list by concatenating inputs""" |
| 32 itemsout = [] | 33 itemsout = [] |
| 33 for item in items: | 34 for item in items: |
| 34 if item is None: | 35 if item is None: |
| 35 continue | 36 continue |
| 36 if type(item) is not type([]): | 37 if type(item) is not type([]): |
| 37 itemsout.append(item) | 38 itemsout.append(item) |
| 38 else: | 39 else: |
| 39 itemsout.extend(item) | 40 itemsout.extend(item) |
| 40 | 41 |
| 41 return itemsout | 42 return itemsout |
| 42 | 43 |
| 43 | 44 |
| 44 class Lexer(object): | |
| 45 | |
| 46 # This field is required by lex to specify the complete list of valid tokens. | |
| 47 tokens = ( | |
| 48 'NAME', | |
| 49 'NUMBER', | |
| 50 | |
| 51 'ORDINAL', | |
| 52 | |
| 53 'HANDLE', | |
| 54 'DATAPIPECONSUMER', | |
| 55 'DATAPIPEPRODUCER', | |
| 56 'MESSAGEPIPE', | |
| 57 | |
| 58 'MODULE', | |
| 59 'STRUCT', | |
| 60 'INTERFACE', | |
| 61 'ENUM', | |
| 62 'VOID', | |
| 63 | |
| 64 'LCURLY', | |
| 65 'RCURLY', | |
| 66 'LPAREN', | |
| 67 'RPAREN', | |
| 68 'LANGLE', | |
| 69 'RANGLE', | |
| 70 'LBRACKET', | |
| 71 'RBRACKET', | |
| 72 'COMMA', | |
| 73 'SEMICOLON', | |
| 74 'EQUALS', | |
| 75 ) | |
| 76 | |
| 77 t_LCURLY = r'{' | |
| 78 t_RCURLY = r'}' | |
| 79 t_LPAREN = r'\(' | |
| 80 t_RPAREN = r'\)' | |
| 81 t_LANGLE = r'<' | |
| 82 t_RANGLE = r'>' | |
| 83 t_LBRACKET = r'\[' | |
| 84 t_RBRACKET = r'\]' | |
| 85 t_COMMA = r',' | |
| 86 t_SEMICOLON = r';' | |
| 87 t_EQUALS = r'=' | |
| 88 t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' | |
| 89 t_NUMBER = r'\d+' | |
| 90 t_ORDINAL = r'@[0-9]*' | |
| 91 | |
| 92 def t_HANDLE(self, t): | |
| 93 r'handle' | |
| 94 return t | |
| 95 | |
| 96 def t_DATAPIPECONSUMER(self, t): | |
| 97 r'data_pipe_consumer' | |
| 98 return t | |
| 99 | |
| 100 def t_DATAPIPEPRODUCER(self, t): | |
| 101 r'data_pipe_producer' | |
| 102 return t | |
| 103 | |
| 104 def t_MESSAGEPIPE(self, t): | |
| 105 r'message_pipe' | |
| 106 return t | |
| 107 | |
| 108 def t_MODULE(self, t): | |
| 109 r'module' | |
| 110 return t | |
| 111 | |
| 112 def t_STRUCT(self, t): | |
| 113 r'struct' | |
| 114 return t | |
| 115 | |
| 116 def t_INTERFACE(self, t): | |
| 117 r'interface' | |
| 118 return t | |
| 119 | |
| 120 def t_ENUM(self, t): | |
| 121 r'enum' | |
| 122 return t | |
| 123 | |
| 124 def t_VOID(self, t): | |
| 125 r'void' | |
| 126 return t | |
| 127 | |
| 128 # Ignore C and C++ style comments | |
| 129 def t_COMMENT(self, t): | |
| 130 r'(/\*(.|\n)*?\*/)|(//.*(\n[ \t]*//.*)*)' | |
| 131 pass | |
| 132 | |
| 133 # Ignored characters | |
| 134 t_ignore = " \t" | |
| 135 | |
| 136 def t_newline(self, t): | |
| 137 r'\n+' | |
| 138 t.lexer.lineno += t.value.count("\n") | |
| 139 | |
| 140 def t_error(self, t): | |
| 141 print("Illegal character '%s'" % t.value[0]) | |
| 142 t.lexer.skip(1) | |
| 143 | |
| 144 | |
| 145 class Parser(object): | 45 class Parser(object): |
| 146 | 46 |
| 147 def __init__(self, lexer): | 47 def __init__(self, lexer): |
| 148 self.tokens = lexer.tokens | 48 self.tokens = lexer.tokens |
| 149 | 49 |
| 150 def p_module(self, p): | 50 def p_module(self, p): |
| 151 """module : MODULE NAME LCURLY definitions RCURLY""" | 51 """module : MODULE NAME LBRACE definitions RBRACE""" |
| 152 p[0] = ('MODULE', p[2], p[4]) | 52 p[0] = ('MODULE', p[2], p[4]) |
| 153 | 53 |
| 154 def p_definitions(self, p): | 54 def p_definitions(self, p): |
| 155 """definitions : definition definitions | 55 """definitions : definition definitions |
| 156 |""" | 56 |""" |
| 157 if len(p) > 1: | 57 if len(p) > 1: |
| 158 p[0] = ListFromConcat(p[1], p[2]) | 58 p[0] = ListFromConcat(p[1], p[2]) |
| 159 | 59 |
| 160 def p_definition(self, p): | 60 def p_definition(self, p): |
| 161 """definition : struct | 61 """definition : struct |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 172 def p_attributes(self, p): | 72 def p_attributes(self, p): |
| 173 """attributes : attribute | 73 """attributes : attribute |
| 174 | attribute COMMA attributes | 74 | attribute COMMA attributes |
| 175 | """ | 75 | """ |
| 176 if len(p) == 2: | 76 if len(p) == 2: |
| 177 p[0] = ListFromConcat(p[1]) | 77 p[0] = ListFromConcat(p[1]) |
| 178 elif len(p) > 3: | 78 elif len(p) > 3: |
| 179 p[0] = ListFromConcat(p[1], p[3]) | 79 p[0] = ListFromConcat(p[1], p[3]) |
| 180 | 80 |
| 181 def p_attribute(self, p): | 81 def p_attribute(self, p): |
| 182 """attribute : NAME EQUALS NUMBER | 82 """attribute : NAME EQUALS expression |
| 183 | NAME EQUALS NAME""" | 83 | NAME EQUALS NAME""" |
| 184 p[0] = ('ATTRIBUTE', p[1], p[3]) | 84 p[0] = ('ATTRIBUTE', p[1], p[3]) |
| 185 | 85 |
| 186 def p_struct(self, p): | 86 def p_struct(self, p): |
| 187 """struct : attribute_section STRUCT NAME LCURLY struct_body RCURLY SEMICOLO N""" | 87 """struct : attribute_section STRUCT NAME LBRACE struct_body RBRACE SEMI""" |
| 188 p[0] = ('STRUCT', p[3], p[1], p[5]) | 88 p[0] = ('STRUCT', p[3], p[1], p[5]) |
| 189 | 89 |
| 190 def p_struct_body(self, p): | 90 def p_struct_body(self, p): |
| 191 """struct_body : field struct_body | 91 """struct_body : field struct_body |
| 192 | enum struct_body | 92 | enum struct_body |
| 193 |""" | 93 |""" |
| 194 if len(p) > 1: | 94 if len(p) > 1: |
| 195 p[0] = ListFromConcat(p[1], p[2]) | 95 p[0] = ListFromConcat(p[1], p[2]) |
| 196 | 96 |
| 197 def p_field(self, p): | 97 def p_field(self, p): |
| 198 """field : typename NAME ordinal SEMICOLON""" | 98 """field : typename NAME ordinal SEMI""" |
| 199 p[0] = ('FIELD', p[1], p[2], p[3]) | 99 p[0] = ('FIELD', p[1], p[2], p[3]) |
| 200 | 100 |
| 201 def p_interface(self, p): | 101 def p_interface(self, p): |
| 202 """interface : attribute_section INTERFACE NAME LCURLY interface_body RCURLY SEMICOLON""" | 102 """interface : attribute_section INTERFACE NAME LBRACE interface_body RBRACE SEMI""" |
| 203 p[0] = ('INTERFACE', p[3], p[1], p[5]) | 103 p[0] = ('INTERFACE', p[3], p[1], p[5]) |
| 204 | 104 |
| 205 def p_interface_body(self, p): | 105 def p_interface_body(self, p): |
| 206 """interface_body : method interface_body | 106 """interface_body : method interface_body |
| 207 | enum interface_body | 107 | enum interface_body |
| 208 | """ | 108 | """ |
| 209 if len(p) > 1: | 109 if len(p) > 1: |
| 210 p[0] = ListFromConcat(p[1], p[2]) | 110 p[0] = ListFromConcat(p[1], p[2]) |
| 211 | 111 |
| 212 def p_method(self, p): | 112 def p_method(self, p): |
| 213 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMICOLON""" | 113 """method : VOID NAME LPAREN parameters RPAREN ordinal SEMI""" |
| 214 p[0] = ('METHOD', p[2], p[4], p[6]) | 114 p[0] = ('METHOD', p[2], p[4], p[6]) |
| 215 | 115 |
| 216 def p_parameters(self, p): | 116 def p_parameters(self, p): |
| 217 """parameters : parameter | 117 """parameters : parameter |
| 218 | parameter COMMA parameters | 118 | parameter COMMA parameters |
| 219 | """ | 119 | """ |
| 220 if len(p) == 1: | 120 if len(p) == 1: |
| 221 p[0] = [] | 121 p[0] = [] |
| 222 elif len(p) == 2: | 122 elif len(p) == 2: |
| 223 p[0] = ListFromConcat(p[1]) | 123 p[0] = ListFromConcat(p[1]) |
| 224 elif len(p) > 3: | 124 elif len(p) > 3: |
| 225 p[0] = ListFromConcat(p[1], p[3]) | 125 p[0] = ListFromConcat(p[1], p[3]) |
| 226 | 126 |
| 227 def p_parameter(self, p): | 127 def p_parameter(self, p): |
| 228 """parameter : typename NAME ordinal""" | 128 """parameter : typename NAME ordinal""" |
| 229 p[0] = ('PARAM', p[1], p[2], p[3]) | 129 p[0] = ('PARAM', p[1], p[2], p[3]) |
| 230 | 130 |
| 231 def p_typename(self, p): | 131 def p_typename(self, p): |
| 232 """typename : basictypename | 132 """typename : basictypename |
| 233 | array""" | 133 | array""" |
| 234 p[0] = p[1] | 134 p[0] = p[1] |
| 235 | 135 |
| 236 def p_basictypename(self, p): | 136 def p_basictypename(self, p): |
| 237 """basictypename : NAME | 137 """basictypename : NAME |
| 238 | HANDLE | 138 | HANDLE |
| 239 | specializedhandle""" | 139 | specializedhandle""" |
| 240 p[0] = p[1] | 140 p[0] = p[1] |
| 241 | 141 |
| 242 def p_specializedhandle(self, p): | 142 def p_specializedhandle(self, p): |
| 243 """specializedhandle : HANDLE LANGLE specializedhandlename RANGLE""" | 143 """specializedhandle : HANDLE LT specializedhandlename GT""" |
| 244 p[0] = "handle<" + p[3] + ">" | 144 p[0] = "handle<" + p[3] + ">" |
| 245 | 145 |
| 246 def p_specializedhandlename(self, p): | 146 def p_specializedhandlename(self, p): |
| 247 """specializedhandlename : DATAPIPECONSUMER | 147 """specializedhandlename : DATA_PIPE_CONSUMER |
| 248 | DATAPIPEPRODUCER | 148 | DATA_PIPE_PRODUCER |
| 249 | MESSAGEPIPE""" | 149 | MESSAGE_PIPE""" |
| 250 p[0] = p[1] | 150 p[0] = p[1] |
| 251 | 151 |
| 252 def p_array(self, p): | 152 def p_array(self, p): |
| 253 """array : basictypename LBRACKET RBRACKET""" | 153 """array : basictypename LBRACKET RBRACKET""" |
| 254 p[0] = p[1] + "[]" | 154 p[0] = p[1] + "[]" |
| 255 | 155 |
| 256 def p_ordinal(self, p): | 156 def p_ordinal(self, p): |
| 257 """ordinal : ORDINAL | 157 """ordinal : ORDINAL |
| 258 | """ | 158 | """ |
| 259 if len(p) > 1: | 159 if len(p) > 1: |
| 260 p[0] = p[1] | 160 p[0] = p[1] |
| 261 | 161 |
| 262 def p_enum(self, p): | 162 def p_enum(self, p): |
| 263 """enum : ENUM NAME LCURLY enum_fields RCURLY SEMICOLON""" | 163 """enum : ENUM NAME LBRACE enum_fields RBRACE SEMI""" |
| 264 p[0] = ('ENUM', p[2], p[4]) | 164 p[0] = ('ENUM', p[2], p[4]) |
| 265 | 165 |
| 266 def p_enum_fields(self, p): | 166 def p_enum_fields(self, p): |
| 267 """enum_fields : enum_field | 167 """enum_fields : enum_field |
| 268 | enum_field COMMA enum_fields | 168 | enum_field COMMA enum_fields |
| 269 |""" | 169 |""" |
| 270 if len(p) == 2: | 170 if len(p) == 2: |
| 271 p[0] = ListFromConcat(p[1]) | 171 p[0] = ListFromConcat(p[1]) |
| 272 elif len(p) > 3: | 172 elif len(p) > 3: |
| 273 p[0] = ListFromConcat(p[1], p[3]) | 173 p[0] = ListFromConcat(p[1], p[3]) |
| 274 | 174 |
| 275 def p_enum_field(self, p): | 175 def p_enum_field(self, p): |
| 276 """enum_field : NAME | 176 """enum_field : NAME |
| 277 | NAME EQUALS NUMBER""" | 177 | NAME EQUALS expression""" |
| 278 if len(p) == 2: | 178 if len(p) == 2: |
| 279 p[0] = ('ENUM_FIELD', p[1], None) | 179 p[0] = ('ENUM_FIELD', p[1], None) |
| 280 else: | 180 else: |
| 281 p[0] = ('ENUM_FIELD', p[1], p[3]) | 181 p[0] = ('ENUM_FIELD', p[1], p[3]) |
| 282 | 182 |
| 183 ### Expressions ### | |
| 184 | |
| 185 def p_expression(self, p): | |
| 186 """expression : conditional_expression""" | |
| 187 p[0] = p[1] | |
| 188 | |
| 189 def p_conditional_expression(self, p): | |
| 190 """conditional_expression : binary_expression | |
| 191 | binary_expression CONDOP expression COLON condit ional_expression""" | |
| 192 # Just pass the arguments through. I don't think it's possible to preserve | |
| 193 # the spaces of the original, so just put a single space between them. | |
| 194 p[0] = ' '.join(p[1:]) | |
| 195 | |
| 196 # PLY lets us specify precedence of operators, but since we don't actually | |
|
darin (slow to review)
2014/01/10 00:36:34
Perhaps we should evaluate these expressions here?
| |
| 197 # evaluate them, we don't need that here. | |
| 198 def p_binary_expression(self, p): | |
| 199 """binary_expression : unary_expression | |
| 200 | binary_expression binary_operator binary_expression"" " | |
| 201 p[0] = ' '.join(p[1:]) | |
| 202 | |
| 203 def p_binary_operator(self, p): | |
| 204 """binary_operator : TIMES | |
| 205 | DIVIDE | |
| 206 | MOD | |
| 207 | PLUS | |
| 208 | MINUS | |
| 209 | RSHIFT | |
| 210 | LSHIFT | |
| 211 | LT | |
| 212 | LE | |
| 213 | GE | |
| 214 | GT | |
| 215 | EQ | |
| 216 | NE | |
| 217 | AND | |
| 218 | OR | |
| 219 | XOR | |
| 220 | LAND | |
| 221 | LOR""" | |
| 222 p[0] = p[1] | |
| 223 | |
| 224 def p_unary_expression(self, p): | |
| 225 """unary_expression : primary_expression | |
| 226 | unary_operator expression""" | |
| 227 p[0] = ''.join(p[1:]) | |
| 228 | |
| 229 def p_unary_operator(self, p): | |
| 230 """unary_operator : TIMES | |
| 231 | PLUS | |
| 232 | MINUS | |
| 233 | NOT | |
| 234 | LNOT""" | |
| 235 p[0] = p[1] | |
| 236 | |
| 237 def p_primary_expression(self, p): | |
| 238 """primary_expression : constant | |
| 239 | NAME | |
| 240 | LPAREN expression RPAREN""" | |
| 241 p[0] = ''.join(p[1:]) | |
| 242 | |
| 243 def p_constant(self, p): | |
| 244 """constant : INT_CONST_DEC | |
| 245 | INT_CONST_OCT | |
| 246 | INT_CONST_HEX | |
| 247 | FLOAT_CONST | |
| 248 | HEX_FLOAT_CONST | |
| 249 | CHAR_CONST | |
| 250 | WCHAR_CONST | |
| 251 | STRING_LITERAL | |
| 252 | WSTRING_LITERAL""" | |
| 253 p[0] = ''.join(p[1:]) | |
| 254 | |
| 283 def p_error(self, e): | 255 def p_error(self, e): |
| 284 print('error: %s'%e) | 256 print('error: %s'%e) |
| 285 | 257 |
| 286 | 258 |
| 287 def Parse(filename): | 259 def Parse(filename): |
| 288 lexer = Lexer() | 260 lexer = Lexer() |
| 289 parser = Parser(lexer) | 261 parser = Parser(lexer) |
| 290 | 262 |
| 291 lex.lex(object=lexer) | 263 lex.lex(object=lexer) |
| 292 yacc.yacc(module=parser, debug=0, write_tables=0) | 264 yacc.yacc(module=parser, debug=0, write_tables=0) |
| 293 | 265 |
| 294 tree = yacc.parse(open(filename).read()) | 266 tree = yacc.parse(open(filename).read()) |
| 295 return tree | 267 return tree |
| 296 | 268 |
| 297 | 269 |
| 298 def Main(): | 270 def Main(): |
| 299 if len(sys.argv) < 2: | 271 if len(sys.argv) < 2: |
| 300 print("usage: %s filename" % (sys.argv[0])) | 272 print("usage: %s filename" % (sys.argv[0])) |
| 301 sys.exit(1) | 273 sys.exit(1) |
| 302 tree = Parse(filename=sys.argv[1]) | 274 tree = Parse(filename=sys.argv[1]) |
| 303 print(tree) | 275 print(tree) |
| 304 | 276 |
| 305 | 277 |
| 306 if __name__ == '__main__': | 278 if __name__ == '__main__': |
| 307 Main() | 279 Main() |
| OLD | NEW |