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', 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'0x[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 return t 71 72def t_error(t): 73 t.type = t.value[0] 74 t.value = t.value[0] 75 t.lexer.skip(1) 76 return t 77 78import ply.lex as lex 79lexer = lex.lex() 80 81class Typename(object): 82 pass 83 84class SimpleTypename(Typename): 85 def __init__(self, name): 86 self.name = name 87 88 def __str__(self): 89 return self.name 90 91class GenericTypename(Typename): 92 def __init__(self, name, arg): 93 self.name = name 94 self.arg = arg 95 96 def __str__(self): 97 return '%s<%s>' % (self.name, self.arg) 98 99class EnumHeader(object): 100 def __init__(self, name, base): 101 self.name = name 102 self.base = base 103 104 def __str__(self): 105 return '%s%s' % (self.name, ' %s' % self.base if self.base else '') 106 107class StructHeader(object): 108 def __init__(self, name): 109 self.name = name 110 111 def __str__(self): 112 return 'struct %s' % self.name 113 114class EnumDecl(object): 115 def __init__(self, header, cases): 116 self.header = header 117 self.cases = cases 118 self.fillInValues() 119 120 def fillInValues(self): 121 # if no cases, we're done 122 if len(self.cases) < 1: return 123 # then, if case 0 has no value, set it to 0 124 if self.cases[0].value is None: 125 self.cases[0].value = EnumValueConstant("0") 126 # then for all other cases... 127 for i in range(1,len(self.cases)): 128 # ...if there's no value 129 if self.cases[i].value is None: 130 # set to previous case + 1 131 self.cases[i].value = EnumValueSuccessor( 132 EnumValueLocalRef(self.cases[i-1].name)) 133 134 def __str__(self): 135 return '%s {\n%s\n}' % (self.header, 136 '\n'.join(str(x) for x in self.cases)) 137 138 def __repr__(self): 139 return self.__str__() 140 141class StructDecl(object): 142 def __init__(self, header, items): 143 self.header = header 144 self.items = items 145 146 def __str__(self): 147 return '%s {\n%s\n}' % (self.header, 148 '\n'.join(str(x) for x in self.items)) 149 150 def __repr__(self): 151 return self.__str__() 152 153class StructElement(object): 154 pass 155 156class StructElementIVar(StructElement): 157 def __init__(self, typename, name): 158 self.typename = typename 159 self.name = name 160 161 def __str__(self): 162 return '%s %s' % (self.typename, self.name) 163 164class StructElementStruct(StructElement): 165 def __init__(self, struct): 166 self.name = struct.header.name 167 self.struct = struct 168 169 def __str__(self): 170 return self.struct.__str__() 171 172class EnumCase(object): 173 def __init__(self, name, value): 174 self.name = name 175 self.value = value 176 177 def __str__(self): 178 return '%s = %s' % (self.name, self.value) 179 180class PackageID(object): 181 def __init__(self, name, version): 182 self.name = name 183 self.version = version 184 185 def __str__(self): 186 return '%s%s' % (self.name, self.version) 187 188class Package(object): 189 def __init__(self, package): 190 self.package = package 191 192 def __str__(self): 193 return 'package %s' % self.package 194 195class Import(object): 196 def __init__(self, package): 197 self.package = package 198 199 def __str__(self): 200 return 'import %s' % self.package 201 202class Header(object): 203 def __init__(self, package, imports): 204 self.package = package 205 self.imports = imports 206 207 def __str__(self): 208 return str(self.package) + "\n" + \ 209 '\n'.join(str(x) for x in self.imports) 210 211class EnumValue(object): 212 def resolve(self, enum, document): 213 pass 214 215class EnumValueConstant(EnumValue): 216 def __init__(self, value): 217 self.value = value 218 219 def __str__(self): 220 return self.value 221 222 def resolve(self, enum, document): 223 if self.value.startswith("0x"): 224 return int(self.value, 16) 225 else: 226 return int(self.value, 10) 227 228class EnumValueSuccessor(EnumValue): 229 def __init__(self, value): 230 self.value = value 231 232 def __str__(self): 233 return '%s + 1' % self.value 234 235 def resolve(self, enum, document): 236 return self.value.resolve(enum, document) + 1 237 238class EnumValueLocalRef(EnumValue): 239 def __init__(self, ref): 240 self.ref = ref 241 242 def __str__(self): 243 return self.ref 244 245 def resolve(self, enum, document): 246 for case in enum.cases: 247 if case.name == self.ref: return case.value.resolve(enum, document) 248 249class EnumValueLShift(EnumValue): 250 def __init__(self, base, offset): 251 self.base = base 252 self.offset = offset 253 254 def __str__(self): 255 return '%s << %s' % (self.base, self.offset) 256 257 def resolve(self, enum, document): 258 base = self.base.resolve(enum, document) 259 offset = self.offset.resolve(enum, document) 260 return base << offset 261 262class EnumValueOr(EnumValue): 263 def __init__(self, param1, param2): 264 self.param1 = param1 265 self.param2 = param2 266 267 def __str__(self): 268 return '%s | %s' % (self.param1, self.param2) 269 270 def resolve(self, enum, document): 271 param1 = self.param1.resolve(enum, document) 272 param2 = self.param2.resolve(enum, document) 273 return param1 | param2 274 275class EnumValueExternRef(EnumValue): 276 def __init__(self, where, ref): 277 self.where = where 278 self.ref = ref 279 280 def __str__(self): 281 return '%s:%s' % (self.where, self.ref) 282 283 def resolve(self, enum, document): 284 enum = document['enums'][self.where] 285 return EnumValueLocalRef(self.ref).resolve(enum, document) 286 287# Error rule for syntax errors 288def p_error(p): 289 print("Syntax error in input: %s" % p) 290 try: 291 while True: 292 print(p.lexer.next().value, end=' ') 293 except: 294 pass 295 296def p_document(t): 297 'document : header type_decls' 298 enums = {} 299 structs = {} 300 for enum in t[2]: 301 if not isinstance(enum, EnumDecl): continue 302 enums[enum.header.name] = enum 303 for struct in t[2]: 304 if not isinstance(struct, StructDecl): continue 305 structs[struct.header.name] = struct 306 t[0] = {'header' : t[1], 'enums' : enums, 'structs' : structs} 307 308def p_type_decls_1(t): 309 'type_decls : type_decl' 310 t[0] = [t[1]] 311def p_type_decls_2(t): 312 'type_decls : type_decls type_decl' 313 t[0] = t[1] + [t[2]] 314 315def p_type_decl_e(t): 316 'type_decl : enum_decl' 317 t[0] = t[1] 318def p_type_decl_s(t): 319 'type_decl : struct_decl' 320 t[0] = t[1] 321 322def p_enum_cases_1(t): 323 'enum_cases : enum_case' 324 t[0] = [t[1]] 325def p_enum_cases_2(t): 326 'enum_cases : enum_cases COMMA enum_case' 327 t[0] = t[1] + [t[3]] 328 329def p_struct_elements_1(t): 330 'struct_elements : struct_element' 331 t[0] = [t[1]] 332def p_struct_elements_2(t): 333 'struct_elements : struct_elements struct_element' 334 t[0] = t[1] + [t[2]] 335 336def p_enum_base_1(t): 337 'enum_base : VERSION COLON COLON IDENTIFIER' 338 t[0] = '%s::%s' % (t[1], t[4]) 339def p_enum_base_2(t): 340 'enum_base : IDENTIFIER' 341 t[0] = t[1] 342 343def p_struct_header(t): 344 'struct_header : struct IDENTIFIER' 345 t[0] = StructHeader(t[2]) 346 347def p_enum_header_1(t): 348 'enum_header : enum IDENTIFIER' 349 t[0] = EnumHeader(t[2], None) 350def p_enum_header_2(t): 351 'enum_header : enum IDENTIFIER COLON enum_base' 352 t[0] = EnumHeader(t[2], t[4]) 353 354def p_struct_decl(t): 355 'struct_decl : struct_header LBRACE struct_elements RBRACE SEMICOLON' 356 t[0] = StructDecl(t[1], t[3]) 357 358def p_enum_decl_1(t): 359 'enum_decl : enum_header LBRACE enum_cases RBRACE SEMICOLON' 360 t[0] = EnumDecl(t[1], t[3]) 361def p_enum_decl_2(t): 362 'enum_decl : enum_header LBRACE enum_cases COMMA RBRACE SEMICOLON' 363 t[0] = EnumDecl(t[1], t[3]) 364 365def p_enum_value_1(t): 366 '''enum_value : NUMBER 367 | HEX''' 368 t[0] = EnumValueConstant(t[1]) 369def p_enum_value_2(t): 370 'enum_value : enum_value SHIFT NUMBER' 371 t[0] = EnumValueLShift(t[1], EnumValueConstant(t[3])) 372def p_enum_value_3(t): 373 'enum_value : enum_value OR enum_value' 374 t[0] = EnumValueOr(t[1], t[3]) 375def p_enum_value_4(t): 376 'enum_value : LPAREN enum_value RPAREN' 377 t[0] = t[2] 378def p_enum_value_5(t): 379 'enum_value : IDENTIFIER COLON IDENTIFIER' 380 t[0] = EnumValueExternRef(t[1],t[3]) 381def p_enum_value_6(t): 382 'enum_value : IDENTIFIER' 383 t[0] = EnumValueLocalRef(t[1]) 384 385def p_typename_v(t): 386 'typename : IDENTIFIER' 387 t[0] = SimpleTypename(t[1]) 388def p_typename_g(t): 389 'typename : IDENTIFIER LESSTHAN IDENTIFIER GREATERTHAN' 390 t[0] = GenericTypename(t[1], t[3]) 391 392def p_struct_element_ivar(t): 393 'struct_element : typename IDENTIFIER SEMICOLON' 394 t[0] = StructElementIVar(t[1], t[2]) 395 396def p_struct_element_struct(t): 397 'struct_element : struct_decl' 398 t[0] = StructElementStruct(t[1]) 399 400def p_enum_case_v(t): 401 'enum_case : IDENTIFIER EQUALS enum_value' 402 t[0] = EnumCase(t[1], t[3]) 403def p_enum_case_b(t): 404 'enum_case : IDENTIFIER' 405 t[0] = EnumCase(t[1], None) 406 407def p_header_1(t): 408 'header : package_decl' 409 t[0] = Header(t[1], []) 410 411def p_header_2(t): 412 'header : package_decl import_decls' 413 t[0] = Header(t[1], t[2]) 414 415def p_import_decls_1(t): 416 'import_decls : import_decl' 417 t[0] = [t[1]] 418 419def p_import_decls_2(t): 420 'import_decls : import_decls import_decl' 421 t[0] = t[1] + [t[2]] 422 423def p_package_decl(t): 424 'package_decl : package package_ID SEMICOLON' 425 t[0] = Package(t[2]) 426 427def p_import_decl(t): 428 'import_decl : import package_ID SEMICOLON' 429 t[0] = Import(t[2]) 430 431def p_package_ID(t): 432 'package_ID : dotted_identifier VERSION' 433 t[0] = PackageID(t[1], t[2]) 434 435def p_dotted_identifier_1(t): 436 'dotted_identifier : IDENTIFIER' 437 t[0] = t[1] 438def p_dotted_identifier_2(t): 439 'dotted_identifier : dotted_identifier DOT IDENTIFIER' 440 t[0] = t[1] + '.' + t[3] 441 442class SilentLogger(object): 443 def warning(*args): 444 pass 445 446import ply.yacc as yacc 447parser = yacc.yacc(debug=False, write_tables=False, errorlog=SilentLogger()) 448import sys 449 450def parse(filename): 451 return parser.parse(open(filename, 'r').read()) 452