xref: /aosp_15_r20/external/angle/src/compiler/generate_parser_tools.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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