1#!/usr/bin/env python3 2# 3# Copyright (C) 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18# A parser for enum types defined in HIDL. 19# This script can parse HIDL files and generate a parse tree. 20# To use, import and call parse("path/to/file.hal") 21# It will return a Python dictionary with three keys: 22# - header: an instance of Header 23# - enums: a dictionary of EnumDecl objects by name 24# - structs: a dictionary of StructDecl objects by name 25 26# It requires 'ply' (Python Lex/Yacc). 27 28from __future__ import print_function 29 30import ply 31 32tokens = ('package', 'import', 'enum', 'struct', 'typedef', 33 'COLON', 'IDENTIFIER', 'COMMENT', 'NUMBER', 'HEX', 'OR', 'EQUALS', 34 'LPAREN', 'RPAREN', 'LBRACE', 'RBRACE', 'DOT', 'SEMICOLON', 'VERSION', 35 'COMMA', 'SHIFT', 'LESSTHAN', 'GREATERTHAN') 36 37t_COLON = r':' 38t_NUMBER = r'[0-9]+' 39t_HEX = r'0[x|X][0-9A-Fa-f]+' 40t_OR = r'\|' 41t_EQUALS = r'=' 42t_LPAREN = r'\(' 43t_RPAREN = r'\)' 44t_SHIFT = r'<<' 45t_LESSTHAN = r'<' 46t_GREATERTHAN = r'>' 47 48def t_COMMENT(t): 49 r'(/\*(.|\n)*?\*/)|(//.*)' 50 pass 51 52t_LBRACE = r'{' 53t_RBRACE = r'}' 54t_DOT = r'\.' 55t_SEMICOLON = r';' 56t_VERSION = r'@[0-9].[0-9]' 57t_COMMA = r',' 58t_ignore = ' \n\t' 59 60def t_IDENTIFIER(t): 61 r'[a-zA-Z_][a-zA-Z_0-9]*' 62 if t.value == 'package': 63 t.type = 'package' 64 elif t.value == 'import': 65 t.type = 'import' 66 elif t.value == 'enum': 67 t.type = 'enum' 68 elif t.value == 'struct': 69 t.type = 'struct' 70 elif t.value == 'typedef': 71 t.type = 'typedef' 72 return t 73 74def t_error(t): 75 t.type = t.value[0] 76 t.value = t.value[0] 77 t.lexer.skip(1) 78 return t 79 80import ply.lex as lex 81lexer = lex.lex() 82 83class Typename(object): 84 pass 85 86class SimpleTypename(Typename): 87 def __init__(self, name): 88 self.name = name 89 90 def __str__(self): 91 return self.name 92 93class GenericTypename(Typename): 94 def __init__(self, name, arg): 95 self.name = name 96 self.arg = arg 97 98 def __str__(self): 99 return '%s<%s>' % (self.name, self.arg) 100 101class EnumHeader(object): 102 def __init__(self, name, base): 103 self.name = name 104 self.base = base 105 106 def __str__(self): 107 return '%s%s' % (self.name, ' %s' % self.base if self.base else '') 108 109class StructHeader(object): 110 def __init__(self, name): 111 self.name = name 112 113 def __str__(self): 114 return 'struct %s' % self.name 115 116class TypedefHeader(object): 117 def __init__(self, name): 118 self.name = name 119 120 def __str__(self): 121 return 'typedef %s' % self.name 122 123class EnumDecl(object): 124 def __init__(self, header, cases): 125 self.header = header 126 self.cases = cases 127 self.fillInValues() 128 129 def fillInValues(self): 130 # if no cases, we're done 131 if len(self.cases) < 1: return 132 # then, if case 0 has no value, set it to 0 133 if self.cases[0].value is None: 134 self.cases[0].value = EnumValueConstant("0") 135 # then for all other cases... 136 for i in range(1,len(self.cases)): 137 # ...if there's no value 138 if self.cases[i].value is None: 139 # set to previous case + 1 140 self.cases[i].value = EnumValueSuccessor( 141 EnumValueLocalRef(self.cases[i-1].name)) 142 143 def __str__(self): 144 return '%s {\n%s\n}' % (self.header, 145 '\n'.join(str(x) for x in self.cases)) 146 147 def __repr__(self): 148 return self.__str__() 149 150class StructDecl(object): 151 def __init__(self, header, items): 152 self.header = header 153 self.items = items 154 155 def __str__(self): 156 return '%s {\n%s\n}' % (self.header, 157 '\n'.join(str(x) for x in self.items)) 158 159 def __repr__(self): 160 return self.__str__() 161 162class TypedefDecl(object): 163 def __init__(self, header, name): 164 self.header = header 165 self.name = name 166 167 def __str__(self): 168 return '%s {\n%s\n}' % (self.header, 169 self.name) 170 171 def __repr__(self): 172 return self.__str__() 173 174class StructElement(object): 175 pass 176 177class StructElementIVar(StructElement): 178 def __init__(self, typename, name): 179 self.typename = typename 180 self.name = name 181 182 def __str__(self): 183 return '%s %s' % (self.typename, self.name) 184 185class StructElementStruct(StructElement): 186 def __init__(self, struct): 187 self.name = struct.header.name 188 self.struct = struct 189 190 def __str__(self): 191 return self.struct.__str__() 192 193class EnumCase(object): 194 def __init__(self, name, value): 195 self.name = name 196 self.value = value 197 198 def __str__(self): 199 return '%s = %s' % (self.name, self.value) 200 201class PackageID(object): 202 def __init__(self, name, version): 203 self.name = name 204 self.version = version 205 206 def __str__(self): 207 return '%s%s' % (self.name, self.version) 208 209class Package(object): 210 def __init__(self, package): 211 self.package = package 212 213 def __str__(self): 214 return 'package %s' % self.package 215 216class Import(object): 217 def __init__(self, package): 218 self.package = package 219 220 def __str__(self): 221 return 'import %s' % self.package 222 223class Header(object): 224 def __init__(self, package, imports): 225 self.package = package 226 self.imports = imports 227 228 def __str__(self): 229 return str(self.package) + "\n" + \ 230 '\n'.join(str(x) for x in self.imports) 231 232class EnumValue(object): 233 def resolve(self, enum, document): 234 pass 235 236class EnumValueConstant(EnumValue): 237 def __init__(self, value): 238 self.value = value 239 240 def __str__(self): 241 return self.value 242 243 def resolve(self, enum, document): 244 if self.value.lower().startswith("0x"): 245 return int(self.value, 16) 246 else: 247 return int(self.value, 10) 248 249class EnumValueSuccessor(EnumValue): 250 def __init__(self, value): 251 self.value = value 252 253 def __str__(self): 254 return '%s + 1' % self.value 255 256 def resolve(self, enum, document): 257 return self.value.resolve(enum, document) + 1 258 259class EnumValueLocalRef(EnumValue): 260 def __init__(self, ref): 261 self.ref = ref 262 263 def __str__(self): 264 return self.ref 265 266 def resolve(self, enum, document): 267 for case in enum.cases: 268 if case.name == self.ref: return case.value.resolve(enum, document) 269 270class EnumValueLShift(EnumValue): 271 def __init__(self, base, offset): 272 self.base = base 273 self.offset = offset 274 275 def __str__(self): 276 return '%s << %s' % (self.base, self.offset) 277 278 def resolve(self, enum, document): 279 base = self.base.resolve(enum, document) 280 offset = self.offset.resolve(enum, document) 281 return base << offset 282 283class EnumValueOr(EnumValue): 284 def __init__(self, param1, param2): 285 self.param1 = param1 286 self.param2 = param2 287 288 def __str__(self): 289 return '%s | %s' % (self.param1, self.param2) 290 291 def resolve(self, enum, document): 292 param1 = self.param1.resolve(enum, document) 293 param2 = self.param2.resolve(enum, document) 294 return param1 | param2 295 296class EnumValueExternRef(EnumValue): 297 def __init__(self, where, ref): 298 self.where = where 299 self.ref = ref 300 301 def __str__(self): 302 return '%s:%s' % (self.where, self.ref) 303 304 def resolve(self, enum, document): 305 enum = document['enums'][self.where] 306 return EnumValueLocalRef(self.ref).resolve(enum, document) 307 308class Typedef(object): 309 def __init__(self, header, name): 310 self.header = header 311 self.name = name 312 313 def __str__(self): 314 return 'typedef %s %s' % (self.typename, self.name) 315 316# Error rule for syntax errors 317def p_error(p): 318 print("Syntax error in input: %s" % p) 319 try: 320 while True: 321 print(p.lexer.next().value, end=' ') 322 except: 323 pass 324 325def p_document(t): 326 'document : header type_decls' 327 enums = {} 328 structs = {} 329 typedefs = {} 330 for enum in t[2]: 331 if not isinstance(enum, EnumDecl): continue 332 enums[enum.header.name] = enum 333 for struct in t[2]: 334 if not isinstance(struct, StructDecl): continue 335 structs[struct.header.name] = struct 336 for typedef in t[2]: 337 if not isinstance(typedef, TypedefDecl): continue 338 typedefs[typedef.header.name] = typedef 339 340 t[0] = {'header' : t[1], 'enums' : enums, 'structs' : structs, 'typedefs' : typedef} 341 342def p_type_decls_1(t): 343 'type_decls : type_decl' 344 t[0] = [t[1]] 345def p_type_decls_2(t): 346 'type_decls : type_decls type_decl' 347 t[0] = t[1] + [t[2]] 348 349def p_type_decl_e(t): 350 'type_decl : enum_decl' 351 t[0] = t[1] 352def p_type_decl_s(t): 353 'type_decl : struct_decl' 354 t[0] = t[1] 355def p_type_decl_t(t): 356 'type_decl : typedef_decl' 357 t[0] = t[1] 358 359def p_enum_cases_1(t): 360 'enum_cases : enum_case' 361 t[0] = [t[1]] 362def p_enum_cases_2(t): 363 'enum_cases : enum_cases COMMA enum_case' 364 t[0] = t[1] + [t[3]] 365 366def p_struct_elements_1(t): 367 'struct_elements : struct_element' 368 t[0] = [t[1]] 369def p_struct_elements_2(t): 370 'struct_elements : struct_elements struct_element' 371 t[0] = t[1] + [t[2]] 372 373def p_enum_base_1(t): 374 'enum_base : VERSION COLON COLON IDENTIFIER' 375 t[0] = '%s::%s' % (t[1], t[4]) 376def p_enum_base_2(t): 377 'enum_base : IDENTIFIER' 378 t[0] = t[1] 379 380def p_typedef_name(t): 381 'typedef_name : IDENTIFIER' 382 t[0] = t[1] 383 384def p_struct_header(t): 385 'struct_header : struct IDENTIFIER' 386 t[0] = StructHeader(t[2]) 387 388def p_enum_header_1(t): 389 'enum_header : enum IDENTIFIER' 390 t[0] = EnumHeader(t[2], None) 391def p_enum_header_2(t): 392 'enum_header : enum IDENTIFIER COLON enum_base' 393 t[0] = EnumHeader(t[2], t[4]) 394 395def p_typedef_header(t): 396 'typedef_header : typedef IDENTIFIER' 397 t[0] = TypedefHeader(t[2]) 398 399def p_struct_decl(t): 400 'struct_decl : struct_header LBRACE struct_elements RBRACE SEMICOLON' 401 t[0] = StructDecl(t[1], t[3]) 402 403def p_enum_decl_1(t): 404 'enum_decl : enum_header LBRACE enum_cases RBRACE SEMICOLON' 405 t[0] = EnumDecl(t[1], t[3]) 406def p_enum_decl_2(t): 407 'enum_decl : enum_header LBRACE enum_cases COMMA RBRACE SEMICOLON' 408 t[0] = EnumDecl(t[1], t[3]) 409 410def p_typedef_decl(t): 411 'typedef_decl : typedef_header typedef_name SEMICOLON' 412 t[0] = TypedefDecl(t[1], t[2]) 413 414def p_enum_value_1(t): 415 '''enum_value : NUMBER 416 | HEX''' 417 t[0] = EnumValueConstant(t[1]) 418def p_enum_value_2(t): 419 'enum_value : enum_value SHIFT NUMBER' 420 t[0] = EnumValueLShift(t[1], EnumValueConstant(t[3])) 421def p_enum_value_3(t): 422 'enum_value : enum_value OR enum_value' 423 t[0] = EnumValueOr(t[1], t[3]) 424def p_enum_value_4(t): 425 'enum_value : LPAREN enum_value RPAREN' 426 t[0] = t[2] 427def p_enum_value_5(t): 428 'enum_value : IDENTIFIER COLON IDENTIFIER' 429 t[0] = EnumValueExternRef(t[1],t[3]) 430def p_enum_value_6(t): 431 'enum_value : IDENTIFIER' 432 t[0] = EnumValueLocalRef(t[1]) 433 434def p_typename_v(t): 435 'typename : IDENTIFIER' 436 t[0] = SimpleTypename(t[1]) 437def p_typename_g(t): 438 'typename : IDENTIFIER LESSTHAN IDENTIFIER GREATERTHAN' 439 t[0] = GenericTypename(t[1], t[3]) 440 441def p_struct_element_ivar(t): 442 'struct_element : typename IDENTIFIER SEMICOLON' 443 t[0] = StructElementIVar(t[1], t[2]) 444 445def p_struct_element_struct(t): 446 'struct_element : struct_decl' 447 t[0] = StructElementStruct(t[1]) 448 449def p_enum_case_v(t): 450 'enum_case : IDENTIFIER EQUALS enum_value' 451 t[0] = EnumCase(t[1], t[3]) 452def p_enum_case_b(t): 453 'enum_case : IDENTIFIER' 454 t[0] = EnumCase(t[1], None) 455 456def p_header_1(t): 457 'header : package_decl' 458 t[0] = Header(t[1], []) 459 460def p_header_2(t): 461 'header : package_decl import_decls' 462 t[0] = Header(t[1], t[2]) 463 464def p_import_decls_1(t): 465 'import_decls : import_decl' 466 t[0] = [t[1]] 467 468def p_import_decls_2(t): 469 'import_decls : import_decls import_decl' 470 t[0] = t[1] + [t[2]] 471 472def p_package_decl(t): 473 'package_decl : package package_ID SEMICOLON' 474 t[0] = Package(t[2]) 475 476def p_import_decl(t): 477 'import_decl : import package_ID SEMICOLON' 478 t[0] = Import(t[2]) 479 480def p_package_ID(t): 481 'package_ID : dotted_identifier VERSION' 482 t[0] = PackageID(t[1], t[2]) 483 484def p_dotted_identifier_1(t): 485 'dotted_identifier : IDENTIFIER' 486 t[0] = t[1] 487def p_dotted_identifier_2(t): 488 'dotted_identifier : dotted_identifier DOT IDENTIFIER' 489 t[0] = t[1] + '.' + t[3] 490 491class SilentLogger(object): 492 def warning(*args): 493 pass 494 def error(*args): 495 print(args) 496 497import ply.yacc as yacc 498parser = yacc.yacc(debug=False, write_tables=False, errorlog=SilentLogger()) 499import sys 500 501def parse(filename): 502 return parser.parse(open(filename, 'r').read()) 503