blob: 0990e26d6dafae823f76a3b8f4325fbe30bb066e [file] [log] [blame]
#!/usr/bin/python
# Copyright 2019 The ANGLE Project Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# generate_parser_tools.py:
# Common functionality to call flex and bison to generate lexer and parser of
# the translator and preprocessor.
import os
import platform
import subprocess
import sys
is_linux = platform.system() == 'Linux'
is_windows = platform.system() == 'Windows'
def get_tool_path_platform(tool_name, platform):
exe_path = os.path.join(sys.path[0], '..', '..', '..', 'tools', 'flex-bison', platform)
return os.path.join(exe_path, tool_name)
def get_tool_path(tool_name):
if is_linux:
platform = 'linux'
ext = ''
else:
assert (is_windows)
platform = 'windows'
ext = '.exe'
return get_tool_path_platform(tool_name + ext, platform)
def get_tool_file_sha1s():
files = [
get_tool_path_platform('flex', 'linux'),
get_tool_path_platform('bison', 'linux'),
get_tool_path_platform('flex.exe', 'windows'),
get_tool_path_platform('bison.exe', 'windows'),
get_tool_path_platform('m4.exe', 'windows')
]
files += [
get_tool_path_platform(dll, 'windows')
for dll in ['msys-2.0.dll', 'msys-iconv-2.dll', 'msys-intl-8.dll']
]
return [f + '.sha1' for f in files]
def run_flex(basename):
flex = get_tool_path('flex')
input_file = basename + '.l'
output_source = basename + '_lex_autogen.cpp'
flex_args = [flex, '--noline', '--nounistd', '--outfile=' + output_source, input_file]
flex_env = os.environ.copy()
if is_windows:
flex_env['M4'] = get_tool_path_platform('m4.exe', 'windows')
process = subprocess.Popen(flex_args, env=flex_env, cwd=sys.path[0])
process.communicate()
if process.returncode != 0:
return process.returncode
# Patch flex output for 64-bit. The patch is simple enough that we could do a string
# replacement. More importantly, the location of the line of code that needs to be substituted
# can vary based on flex version, and the string substitution will find the correct place
# automatically.
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 );"""
patch_out = """
yy_size_t ret = 0;
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
ret, num_to_read );
yyg->yy_n_chars = static_cast<int>(ret);"""
with open(output_source, 'r') as flex_output:
output = flex_output.read()
# If flex's output changes such that this line no longer exists, the patch needs to be
# updated, or possibly removed.
assert (output.find(patch_in) != -1)
patched = output.replace(patch_in, patch_out)
# Remove all tab characters from output. WebKit does not allow any tab characters in source
# files.
patched = patched.replace('\t', ' ')
with open(output_source, 'w') as flex_output_patched:
flex_output_patched.write(patched)
return 0
def run_bison(basename, generate_header):
bison = get_tool_path('bison')
input_file = basename + '.y'
output_header = basename + '_tab_autogen.h'
output_source = basename + '_tab_autogen.cpp'
bison_args = [bison, '--no-lines', '--skeleton=yacc.c']
if generate_header:
bison_args += ['--defines=' + output_header]
bison_args += ['--output=' + output_source, input_file]
bison_env = os.environ.copy()
bison_env['BISON_PKGDATADIR'] = get_tool_path_platform('', 'third_party')
if is_windows:
bison_env['M4'] = get_tool_path_platform('m4.exe', 'windows')
process = subprocess.Popen(bison_args, env=bison_env, cwd=sys.path[0])
process.communicate()
return process.returncode
def get_input_files(basename):
files = [basename + '.l', basename + '.y']
return [os.path.join(sys.path[0], f) for f in files]
def get_output_files(basename, generate_header):
optional_header = [basename + '_tab_autogen.h'] if generate_header else []
files = [basename + '_lex_autogen.cpp', basename + '_tab_autogen.cpp'] + optional_header
return [os.path.join(sys.path[0], f) for f in files]
def generate_parser(basename, generate_header):
# Handle inputs/outputs for run_code_generation.py's auto_script
if len(sys.argv) > 1:
if sys.argv[1] == 'inputs':
inputs = get_tool_file_sha1s()
inputs += get_input_files(basename)
current_file = __file__
if current_file.endswith('.pyc'):
current_file = current_file[:-1]
inputs += [current_file]
print(','.join(inputs))
if sys.argv[1] == 'outputs':
print(','.join(get_output_files(basename, generate_header)))
return 0
# Call flex and bison to generate the lexer and parser.
flex_result = run_flex(basename)
if flex_result != 0:
print 'Failed to run flex. Error ' + str(flex_result)
return 1
bison_result = run_bison(basename, generate_header)
if bison_result != 0:
print 'Failed to run bison. Error ' + str(bison_result)
return 2
return 0