Edit

kc3-lang/angle/src/compiler/generate_parser_tools.py

Branch :

  • Show log

    Commit

  • Author : Cody Northrop
    Date : 2021-04-16 09:17:29
    Hash : 14f8918c
    Message : Migrate more scripts to python3 Test: python3 scripts/run_code_generation.py Bug: angleproject:5707 Change-Id: I5abae69c1c6bf03cc418f10beaabc80288fa1c94 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2828979 Reviewed-by: Jamie Madill <jmadill@chromium.org> Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Cody Northrop <cnorthrop@google.com>

  • src/compiler/generate_parser_tools.py
  • #!/usr/bin/python3
    # 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 %s' % str(flex_result))
            return 1
    
        bison_result = run_bison(basename, generate_header)
        if bison_result != 0:
            print('Failed to run bison. Error %s' % str(bison_result))
            return 2
    
        return 0