1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/python3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2019 The ANGLE Project Authors. All rights reserved. 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker# 6*8975f5c5SAndroid Build Coastguard Worker# generate_parser_tools.py: 7*8975f5c5SAndroid Build Coastguard Worker# Common functionality to call flex and bison to generate lexer and parser of 8*8975f5c5SAndroid Build Coastguard Worker# the translator and preprocessor. 9*8975f5c5SAndroid Build Coastguard Worker 10*8975f5c5SAndroid Build Coastguard Workerimport os 11*8975f5c5SAndroid Build Coastguard Workerimport platform 12*8975f5c5SAndroid Build Coastguard Workerimport subprocess 13*8975f5c5SAndroid Build Coastguard Workerimport sys 14*8975f5c5SAndroid Build Coastguard Worker 15*8975f5c5SAndroid Build Coastguard Workeris_linux = platform.system() == 'Linux' 16*8975f5c5SAndroid Build Coastguard Workeris_mac = platform.system() == 'Darwin' 17*8975f5c5SAndroid Build Coastguard Workeris_windows = platform.system() == 'Windows' 18*8975f5c5SAndroid Build Coastguard Worker 19*8975f5c5SAndroid Build Coastguard Worker 20*8975f5c5SAndroid Build Coastguard Workerdef get_tool_path_platform(tool_name, platform): 21*8975f5c5SAndroid Build Coastguard Worker exe_path = os.path.join(sys.path[0], '..', '..', '..', 'tools', 'flex-bison', platform) 22*8975f5c5SAndroid Build Coastguard Worker 23*8975f5c5SAndroid Build Coastguard Worker return os.path.join(exe_path, tool_name) 24*8975f5c5SAndroid Build Coastguard Worker 25*8975f5c5SAndroid Build Coastguard Worker 26*8975f5c5SAndroid Build Coastguard Workerdef get_tool_path(tool_name): 27*8975f5c5SAndroid Build Coastguard Worker if is_linux: 28*8975f5c5SAndroid Build Coastguard Worker platform = 'linux' 29*8975f5c5SAndroid Build Coastguard Worker ext = '' 30*8975f5c5SAndroid Build Coastguard Worker elif is_mac: 31*8975f5c5SAndroid Build Coastguard Worker platform = 'mac' 32*8975f5c5SAndroid Build Coastguard Worker ext = '' 33*8975f5c5SAndroid Build Coastguard Worker else: 34*8975f5c5SAndroid Build Coastguard Worker assert (is_windows) 35*8975f5c5SAndroid Build Coastguard Worker platform = 'windows' 36*8975f5c5SAndroid Build Coastguard Worker ext = '.exe' 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker return get_tool_path_platform(tool_name + ext, platform) 39*8975f5c5SAndroid Build Coastguard Worker 40*8975f5c5SAndroid Build Coastguard Worker 41*8975f5c5SAndroid Build Coastguard Workerdef get_tool_file_sha1s(): 42*8975f5c5SAndroid Build Coastguard Worker files = [ 43*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('flex', 'linux'), 44*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('bison', 'linux'), 45*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('flex.exe', 'windows'), 46*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('bison.exe', 'windows'), 47*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('m4.exe', 'windows'), 48*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('flex', 'mac'), 49*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform('bison', 'mac'), 50*8975f5c5SAndroid Build Coastguard Worker ] 51*8975f5c5SAndroid Build Coastguard Worker 52*8975f5c5SAndroid Build Coastguard Worker files += [ 53*8975f5c5SAndroid Build Coastguard Worker get_tool_path_platform(dll, 'windows') 54*8975f5c5SAndroid Build Coastguard Worker for dll in ['msys-2.0.dll', 'msys-iconv-2.dll', 'msys-intl-8.dll'] 55*8975f5c5SAndroid Build Coastguard Worker ] 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Worker return [f + '.sha1' for f in files] 58*8975f5c5SAndroid Build Coastguard Worker 59*8975f5c5SAndroid Build Coastguard Worker 60*8975f5c5SAndroid Build Coastguard Workerdef run_flex(basename): 61*8975f5c5SAndroid Build Coastguard Worker flex = get_tool_path('flex') 62*8975f5c5SAndroid Build Coastguard Worker input_file = basename + '.l' 63*8975f5c5SAndroid Build Coastguard Worker output_source = basename + '_lex_autogen.cpp' 64*8975f5c5SAndroid Build Coastguard Worker 65*8975f5c5SAndroid Build Coastguard Worker flex_args = [flex, '--noline', '--nounistd', '--outfile=' + output_source, input_file] 66*8975f5c5SAndroid Build Coastguard Worker 67*8975f5c5SAndroid Build Coastguard Worker flex_env = os.environ.copy() 68*8975f5c5SAndroid Build Coastguard Worker if is_windows: 69*8975f5c5SAndroid Build Coastguard Worker flex_env['M4'] = get_tool_path_platform('m4.exe', 'windows') 70*8975f5c5SAndroid Build Coastguard Worker 71*8975f5c5SAndroid Build Coastguard Worker process = subprocess.Popen(flex_args, env=flex_env, cwd=sys.path[0]) 72*8975f5c5SAndroid Build Coastguard Worker process.communicate() 73*8975f5c5SAndroid Build Coastguard Worker if process.returncode != 0: 74*8975f5c5SAndroid Build Coastguard Worker return process.returncode 75*8975f5c5SAndroid Build Coastguard Worker 76*8975f5c5SAndroid Build Coastguard Worker # Patch flex output for 64-bit. The patch is simple enough that we could do a string 77*8975f5c5SAndroid Build Coastguard Worker # replacement. More importantly, the location of the line of code that needs to be substituted 78*8975f5c5SAndroid Build Coastguard Worker # can vary based on flex version, and the string substitution will find the correct place 79*8975f5c5SAndroid Build Coastguard Worker # automatically. 80*8975f5c5SAndroid Build Coastguard Worker 81*8975f5c5SAndroid Build Coastguard Worker patch_in = """\n\t\tYY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),\n\t\t\tyyg->yy_n_chars, num_to_read );""" 82*8975f5c5SAndroid Build Coastguard Worker patch_out = """ 83*8975f5c5SAndroid Build Coastguard Worker yy_size_t ret = 0; 84*8975f5c5SAndroid Build Coastguard Worker YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), 85*8975f5c5SAndroid Build Coastguard Worker ret, num_to_read ); 86*8975f5c5SAndroid Build Coastguard Worker yyg->yy_n_chars = static_cast<int>(ret);""" 87*8975f5c5SAndroid Build Coastguard Worker 88*8975f5c5SAndroid Build Coastguard Worker with open(output_source, 'r') as flex_output: 89*8975f5c5SAndroid Build Coastguard Worker output = flex_output.read() 90*8975f5c5SAndroid Build Coastguard Worker 91*8975f5c5SAndroid Build Coastguard Worker # If flex's output changes such that this line no longer exists, the patch needs to be 92*8975f5c5SAndroid Build Coastguard Worker # updated, or possibly removed. 93*8975f5c5SAndroid Build Coastguard Worker assert (output.find(patch_in) != -1) 94*8975f5c5SAndroid Build Coastguard Worker 95*8975f5c5SAndroid Build Coastguard Worker patched = output.replace(patch_in, patch_out) 96*8975f5c5SAndroid Build Coastguard Worker 97*8975f5c5SAndroid Build Coastguard Worker # Remove all tab characters from output. WebKit does not allow any tab characters in source 98*8975f5c5SAndroid Build Coastguard Worker # files. 99*8975f5c5SAndroid Build Coastguard Worker patched = patched.replace('\t', ' ') 100*8975f5c5SAndroid Build Coastguard Worker 101*8975f5c5SAndroid Build Coastguard Worker with open(output_source, 'w') as flex_output_patched: 102*8975f5c5SAndroid Build Coastguard Worker flex_output_patched.write(patched) 103*8975f5c5SAndroid Build Coastguard Worker 104*8975f5c5SAndroid Build Coastguard Worker return 0 105*8975f5c5SAndroid Build Coastguard Worker 106*8975f5c5SAndroid Build Coastguard Worker 107*8975f5c5SAndroid Build Coastguard Workerdef run_bison(basename, generate_header): 108*8975f5c5SAndroid Build Coastguard Worker bison = get_tool_path('bison') 109*8975f5c5SAndroid Build Coastguard Worker input_file = basename + '.y' 110*8975f5c5SAndroid Build Coastguard Worker output_header = basename + '_tab_autogen.h' 111*8975f5c5SAndroid Build Coastguard Worker output_source = basename + '_tab_autogen.cpp' 112*8975f5c5SAndroid Build Coastguard Worker 113*8975f5c5SAndroid Build Coastguard Worker bison_args = [bison, '--no-lines', '--skeleton=yacc.c'] 114*8975f5c5SAndroid Build Coastguard Worker if generate_header: 115*8975f5c5SAndroid Build Coastguard Worker bison_args += ['--defines=' + output_header] 116*8975f5c5SAndroid Build Coastguard Worker bison_args += ['--output=' + output_source, input_file] 117*8975f5c5SAndroid Build Coastguard Worker 118*8975f5c5SAndroid Build Coastguard Worker bison_env = os.environ.copy() 119*8975f5c5SAndroid Build Coastguard Worker bison_env['BISON_PKGDATADIR'] = get_tool_path_platform('', 'third_party') 120*8975f5c5SAndroid Build Coastguard Worker if is_windows: 121*8975f5c5SAndroid Build Coastguard Worker bison_env['M4'] = get_tool_path_platform('m4.exe', 'windows') 122*8975f5c5SAndroid Build Coastguard Worker 123*8975f5c5SAndroid Build Coastguard Worker process = subprocess.Popen(bison_args, env=bison_env, cwd=sys.path[0]) 124*8975f5c5SAndroid Build Coastguard Worker process.communicate() 125*8975f5c5SAndroid Build Coastguard Worker return process.returncode 126*8975f5c5SAndroid Build Coastguard Worker 127*8975f5c5SAndroid Build Coastguard Worker 128*8975f5c5SAndroid Build Coastguard Workerdef get_input_files(basename): 129*8975f5c5SAndroid Build Coastguard Worker files = [basename + '.l', basename + '.y'] 130*8975f5c5SAndroid Build Coastguard Worker return [os.path.join(sys.path[0], f) for f in files] 131*8975f5c5SAndroid Build Coastguard Worker 132*8975f5c5SAndroid Build Coastguard Worker 133*8975f5c5SAndroid Build Coastguard Workerdef get_output_files(basename, generate_header): 134*8975f5c5SAndroid Build Coastguard Worker optional_header = [basename + '_tab_autogen.h'] if generate_header else [] 135*8975f5c5SAndroid Build Coastguard Worker files = [basename + '_lex_autogen.cpp', basename + '_tab_autogen.cpp'] + optional_header 136*8975f5c5SAndroid Build Coastguard Worker return [os.path.join(sys.path[0], f) for f in files] 137*8975f5c5SAndroid Build Coastguard Worker 138*8975f5c5SAndroid Build Coastguard Worker 139*8975f5c5SAndroid Build Coastguard Workerdef generate_parser(basename, generate_header): 140*8975f5c5SAndroid Build Coastguard Worker # Handle inputs/outputs for run_code_generation.py's auto_script 141*8975f5c5SAndroid Build Coastguard Worker if len(sys.argv) > 1: 142*8975f5c5SAndroid Build Coastguard Worker if sys.argv[1] == 'inputs': 143*8975f5c5SAndroid Build Coastguard Worker inputs = get_tool_file_sha1s() 144*8975f5c5SAndroid Build Coastguard Worker inputs += get_input_files(basename) 145*8975f5c5SAndroid Build Coastguard Worker current_file = __file__ 146*8975f5c5SAndroid Build Coastguard Worker if current_file.endswith('.pyc'): 147*8975f5c5SAndroid Build Coastguard Worker current_file = current_file[:-1] 148*8975f5c5SAndroid Build Coastguard Worker inputs += [current_file] 149*8975f5c5SAndroid Build Coastguard Worker print(','.join(inputs)) 150*8975f5c5SAndroid Build Coastguard Worker if sys.argv[1] == 'outputs': 151*8975f5c5SAndroid Build Coastguard Worker print(','.join(get_output_files(basename, generate_header))) 152*8975f5c5SAndroid Build Coastguard Worker return 0 153*8975f5c5SAndroid Build Coastguard Worker 154*8975f5c5SAndroid Build Coastguard Worker # Call flex and bison to generate the lexer and parser. 155*8975f5c5SAndroid Build Coastguard Worker flex_result = run_flex(basename) 156*8975f5c5SAndroid Build Coastguard Worker if flex_result != 0: 157*8975f5c5SAndroid Build Coastguard Worker print('Failed to run flex. Error %s' % str(flex_result)) 158*8975f5c5SAndroid Build Coastguard Worker return 1 159*8975f5c5SAndroid Build Coastguard Worker 160*8975f5c5SAndroid Build Coastguard Worker bison_result = run_bison(basename, generate_header) 161*8975f5c5SAndroid Build Coastguard Worker if bison_result != 0: 162*8975f5c5SAndroid Build Coastguard Worker print('Failed to run bison. Error %s' % str(bison_result)) 163*8975f5c5SAndroid Build Coastguard Worker return 2 164*8975f5c5SAndroid Build Coastguard Worker 165*8975f5c5SAndroid Build Coastguard Worker return 0 166