99 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
			
		
		
	
	
			99 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable File
		
	
	
| #!/usr/bin/env python3
 | |
| #
 | |
| # Copyright (C) 2016 The Android Open Source Project
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| #      http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| 
 | |
| import sys, re, os
 | |
| from io import StringIO
 | |
| 
 | |
| SCRIPT_DIR = os.path.dirname(sys.argv[0])
 | |
| # This file is included verbatim at the start of the in-memory python script.
 | |
| SCRIPT_SETUP_CODE = SCRIPT_DIR + "/common/gen_setup.py"
 | |
| INTERP_DEFS_FILE = SCRIPT_DIR + "/../../../libdexfile/dex/dex_instruction_list.h"
 | |
| NUM_PACKED_OPCODES = 256
 | |
| 
 | |
| # Extract an ordered list of instructions from the VM sources.  We use the
 | |
| # "goto table" definition macro, which has exactly NUM_PACKED_OPCODES entries.
 | |
| def getOpcodeList():
 | |
|   opcodes = []
 | |
|   opcode_fp = open(INTERP_DEFS_FILE)
 | |
|   opcode_re = re.compile(r"^\s*V\((....), (\w+),.*", re.DOTALL)
 | |
|   for line in opcode_fp:
 | |
|     match = opcode_re.match(line)
 | |
|     if not match:
 | |
|       continue
 | |
|     opcodes.append("op_" + match.group(2).lower())
 | |
|   opcode_fp.close()
 | |
| 
 | |
|   if len(opcodes) != NUM_PACKED_OPCODES:
 | |
|     print("ERROR: found ", len(opcodes), " opcodes in Interp.h (expected ", NUM_PACKED_OPCODES, ")")
 | |
|     raise SyntaxError("bad opcode count")
 | |
|   return opcodes
 | |
| 
 | |
| indent_re = re.compile(r"^%( *)")
 | |
| 
 | |
| # Finds variable references in text: $foo or ${foo}
 | |
| escape_re = re.compile(r'''
 | |
|   (?<!\$)        # Look-back: must not be preceded by another $.
 | |
|   \$
 | |
|   (\{)?          # May be enclosed by { } pair.
 | |
|   (?P<name>\w+)  # Save the symbol in named group.
 | |
|   (?(1)\})       # Expect } if and only if { was present.
 | |
| ''', re.VERBOSE)
 | |
| 
 | |
| def generate_script(output_filename, input_filenames):
 | |
|   # Create new python script and write the initial setup code.
 | |
|   script = StringIO()  # File-like in-memory buffer.
 | |
|   script.write("# DO NOT EDIT: This file was generated by gen-mterp.py.\n")
 | |
|   script.write(open(SCRIPT_SETUP_CODE, "r").read())
 | |
|   script.write("def opcodes():\n")
 | |
|   for i, opcode in enumerate(getOpcodeList()):
 | |
|     script.write('  write_opcode({0}, "{1}", {1})\n'.format(i, opcode))
 | |
| 
 | |
|   # Read all template files and translate them into python code.
 | |
|   for input_filename in sorted(input_filenames):
 | |
|     lines = open(input_filename, "r").readlines()
 | |
|     indent = ""
 | |
|     for line_number, line in enumerate(lines, 1):
 | |
|       file_line = "{}:{}".format("/".join(input_filename.split("/")[-2:]), line_number)
 | |
|       line = line.rstrip()
 | |
|       if line.startswith("%"):
 | |
|         script.write("{:80}  # {}\n".format(line.lstrip("%"), file_line))
 | |
|         indent = indent_re.match(line).group(1)
 | |
|         if line.endswith(":"):
 | |
|           indent += "  "
 | |
|       else:
 | |
|         line = escape_re.sub(r"''' + \g<name> + '''", line)
 | |
|         line = line.replace("\\", "\\\\")
 | |
|         line = line.replace("$$", "$")
 | |
|         script.write(indent + "write_line('''" + line + "''')\n")
 | |
|     script.write("\n")
 | |
| 
 | |
|   script.write("generate('''" + output_filename + "''')\n")
 | |
|   script.seek(0)
 | |
|   return script.read()
 | |
| 
 | |
| if len(sys.argv) <= 3:
 | |
|   print("Usage: output_file input_file(s)")
 | |
|   sys.exit(1)
 | |
| 
 | |
| # Generate the script and execute it.
 | |
| output_filename = sys.argv[1]
 | |
| input_filenames = sys.argv[2:]
 | |
| script_filename = output_filename + ".py"
 | |
| script = generate_script(output_filename, input_filenames)
 | |
| with open(script_filename, "w") as script_file:
 | |
|   script_file.write(script)  # Write to disk for debugging.
 | |
| exec(compile(script, script_filename, mode='exec'))
 |