1#!/bin/env python 2COPYRIGHT = """\ 3/* 4 * Copyright 2021 Intel Corporation 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sub license, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice (including the 15 * next paragraph) shall be included in all copies or substantial portions 16 * of the Software. 17 * 18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. 21 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR 22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 */ 26""" 27 28import os 29import re 30import ply.lex as lex 31import ply.yacc as yacc 32 33# Libraries 34 35libraries = {} 36 37# LEXER 38 39keywords = { 40 '__debugbreak': 'KW_DEBUGBREAK', 41 'alignas': 'KW_ALIGNAS', 42 'args': 'KW_ARGS', 43 'atomic': 'KW_ATOMIC', 44 'atomic_return': 'KW_ATOMIC_RETURN', 45 'const': 'KW_CONST', 46 'control': 'KW_CONTROL', 47 'define': 'KW_DEFINE', 48 'dispatch': 'KW_DISPATCH', 49 'dispatch_indirect': 'KW_DISPATCH_INDIRECT', 50 'goto': 'KW_GOTO', 51 'if': 'KW_IF', 52 'kernel': 'KW_KERNEL', 53 'kernel_module': 'KW_KERNEL_MODULE', 54 'import': 'KW_IMPORT', 55 'library': 'KW_LIBRARY', 56 'links': 'KW_LINKS', 57 'load_dword': 'KW_LOAD_DWORD', 58 'load_qword': 'KW_LOAD_QWORD', 59 'metakernel': 'KW_METAKERNEL', 60 'module': 'KW_MODULE', 61 'not': 'KW_NOT', 62 'offsetof': 'KW_OFFSETOF', 63 'postsync': 'KW_POSTSYNC', 64 'print': 'KW_PRINT', 65 'semaphore_wait': 'KW_SEMAPHORE_WAIT', 66 'shiftof': 'KW_SHIFTOF', 67 'sizeof': 'KW_SIZEOF', 68 'store_dword': 'KW_STORE_DWORD', 69 'store_qword': 'KW_STORE_QWORD', 70 'store_timestamp': 'KW_STORE_TIMESTAMP', 71 'struct': 'KW_STRUCT', 72 'unsigned': 'KW_UNSIGNED', 73 'while': 'KW_WHILE' 74} 75 76ops = { 77 '&&': 'OP_LOGICAL_AND', 78 '||': 'OP_LOGICAL_OR', 79 '==': 'OP_EQUALEQUAL', 80 '!=': 'OP_NOTEQUAL', 81 '<=': 'OP_LESSEQUAL', 82 '>=': 'OP_GREATEREQUAL', 83 '<<': 'OP_LSHIFT', 84 '>>': 'OP_RSHIFT' 85} 86 87tokens = [ 88 'INT_LITERAL', 89 'STRING_LITERAL', 90 'OP', 91 'IDENTIFIER' 92] + list(keywords.values()) + list(ops.values()) 93 94def t_INT_LITERAL(t): 95 r'(0x[a-fA-F0-9]+|\d+)' 96 if t.value.startswith('0x'): 97 t.value = int(t.value[2:], 16) 98 else: 99 t.value = int(t.value) 100 return t 101 102def t_OP(t): 103 r'(&&|\|\||==|!=|<=|>=|<<|>>)' 104 t.type = ops.get(t.value) 105 return t 106 107def t_IDENTIFIER(t): 108 r'[a-zA-Z_][a-zA-Z_0-9]*' 109 t.type = keywords.get(t.value, 'IDENTIFIER') 110 return t 111 112def t_STRING_LITERAL(t): 113 r'"(\\.|[^"\\])*"' 114 t.value = t.value[1:-1] 115 return t 116 117literals = "+*/(){};:,=&|!~^.%?-<>[]" 118 119t_ignore = ' \t' 120 121def t_newline(t): 122 r'\n+' 123 t.lexer.lineno += len(t.value) 124 125def t_error(t): 126 print("WUT: {}".format(t.value)) 127 t.lexer.skip(1) 128 129LEXER = lex.lex() 130 131# PARSER 132 133precedence = ( 134 ('right', '?', ':'), 135 ('left', 'OP_LOGICAL_OR', 'OP_LOGICAL_AND'), 136 ('left', '|'), 137 ('left', '^'), 138 ('left', '&'), 139 ('left', 'OP_EQUALEQUAL', 'OP_NOTEQUAL'), 140 ('left', '<', '>', 'OP_LESSEQUAL', 'OP_GREATEREQUAL'), 141 ('left', 'OP_LSHIFT', 'OP_RSHIFT'), 142 ('left', '+', '-'), 143 ('left', '*', '/', '%'), 144 ('right', '!', '~'), 145 ('left', '[', ']', '.') 146) 147 148def p_module(p): 149 'module : element_list' 150 p[0] = p[1] 151 152def p_element_list(p): 153 '''element_list : element_list element 154 | element''' 155 if len(p) == 2: 156 p[0] = [p[1]] 157 else: 158 p[0] = p[1] + [p[2]] 159 160def p_element(p): 161 '''element : kernel_definition 162 | kernel_module_definition 163 | library_definition 164 | metakernel_definition 165 | module_name 166 | struct_definition 167 | const_definition 168 | import_definition''' 169 p[0] = p[1] 170 171def p_module_name(p): 172 'module_name : KW_MODULE IDENTIFIER ";"' 173 p[0] = ('module-name', p[2]) 174 175def p_kernel_module_definition(p): 176 'kernel_module_definition : KW_KERNEL_MODULE IDENTIFIER "(" STRING_LITERAL ")" "{" kernel_definition_list "}"' 177 p[0] = ('kernel-module', p[2], p[4], p[7]) 178 179def p_kernel_definition(p): 180 'kernel_definition : KW_KERNEL IDENTIFIER optional_annotation_list' 181 p[0] = ('kernel', p[2], p[3]) 182 183def p_library_definition(p): 184 'library_definition : KW_LIBRARY IDENTIFIER "{" library_definition_list "}"' 185 p[0] = ('library', p[2], p[4]) 186 187def p_library_definition_list(p): 188 '''library_definition_list : 189 | library_definition_list IDENTIFIER STRING_LITERAL ";"''' 190 if len(p) < 3: 191 p[0] = [] 192 else: 193 p[0] = p[1] 194 p[0].append((p[2], p[3])) 195 196def p_import_definition(p): 197 'import_definition : KW_IMPORT KW_STRUCT IDENTIFIER STRING_LITERAL ";"' 198 p[0] = ('import', p[4], 'struct', p[3]) 199 200def p_links_definition(p): 201 'links_definition : KW_LINKS IDENTIFIER' 202 203 # Process a library include like a preprocessor 204 global libraries 205 206 if not p[2] in libraries: 207 raise "Not able to find library {0}".format(p[2]) 208 p[0] = libraries[p[2]] 209 210def p_metakernel_definition(p): 211 'metakernel_definition : KW_METAKERNEL IDENTIFIER "(" optional_parameter_list ")" optional_annotation_list scope' 212 p[0] = ('meta-kernel', p[2], p[4], p[6], p[7]) 213 214def p_kernel_definition_list(p): 215 '''kernel_definition_list : 216 | kernel_definition_list kernel_definition ";" 217 | kernel_definition_list links_definition ";"''' 218 if len(p) < 3: 219 p[0] = [] 220 else: 221 p[0] = p[1] 222 p[0].append(p[2]) 223 224def p_optional_annotation_list(p): 225 '''optional_annotation_list : 226 | "<" ">" 227 | "<" annotation_list ">"''' 228 if len(p) < 4: 229 p[0] = {} 230 else: 231 p[0] = p[2] 232 233def p_optional_parameter_list(p): 234 '''optional_parameter_list : 235 | parameter_list''' 236 p[0] = p[1] 237 238def p_annotation_list(p): 239 '''annotation_list : annotation''' 240 p[0] = p[1] 241 242def p_annotation_list_append(p): 243 '''annotation_list : annotation_list "," annotation''' 244 p[0] = {**p[1], **p[3]} 245 246def p_annotation(p): 247 '''annotation : IDENTIFIER "=" INT_LITERAL 248 | IDENTIFIER "=" IDENTIFIER 249 | IDENTIFIER "=" STRING_LITERAL''' 250 p[0] = {p[1]: p[3]} 251 252def p_parameter_list(p): 253 '''parameter_list : parameter_definition''' 254 p[0] = [p[1]] 255 256def p_parameter_list_append(p): 257 '''parameter_list : parameter_list "," parameter_definition''' 258 p[0] = p[1] 259 p[0].append(p[3]) 260 261def p_parameter_definition(p): 262 'parameter_definition : IDENTIFIER IDENTIFIER' 263 p[0] = (p[1], p[2]) 264 265def p_scope(p): 266 '''scope : "{" optional_statement_list "}"''' 267 p[0] = p[2] 268 269def p_optional_statement_list(p): 270 '''optional_statement_list : 271 | statement_list''' 272 p[0] = p[1] 273 274def p_statement_list(p): 275 '''statement_list : statement''' 276 p[0] = [p[1]] 277 278def p_statement_list_append(p): 279 '''statement_list : statement_list statement''' 280 p[0] = p[1] 281 p[0].append(p[2]) 282 283def p_statement(p): 284 '''statement : definition_statement ";" 285 | assignment_statement ";" 286 | load_store_statement ";" 287 | dispatch_statement ";" 288 | semaphore_statement ";" 289 | label 290 | goto_statement ";" 291 | scope_statement 292 | atomic_op_statement ";" 293 | control_statement ";" 294 | print_statement ";" 295 | debug_break_statement ";"''' 296 p[0] = p[1] 297 298def p_definition_statement(p): 299 'definition_statement : KW_DEFINE IDENTIFIER value' 300 p[0] = ('define', p[2], p[3]) 301 302def p_assignemt_statement(p): 303 'assignment_statement : value "=" value' 304 p[0] = ('assign', p[1], p[3]) 305 306def p_load_store_statement_load_dword(p): 307 '''load_store_statement : value "=" KW_LOAD_DWORD "(" value ")"''' 308 p[0] = ('load-dword', p[1], p[5]) 309 310def p_load_store_statement_load_qword(p): 311 '''load_store_statement : value "=" KW_LOAD_QWORD "(" value ")"''' 312 p[0] = ('load-qword', p[1], p[5]) 313 314def p_load_store_statement_store_dword(p): 315 '''load_store_statement : KW_STORE_DWORD "(" value "," value ")"''' 316 p[0] = ('store-dword', p[3], p[5]) 317 318def p_load_store_statement_store_qword(p): 319 '''load_store_statement : KW_STORE_QWORD "(" value "," value ")"''' 320 p[0] = ('store-qword', p[3], p[5]) 321 322def p_dispatch_statement(p): 323 '''dispatch_statement : direct_dispatch_statement 324 | indirect_dispatch_statement''' 325 p[0] = p[1] 326 327def p_direct_dispatch_statement(p): 328 '''direct_dispatch_statement : KW_DISPATCH IDENTIFIER "(" value "," value "," value ")" optional_kernel_arg_list optional_postsync''' 329 p[0] = ('dispatch', p[2], (p[4], p[6], p[8]), p[10], p[11]) 330 331def p_indirect_dispatch_statement(p): 332 '''indirect_dispatch_statement : KW_DISPATCH_INDIRECT IDENTIFIER optional_kernel_arg_list optional_postsync''' 333 p[0] = ('dispatch', p[2], None, p[3], p[4]) 334 335def p_optional_kernel_arg_list(p): 336 '''optional_kernel_arg_list : 337 | KW_ARGS "(" value_list ")"''' 338 p[0] = p[3] 339 340def p_value_list(p): 341 '''value_list : value''' 342 p[0] = [p[1]] 343 344def p_value_list_append(p): 345 '''value_list : value_list "," value''' 346 p[0] = p[1] 347 p[0].append(p[3]) 348 349def p_optional_postsync(p): 350 '''optional_postsync : 351 | postsync_operation''' 352 if len(p) > 1: 353 p[0] = p[1] 354 355def p_postsync_operation(p): 356 '''postsync_operation : postsync_write_dword 357 | postsync_write_timestamp''' 358 p[0] = p[1] 359 360def p_postsync_write_dword(p): 361 '''postsync_write_dword : KW_POSTSYNC KW_STORE_DWORD "(" value "," value ")"''' 362 p[0] = ('postsync', 'store-dword', p[4], p[6]) 363 364def p_postsync_write_timestamp(p): 365 '''postsync_write_timestamp : KW_POSTSYNC KW_STORE_TIMESTAMP "(" value ")"''' 366 p[0] = ('postsync', 'timestamp', p[4]) 367 368def p_semaphore_statement(p): 369 '''semaphore_statement : KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value "<" value ")" 370 | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value ">" value ")" 371 | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_LESSEQUAL value ")" 372 | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_GREATEREQUAL value ")" 373 | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_EQUALEQUAL value ")" 374 | KW_SEMAPHORE_WAIT KW_WHILE "(" "*" value OP_NOTEQUAL value ")"''' 375 p[0] = ('sem-wait-while', p[5], p[6], p[7]) 376 377def p_atomic_op_statement(p): 378 '''atomic_op_statement : KW_ATOMIC IDENTIFIER IDENTIFIER "(" value_list ")"''' 379 p[0] = ('atomic', p[2], p[3], p[5]) 380 381def p_atomic_op_statement_return(p): 382 '''atomic_op_statement : KW_ATOMIC_RETURN IDENTIFIER IDENTIFIER "(" value_list ")"''' 383 p[0] = ('atomic-return', p[2], p[3], p[5]) 384 385def p_label(p): 386 '''label : IDENTIFIER ":"''' 387 p[0] = ('label', p[1]) 388 389def p_goto_statement(p): 390 '''goto_statement : KW_GOTO IDENTIFIER''' 391 p[0] = ('goto', p[2]) 392 393def p_goto_statement_if(p): 394 '''goto_statement : KW_GOTO IDENTIFIER KW_IF "(" value ")"''' 395 p[0] = ('goto-if', p[2], p[5]) 396 397def p_goto_statement_if_not(p): 398 '''goto_statement : KW_GOTO IDENTIFIER KW_IF KW_NOT "(" value ")"''' 399 p[0] = ('goto-if-not', p[2], p[6]) 400 401def p_scope_statement(p): 402 '''scope_statement : scope''' 403 p[0] = (p[1]) 404 405def p_control_statement(p): 406 '''control_statement : KW_CONTROL "(" id_list ")"''' 407 p[0] = ('control', p[3]) 408 409def p_print_statement(p): 410 '''print_statement : KW_PRINT "(" printable_list ")"''' 411 p[0] = ('print', p[3]) 412 413def p_printable_list(p): 414 '''printable_list : printable''' 415 p[0] = [p[1]] 416 417def p_printable_list_append(p): 418 '''printable_list : printable_list "," printable''' 419 p[0] = p[1] 420 p[0].append(p[3]) 421 422def p_printable_str_lit(p): 423 '''printable : STRING_LITERAL''' 424 p[0] = '"{}"'.format(p[1]) 425 426def p_printable_value(p): 427 '''printable : value''' 428 p[0] = p[1] 429 430def p_printable_str_lit_value(p): 431 '''printable : STRING_LITERAL value''' 432 p[0] = ('"{}"'.format(p[1]), p[2]) 433 434def p_debug_break_statement(p): 435 '''debug_break_statement : KW_DEBUGBREAK''' 436 p[0] = ('debug-break') 437 438def p_id_list(p): 439 '''id_list : IDENTIFIER''' 440 p[0] = p[1] 441 442def p_id_list_append(p): 443 '''id_list : id_list "," IDENTIFIER''' 444 p[0] = p[1] 445 p[0].append(p[3]) 446 447def p_value(p): 448 '''value : IDENTIFIER 449 | INT_LITERAL''' 450 p[0] = p[1] 451 452def p_value_braces(p): 453 '''value : "(" value ")"''' 454 p[0] = (p[2]) 455 456def p_value_member(p): 457 '''value : value "." IDENTIFIER''' 458 p[0] = ('member', p[1], p[3]) 459 460def p_value_idx(p): 461 '''value : value "[" value "]"''' 462 p[0] = ('index', p[1], p[3]) 463 464def p_value_binop(p): 465 '''value : value "+" value 466 | value "-" value 467 | value "*" value 468 | value "/" value 469 | value "%" value 470 | value "&" value 471 | value "|" value 472 | value "<" value 473 | value ">" value 474 | value "^" value 475 | value OP_LESSEQUAL value 476 | value OP_GREATEREQUAL value 477 | value OP_EQUALEQUAL value 478 | value OP_NOTEQUAL value 479 | value OP_LOGICAL_AND value 480 | value OP_LOGICAL_OR value 481 | value OP_LSHIFT value 482 | value OP_RSHIFT value''' 483 p[0] = (p[2], p[1], p[3]) 484 485def p_value_uniop(p): 486 '''value : "!" value 487 | "~" value''' 488 p[0] = (p[1], p[2]) 489 490def p_value_cond(p): 491 '''value : value "?" value ":" value''' 492 p[0] = ('?', p[1], p[3], p[5]) 493 494def p_value_funcop(p): 495 '''value : KW_OFFSETOF "(" offset_expression ")" 496 | KW_SHIFTOF "(" IDENTIFIER ")" 497 | KW_SIZEOF "(" IDENTIFIER ")"''' 498 p[0] = (p[1], p[3]) 499 500def p_offset_expression(p): 501 '''offset_expression : IDENTIFIER''' 502 p[0] = p[1] 503 504def p_offset_expression_member(p): 505 '''offset_expression : offset_expression "." IDENTIFIER''' 506 p[0] = ('member', p[1], p[3]) 507 508def p_offset_expression_idx(p): 509 '''offset_expression : offset_expression "[" INT_LITERAL "]"''' 510 p[0] = ('index', p[1], p[3]) 511 512def p_struct_definition(p): 513 '''struct_definition : KW_STRUCT optional_alignment_specifier IDENTIFIER "{" optional_struct_member_list "}" ";"''' 514 p[0] = ('struct', p[3], p[5], p[2]) 515 516def p_optional_alignment_specifier(p): 517 '''optional_alignment_specifier : 518 | KW_ALIGNAS "(" INT_LITERAL ")"''' 519 if len(p) == 1: 520 p[0] = 0 521 else: 522 p[0] = p[3] 523 524def p_optional_struct_member_list(p): 525 '''optional_struct_member_list : 526 | struct_member_list''' 527 if len(p) == 1: 528 p[0] = {} 529 else: 530 p[0] = p[1] 531 532def p_struct_member_list(p): 533 '''struct_member_list : struct_member''' 534 p[0] = [p[1]] 535 536def p_struct_member_list_append(p): 537 '''struct_member_list : struct_member_list struct_member''' 538 p[0] = p[1] + [p[2]] 539 540def p_struct_member(p): 541 '''struct_member : struct_member_typename IDENTIFIER ";"''' 542 p[0] = (p[1], p[2]) 543 544def p_struct_member_array(p): 545 '''struct_member : struct_member_typename IDENTIFIER "[" INT_LITERAL "]" ";"''' 546 '''struct_member : struct_member_typename IDENTIFIER "[" IDENTIFIER "]" ";"''' 547 p[0] = {p[1]: p[2], 'count': p[4]} 548 549def p_struct_member_typename(p): 550 '''struct_member_typename : IDENTIFIER''' 551 p[0] = p[1] 552 553def p_struct_member_typename_unsigned(p): 554 '''struct_member_typename : KW_UNSIGNED IDENTIFIER''' 555 p[0] = ('unsigned', p[2]) 556 557def p_struct_member_typename_struct(p): 558 '''struct_member_typename : KW_STRUCT IDENTIFIER''' 559 p[0] = ('struct', p[2]) 560 561def p_const_definition(p): 562 '''const_definition : KW_CONST IDENTIFIER "=" INT_LITERAL ";"''' 563 p[0] = ('named-constant', p[2], p[4]) 564 565PARSER = yacc.yacc() 566 567# Shamelessly stolen from some StackOverflow answer 568def _remove_comments(text): 569 def replacer(match): 570 s = match.group(0) 571 if s.startswith('/'): 572 return " " # note: a space and not an empty string 573 else: 574 return s 575 pattern = re.compile( 576 r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', 577 re.DOTALL | re.MULTILINE 578 ) 579 return re.sub(pattern, replacer, text) 580 581def parse_grl_file(grl_fname, libs): 582 global libraries 583 584 libraries = libs 585 with open(grl_fname, 'r') as f: 586 return PARSER.parse(_remove_comments(f.read())) 587