def test_mov_edi_literal(self): writer = CodeWriter() writer.mov_edi_literal(1234) code = writer.get_code() inst = code[len(code) - 5:] expected = [0xbf, 0xd2, 0x4, 0, 0] for i in range(len(expected)): self.assertEqual(inst[i], expected[i])
def test_mov_edi_literal(self): writer = CodeWriter() writer.mov_edi_literal(1234) code = writer.get_code() inst = code[len(code)-5:] expected = [0xbf, 0xd2, 0x4, 0, 0] for i in range(len(expected)): self.assertEqual(inst[i], expected[i])
def main(vmfile): vmparser = VMParser(vmfile) cw = CodeWriter() while True: vmparser.advance() cw.process_command(vmparser.command) if not vmparser.has_more_commands(): break
def __init__(self): """Inciializa una tabald e simbolos y un ecritor de codigo junto con variables auxiliares""" self.symbolTable = SymbolTable() self.contWhile = -1 self.contIf = -1 self.nombreClase = "" self.kindMetodo = "" self.nombreMetodo = "" self.vmWriter = CodeWriter() self.vmWriter.vm = "" self.nArgs = 0
def translate(vmfiles, asmfile): w = CodeWriter(asmfile) for fn in vmfiles: print 'Parsing %s...'%fn p = Parser(fn) w.set_filename( os.path.splitext( os.path.split(fn)[-1] )[0] ) # Insert Code Here print 'Writing %s...'%asmfile w.close()
def build_code_writer(dest): if is_dest_dir(dest): print('we have a dir') output_filename = str(dest.split('/')[-1]) output_filename = os.path.join(dest, output_filename + '.asm') print(output_filename) code_writer = CodeWriter(output_filename, dest) else: print('we have a file') output_filename = dest[:-3] + '.asm' print(output_filename) code_writer = CodeWriter(output_filename, dest[:-3]) return code_writer
def main(argv): """ Main flow of program dealing with extracting files for reading and initializing files to translate into """ if not check_args(argv): return # extracting asm file to be processed vm_files_path = argv[1] # creating a .asm file to contain vm files translation to hack machine language if os.path.isdir(vm_files_path): dir_name = os.path.basename(vm_files_path) asm_file_name = "{0}/{1}.asm".format(vm_files_path, dir_name) code_writer = CodeWriter(asm_file_name) for file in os.listdir(vm_files_path): if file.endswith(".vm"): code_writer.set_file_name(file) vm_parser = VMParser('{0}/{1}'.format(vm_files_path, file)) translate_vm_file(code_writer, vm_parser) else: asm_file_name = "{0}.asm".format(os.path.splitext(vm_files_path)[0]) code_writer = CodeWriter(asm_file_name) code_writer.set_file_name(vm_files_path) vm_parser = VMParser(vm_files_path) translate_vm_file(code_writer, vm_parser)
def main(): path = Util.getCommandLineArgument(1) code_writer = CodeWriter(path.replace('.vm', '') + '.asm') if os.path.isdir(path): files = FileSet(path, 'vm') while files.hasMoreFiles(): filename = files.nextFile() Main.parse(filename, code_writer) elif os.path.isfile(path): Main.parse(path, code_writer) code_writer.Close()
class TestCodeWriter(unittest.TestCase): def setUp(self): self.filename = './StackArithmetic/SimpleAdd/SimpleAdd.asm' self.code_writer = CodeWriter(self.filename) def tearDown(self): self.code_writer.Close() def assertion(self, actual, expected): asserted = actual == expected if not asserted: print 'FAILED: assert {} == {}'.format(actual, expected) assert asserted def test_constructor_sets_attributes(self): assert self.code_writer.output.__class__.__name__ == 'file' def test_write_arthmetic(self): # self.assertion(self.code_writer.writeArithmetic('add'), '') assert '@SP' in self.code_writer.writeArithmetic('add')
def main(): parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('path', type=str, help='vm file or folder') args = parser.parse_args() path = args.path if path.endswith(".vm"): # file with CodeWriter(path[:-3] + ".asm") as code_writer: translate_file(path, code_writer) print "Translated to", path[:-3] + ".asm" else: # directory if path.endswith("/"): path = path[:-1] with CodeWriter(path + ".asm") as code_writer: files = glob.glob("%s/*" % path) for file in files: if file.endswith(".vm"): translate_file(file, code_writer) print "Translated to", path + ".asm"
def main(): vm_filename = sys.argv[1] asm_filename = vm_filename.replace('.vm', '.asm') vm_file = open(vm_filename, 'r') asm_file = open(asm_filename, 'a') parser = Parser(vm_file) code_writer = CodeWriter(asm_file) while parser.has_more_commands(): parser.advance() if parser.command_type() == C_ARITHMETIC: code_writer.write_arithmetic(parser.arg1()) elif parser.command_type() == C_PUSH: code_writer.write_push_pop(C_PUSH, parser.arg1(), parser.arg2()) elif parser.command_type() == C_POP: code_writer.write_push_pop(C_POP, parser.arg1(), parser.arg2()) vm_file.close() code_writer.close()
def translate(self): for count, f in enumerate(self.files_to_translate): should_bootstrap = True if count == 0 else False code_writer = CodeWriter(f.split('.vm')[0].split('/')[-1]) parser = Parser(f) for line in parser.read_lines(): if should_bootstrap and self.initiate_bootstrap: self.output_string += code_writer.bootstrap( self.contains_sys_vm_file) should_bootstrap = False command_type = parser.command_type(line) arg1 = parser.arg1(line) arg2 = parser.arg2(line) translated_line = code_writer.generate(command_type, arg1, arg2) self.output_string += translated_line self.__write_out()
def main(): # Input file Path in_file = Path(argv[1]) # Check if provided argument is # a file or a directory if (in_file.is_dir()): # Argument path to a directory out_file = in_file / in_file.with_suffix(".asm") elif (in_file.is_file()): # Argument is path to a file # Output file Path out_file = in_file.with_suffix(".asm") # Construct a CodeWriter to # handle output file asm_writer = CodeWriter(out_file) if (in_file.is_file()): # Translate the single file translate_in_file(asm_writer, in_file) elif (in_file.is_dir()): # Have to loop through every file asm_writer.write_bootstrap_code() # Loop through each file and translate for f in in_file.iterdir(): # File is .vm file? if f.suffix == ".vm": print(f"translating {f.name}...") asm_writer.set_file_name(f.stem) translate_in_file(asm_writer, f)
def __init__(self, scanner, output_file=None): self.scanner = scanner self.tokens = scanner.tokens self.log = logging.getLogger('parser') self.table = SymbolTable() if not len(self.log.handlers): self.log.setLevel(logging.DEBUG) hdlr = logging.FileHandler('/tmp/myapp.log') formatter = logging.Formatter( '%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) self.log.addHandler(hdlr) self.writer = CodeWriter(out_file=output_file)
def __init__(self, prefix, version, sourceFile, vars=None, events=None, outputdir=None): if not vars: vars = [] if not events: events = [] self.variables = vars self.events = events self.prefix = prefix self.version = version self.source = sourceFile hfile = headerFileName(prefix) + '.h' cfile = headerFileName(prefix) + '.c' if outputdir: hfile = os.path.join(outputdir, hfile) cfile = os.path.join(outputdir, cfile) self.hFile = CodeWriter(hfile) self.cFile = CodeWriter(cfile)
def main(): filename = sys.argv[1].split('.')[0] parser = Parser(filename) code = CodeWriter(filename) while(parser.has_more_commands()): parser.advance() command_type = parser.command_type() if command_type == 'C_ARITHMETIC': code.write_arithmetic(parser.arg1()) elif command_type == 'C_PUSH' or command_type == 'C_POP': code.write_push_pop(parser.command(), parser.arg1(), parser.arg2()) # print(parser.current_command) parser.close() code.close()
def translate(vmfiles, asmfile): w = CodeWriter(asmfile) for fn in vmfiles: print 'Parsing %s...' % fn p = Parser(fn) w.set_filename(os.path.splitext(os.path.split(fn)[-1])[0]) # Insert Code Here print 'Writing %s...' % asmfile w.close()
def translate(self): code_writer = CodeWriter(self.destination_file) # for each source filename for source_filename in self.source_filenames: parser = Parser(source_filename) code_writer.set_filename(source_filename) # parse each command while parser.has_more_commands(): # advance to the next command parser.advance() # parse the command type command_type = parser.command_type() if command_type == "C_ARITHMETIC": code_writer.write_arithemtic(parser.arg1()) elif command_type in ["C_POP", "C_PUSH"]: code_writer.write_push_pop(command_type, parser.arg1(), parser.arg2()) else: raise Error("Not implemented: command type " + command_type) # close the output file code_writer.close()
def main(): args = get_args() dbc_filepath = args.dbc output = args.output print_only = args.print_only dbc_node_name = args.dbc_node_name if not os.path.isfile(dbc_filepath): print("Unable to find DBC file: [{}]".format(dbc_filepath)) return 1 # Return early try: code_writer = CodeWriter(dbc_filepath, dbc_node_name) except InvalidDBCNodeError as err: print(ColorString(str(err)).red) return 1 # Return early if not print_only: dbc_filename = os.path.basename(dbc_filepath) basename, ext = os.path.splitext(os.path.basename(dbc_filepath)) output_filename = "{}.h".format(basename) if output is None: output_filepath = output_filename elif os.path.isdir(output) or "." not in os.path.basename(output): output_filepath = os.path.join(output, output_filename) else: output_filepath = output message = "Generating code [{}] -> [{}]".format( dbc_filename, output_filename) if dbc_node_name != GENERATE_ALL_NODE_NAME: message += " using node [{}]".format(dbc_node_name) print(ColorString(message).green) if not os.path.isdir(os.path.dirname(output_filepath)): os.makedirs(os.path.dirname(output_filepath)) with open(output_filepath, "w") as file: file.write(str(code_writer)) else: print(code_writer) return 0
def main(): # If there is an invalid number of arguments the program stops. if len(sys.argv) != 2: print("ERROR: Invalid number of arguments. Expected: file_name.vm ") exit(1) # the VM translator only accepts vm files to be translated into assembly files. elif sys.argv[1][-3:] != ".vm": print("ERROR: Invalid file type. Expected: vm file") exit(1) # Get the name of the file to be parsed from the arguments. input_file = sys.argv[1] # Creates a new parser to parse the file. parser = Parser(input_file) # Creates the code writer with the input file excluding the .vm part code_writer = CodeWriter(input_file[0:-3]) # Reads the whole file. while parser.has_more_commands(): parser.advance() # Gets the command type from the current command. command_type = parser.command_type() # If the command type is C_ARITHMETIC parses it to get the command and passes it to the code writer to add it to the output file if command_type == "C_ARITHMETIC": command = parser.arg1() code_writer.write_arithmetic(command) # If the command type is C_PUSH or C_POP parses it to get the segment and the index and passes it to the code writer to add it to the output file elif command_type == "C_PUSH" or command_type == "C_POP": segment = parser.arg1() index = parser.arg2() code_writer.write_push_pop(command_type, segment, index) del parser code_writer.close()
def main(): if len(sys.argv) != 2: print('<VMTranslator>: Execute script with ' 'one argument only (The path of an existing "vm" file)\n') exit() vm_file = sys.argv[1] parser = VMParser(vm_file) asm_file = vm_file.replace('.vm', '.asm') code_writer = CodeWriter(asm_file) while parser.has_more_commands(): code_writer.write_command(parser.command) parser.advance() code_writer.write_end() print '<VMTranslator>: Successfully created "{}"\n'.format(asm_file)
def main(): '''Main entry point for the script.''' # For each .vm file, create a parser object filetrue = os.path.isfile(sys.argv[1]) dirtrue = os.path.isdir(sys.argv[1]) vmfiles = [] # Rename directory as a ".asm" file for later use finame = os.path.basename(os.path.normpath(sys.argv[1])) + ".asm" # Get file path with .asm file appended dirname = os.path.join(sys.argv[1], finame) # Create list of files to convert and add to asm file if dirtrue: cw = CodeWriter(dirname) fi = os.listdir(sys.argv[1]) for names in fi: if names.endswith(".vm"): vmfiles.append(sys.argv[1] + names) elif filetrue: di = sys.argv[1] if di.endswith(".vm"): vmfiles.append(di) tr = vmfiles[0] trs = tr.replace("vm", "asm") cw = CodeWriter(trs) else: print "invalid filetype: only input .vm files" else: print "usage: 'python <file.vm> or <dirname/>'" out = cw.constructor() cw.writeInit(out) with out as outfile: for files in vmfiles: # Create new instance of class Parser() p = cw.setFileName(files) with p.constructor() as infile: for line in infile: if p.commandType(line) == "comments": pass elif p.commandType(line) == "C_ARITHMETIC": cw.writeArithmetic(outfile, p.args(line)[0]) elif p.commandType(line) == "C_IF": # Handle if-goto command cw.writeIf(outfile, p.args(line)[1]) elif p.commandType(line) == "C_GOTO": # Handle goto command cw.writeGoto(outfile, p.args(line)[1]) elif p.commandType(line) == "C_RETURN": # Return function result cw.writeReturn(outfile) elif p.commandType(line) == "C_LABEL": # Set label address cw.writeLabel(outfile, p.args(line)[1]) elif p.commandType(line) == "C_CALL": # Handle function calls cw.writeCall(outfile, p.args(line)[1], p.args(line)[2]) elif p.commandType(line) == "C_FUNCTION": cw.writeFunction(outfile, p.args(line)[1], p.args(line)[2]) elif p.commandType(line) == "C_PUSH" or "C_POP": cw.writePushPop(outfile, p.commandType(line), p.args(line)[1], p.args(line)[2])
from parser import Parser from code_writer import CodeWriter # get input file name try: input_folder_name = sys.argv[1].replace('/', '') except IndexError: print('there is no folder argument') vm_files = filter(lambda f : f.endswith('.vm'), os.listdir(input_folder_name)) vm_files = deque(vm_files) for f in ['Main.vm', 'Sys.vm']: if f in vm_files: vm_files.remove(f) vm_files.appendleft(f) vm_files.appendleft('../BootstrapCode.vm') shared_data = SharedData(input_folder_name) io_file = IOFile(shared_data) parser = Parser(shared_data) code_writer = CodeWriter(shared_data) for f in vm_files: shared_data.set_input_file_name(f) io_file.file_to_array() parser.run() code_writer.run() io_file.array_to_file()
def translate(self): code_writer = CodeWriter(self.destination_file) # for each source filename for source_filename in self.source_filenames: parser = Parser(source_filename) code_writer.set_filename(source_filename) # parse each command while parser.has_more_commands(): # advance to the next command parser.advance() # parse the command type command_type = parser.command_type() if command_type == "C_ARITHMETIC": code_writer.write_arithemtic(parser.arg1()) elif command_type in ["C_POP", "C_PUSH"]: code_writer.write_push_pop(command_type, parser.arg1(), parser.arg2()) elif command_type == "C_LABEL": code_writer.write_label(parser.arg1()) elif command_type == "C_GOTO": code_writer.write_goto(parser.arg1()) elif command_type == "C_IF": code_writer.write_if(parser.arg1()) elif command_type == "C_FUNCTION": code_writer.write_function(parser.arg1(), parser.arg2()) elif command_type == "C_RETURN": code_writer.write_return() elif command_type == "C_CALL": code_writer.write_call(parser.arg1(), parser.arg2()) else: raise Exception("Not implemented: command type " + command_type) # close the output file code_writer.close()
def setUp(self): self.filename = './StackArithmetic/SimpleAdd/SimpleAdd.asm' self.code_writer = CodeWriter(self.filename)
from parser import Parser from code_writer import CodeWriter arg_parser = argparse.ArgumentParser(description='Translate vm code into assembly code') arg_parser.add_argument('path_input', help='The path for vm file *.vm or the directory path which contains *.vm files') args = arg_parser.parse_args() path_input = Path(args.path_input) assert path_input.exists(), "Path not exists." if path_input.is_dir(): # Translate all vm files in directory vmfiles = [f for f in path_input.glob('*.vm')] assert vmfiles, "No vm file in this directory." out_asm_file = path_input / (path_input.name + '.asm') # Out asm file name same as directory name returned_contents = {} for vmfile in vmfiles: psr = Parser(vmfile) parse_result = psr.parse() returned_contents = {**returned_contents, **parse_result} # Merge returned results to dict returned_contents else: # Translate one vm file vmfile = path_input out_asm_file = path_input.with_suffix('.asm') psr = Parser(vmfile) returned_contents = psr.parse() cw = CodeWriter(returned_contents, out_asm_file) cw.write() print('Successfully translate to assembly ' + out_asm_file.as_posix())
elif parser.command_type() == 'C_RETURN': code_writer.write_return() elif parser.command_type() == 'C_CALL': function_name = parser.arg1() num_args = int(parser.arg2()) code_writer.write_call(function_name, num_args) if __name__ == '__main__': input_file = sys.argv[1] if path.isfile(input_file): src_vm_files = [input_file] asm_file = path.splitext(input_file)[0] + ".asm" else: src_vm_files = glob.glob(path.join(sys.argv[1], '*.vm')) asm_file = path.split(input_file.rstrip('/') + ".asm")[1] asm_file = path.join(input_file, asm_file) code_writer = CodeWriter(asm_file) if len(src_vm_files) != 1: code_writer.write_init() for src_vm_file in src_vm_files: parse_and_write(code_writer, src_vm_file) code_writer.close()
class LogFile: def __init__(self, prefix, version, sourceFile, vars=None, events=None, outputdir=None): if not vars: vars = [] if not events: events = [] self.variables = vars self.events = events self.prefix = prefix self.version = version self.source = sourceFile hfile = headerFileName(prefix) + '.h' cfile = headerFileName(prefix) + '.c' if outputdir: hfile = os.path.join(outputdir, hfile) cfile = os.path.join(outputdir, cfile) self.hFile = CodeWriter(hfile) self.cFile = CodeWriter(cfile) def constructCodeFile(self): self.cFile.clear() self.cFile.append(AutogenString(self.source)) #include the header file self.cFile.include('"{file}.h"'.format(file=headerFileName(self.prefix))) self.cFile.appendLine() #add in the global functions self.cFile.startComment() self.cFile.appendLine("Global functions") self.cFile.finishComment() self.cFile.appendLine() self.createResetFunction() self.createCopyAllToFunction() self.createCopyDataToFunction() self.createCopyAllFromFunction() self.createCopyDataFromFunction() self.getSelectionSizeFunction() self.cFile.appendLine() self.cFile.startComment() self.cFile.appendLine("Individual variable functions") self.cFile.finishComment() self.cFile.appendLine() #add in the functions to add variables for v in self.variables: self.createAdditionFunction(v) self.createDecodeFunction(v) self.titleByIndexFunction() self.unitsByIndexFunction() self.valueByIndexFunction() if len(self.events) > 0: self.cFile.appendLine() self.cFile.appendLine(comment='Functions to copy *events* to a buffer') for e in self.events: self.addEventCopyFuncs(e) self.cFile.appendLine(comment='Decode a {pref} event to a string'.format(pref=self.prefix)) self.eventsToStringFunction() self.cFile.appendLine() self.cFile.appendLine(comment='Functions for formatting individual events to a string') for e in self.events: self.eventToStringFunc(e) def constructHeaderFile(self): self.hFile.clear() self.hFile.append(AutogenString(self.source)) self.hFile.startIf(headerDefineName(self.prefix),invert=True) self.hFile.define(headerDefineName(self.prefix)) self.hFile.appendLine() self.hFile.include('"logjam_common.h"', comment='common LogJam routines') self.hFile.appendLine() self.hFile.externEntry() #version information self.hFile.appendLine() self.hFile.appendLine(comment='{pre} logging version'.format(pre=self.prefix)) self.hFile.define('LOG_{pref}_VERSION()'.format(pref=self.prefix),value='"{v}"'.format(v=self.version)) vMaj, vMin = self.version.split('.') self.hFile.define('LOG_{pref}_VERSION_MAJOR'.format(pref=self.prefix),value=vMaj) self.hFile.define('LOG_{pref}_VERSION_MINOR'.format(pref=self.prefix),value=vMin) self.hFile.appendLine() #create global enumeration for the variables fn = lambda i,val: "{val} is stored in byte {n}, position {m}".format(val=val,n=int(int(i)/8),m=i%8) self.hFile.createEnum('Log{pref}_VariableEnum_t'.format(pref=self.prefix),[v.getEnumString() for v in self.variables],split=8,commentFunc=fn) self.hFile.appendLine(comment='{n} bytes are required to store all parameter selction bits for {log} logging'.format(n=bitfieldSize(len(self.variables)),log=self.prefix)) self.hFile.define('LOG_{pref}_SELECTION_BYTES'.format(pref=self.prefix.upper()),value=bitfieldSize(len(self.variables))) self.hFile.appendLine() self.hFile.appendLine(comment="Number of variables defined for the '{pref}' logging structure".format(pref=self.prefix)) self.hFile.define('LOG_{pref}_VARIABLE_COUNT'.format(pref=self.prefix.upper()), value=len(self.variables)) self.hFile.appendLine() self.hFile.appendLine(comment="Struct definition for storing the selection bits of the " + self.prefix + " logging struct") self.hFile.appendLine(comment='This is not stored as a native c bitfield to preserve explicit ordering between processors, compilers, etc') self.hFile.appendLine('typedef uint8_t {name}[LOG_{pref}_SELECTION_BYTES];'.format(pref=self.prefix.upper(),name=bitfieldStructName(self.prefix))) self.hFile.appendLine() self.hFile.appendLine(comment="Data struct definition for the " + self.prefix + " logging struct") self.createDataStruct() #total data size d_size = sum([v.bytes for v in self.variables]) self.hFile.appendLine() self.hFile.appendLine(comment='{n} bytes are required to store all the data parameters'.format(n=d_size)) self.hFile.define('LOG_{pref}_DATA_BYTES'.format(pref=self.prefix.upper()),value=d_size) self.hFile.appendLine() #events if len(self.events) > 0: self.hFile.appendLine(comment='Logging event definitions for the {the}'.format(the=self.prefix)) self.hFile.appendLine(comment='Enumeration starts at 0x80 as *generic* events are 0x00 -> 0x7F') self.hFile.createEnum('Log{pref}_EventEnum_t'.format(pref=self.prefix),[e.getEnumString() for e in self.events],start="0x80") self.hFile.appendLine() self.hFile.appendLine(comment='Functions to copy various log events to logging buffer') self.hFile.appendLine(comment='Each function returns the number of bytes written to the log') self.hFile.appendLine(comment='Pointer is automatically incremented as required') #functions for the events for e in self.events: self.hFile.appendLine('inline uint8_t {func};'.format(func=e.eventPrototype())) self.hFile.appendLine(); self.hFile.appendLine(comment='Function to extract an event from a buffer, and format it as a human-readable string') self.hFile.appendLine(self.eventsToStringPrototype() + ';') self.hFile.appendLine() self.hFile.appendLine(comment='Functions for turning individual events into strings') for e in self.events: self.hFile.appendLine(e.toStringPrototype() + ';',comment='Format the {evt} event into a string'.format(evt=e.getEnumString())) self.hFile.appendLine() self.hFile.startComment() self.hFile.appendLine("Global Functions:") self.hFile.finishComment() self.hFile.appendLine(comment="Reset the bitfield of the logging structure") self.hFile.appendLine(self.resetPrototype() + ";") self.hFile.appendLine(comment='Copy *all* data from the logging structure') self.hFile.appendLine(self.copyAllPrototype() + ';') self.hFile.appendLine(comment="Copy *selected* data from the logging structure") self.hFile.appendLine(self.copySelectedPrototype() + ";") self.hFile.appendLine(comment='Copy all data back out from a buffer') self.hFile.appendLine(self.copyAllFromPrototype() + ';') self.hFile.appendLine(comment='Copy *selected* data back out from a buffer') self.hFile.appendLine(self.copyDataFromPrototype() + ';') self.hFile.appendLine(comment='Get the total size of the selected variables') self.hFile.appendLine(self.getSelectionSizePrototype() + ';') self.hFile.appendLine() self.hFile.appendLine(comment="Functions for getting variable information based on the index"); self.hFile.appendLine(self.titleByIndexPrototype()+';') self.hFile.appendLine(self.unitsByIndexPrototype()+';') self.hFile.appendLine(self.valueByIndexPrototype() + ';') self.hFile.appendLine() self.hFile.startComment() self.hFile.appendLine("Variable Functions:") self.hFile.appendLine("These functions are applied to individual variables within the logging structure") self.hFile.finishComment() #add in the 'addition' functions for var in self.variables: self.hFile.appendLine() self.hFile.appendLine(comment="Functions for the '{name}' variable".format(name=var.name)) self.hFile.define('Log{prefix}_{name}Title() {title}'.format( prefix=self.prefix, name=var.name, title=var.getTitleString()), comment='Title string for {var} variable'.format(var=var.name)) self.hFile.define('Log{prefix}_{name}Units() {units}'.format( prefix=self.prefix, name=var.name, units=var.getUnitsString()), comment='Units string for {var} variable'.format(var=var.name)) self.hFile.appendLine(self.additionPrototype(var) + '; //Add ' + var.name + " to the log struct") self.hFile.appendLine(self.decodePrototype(var) + '; //Decode ' + var.name + ' into a printable string') self.hFile.appendLine() self.hFile.externExit() self.hFile.endIf() def saveFiles(self): self.constructHeaderFile() self.constructCodeFile() self.hFile.writeToFile() self.cFile.writeToFile() def addEventCopyFuncs(self, e): #copy TO buffer self.cFile.appendLine('inline uint8_t {func}'.format(func=e.eventPrototype())) self.cFile.openBrace() #copy across the event type self.cFile.appendLine('*(*ptr++) = {evt};'.format(evt=e.getEnumString()),comment='Copy the event type to the buffer') if len(e.variables) > 0: self.cFile.appendLine() for v in e.variables: self.copyVarToBuffer(v,struct='',pointer='ptr') self.cFile.appendLine() self.cFile.appendLine('return {n};'.format(n=e.eventSize()),comment='Number of bytes copied') self.cFile.closeBrace() self.cFile.appendLine() #create the struct of the variables def createDataStruct(self): self.hFile.appendLine('typedef struct {') self.hFile.tabIn() for v in self.variables: self.hFile.appendLine(comment="Variable '{name}'{units}{scaler} ({n} bytes)".format( name = v.name, units = ", units='{u}'".format(u=v.units) if v.units else '', scaler = ", scaler=1.0/{scaler}".format(scaler=v.scaler) if v.scaler > 1 else '', n = v.bytes)) self.hFile.appendLine(v.dataString()) self.hFile.tabOut() self.hFile.appendLine('} ' + dataStructName(self.prefix) + ';') def additionPrototype(self,var): return self.createVariableFunction(var,'add',returnType='bool',extra=[('onlyIfNew','bool')]) #create the function for adding a variable to the logging structure def createAdditionFunction(self, var): self.cFile.appendLine(comment='Add variable {name} to the {prefix} logging struct'.format( name=var.name, prefix=self.prefix)) self.cFile.appendLine(self.additionPrototype(var)) self.cFile.openBrace() self.cFile.appendLine('if (onlyIfNew == true)',comment='Ignore value if it is the same as the value already stored') self.cFile.openBrace() self.cFile.appendLine('if (data->{var} == {var})'.format(var=var.name)) self.cFile.tabIn() self.cFile.appendLine('return false;') self.cFile.tabOut() self.cFile.closeBrace() self.cFile.appendLine() self.cFile.appendLine(var.setBit('selection'),comment='Set the appropriate bit') #now actually add the variable in self.cFile.appendLine(var.addVariable('data')) self.cFile.appendLine() self.cFile.appendLine('return true;') self.cFile.closeBrace() self.cFile.appendLine() #function for decoding a particular variable into a printable string for writing to a log file def decodePrototype(self, var): return self.createVariableFunction(var,'decode',blank=True,bits=False,returnType='void',extra=[('*str','char')]) def createDecodeFunction(self, var): self.cFile.appendLine(comment='Decode the {name} variable and return a printable string (e.g. for saving to a log file'.format(name=var.name)) self.cFile.appendLine(comment='Pointer to *str must have enough space allocated!') self.cFile.appendLine(self.decodePrototype(var)) self.cFile.openBrace() self.cFile.appendLine('sprintf(str,"{patt}",data->{var});'.format(patt=var.getStringCast(),var=var.name)) self.cFile.closeBrace() self.cFile.appendLine() pass #create a function pointing to a particular variable def createVariableFunction(self, var, name, blank=False, extra=None,ptr=False, **params): name = var.getFunctionName(name) if not extra: extra = [] if not blank: extra = [('{ptr}{name}'.format(ptr='*' if ptr else '',name=var.name),var.format)] + extra return self.createFunctionPrototype(name,extra=extra,**params) """ Create a function type of given NAME name - name of the function data - Include a pointer to the LogData_t struct? bits - Include a pointer to the LogBitfield_t struct? inline - Make the function inline? returnType - Function return type extra - Extra parameters to pass to the function - list of tuples """ def createFunctionPrototype(self, name, data=True, bits=True, inline=False, returnType='void', extra=None): if not extra: extra = [] #pass extra parameters to the function as such #params = {'*dest': 'void'} (name, type) paramstring = "" for pair in extra: paramstring += ', ' paramstring += pair[1] paramstring += ' ' paramstring += pair[0] return '{inline}{returnType} Log{prefix}_{name}({data}{comma}{bits}{params})'.format( inline='inline ' if inline else '', returnType=returnType, prefix=self.prefix.capitalize(), name=name, comma=', ' if data and bits else '', data=dataStructName(self.prefix) + " *data" if data else "", bits=bitfieldStructName(self.prefix) + " *selection" if bits else "", params=paramstring) def resetPrototype(self): return self.createFunctionPrototype('ResetSelection',data=False) #create a function to reset the logging structure def createResetFunction(self): #add the reset function to the c file self.cFile.appendLine(comment='Reset the log data struct (e.g. after writing to memory)') self.cFile.appendLine(comment='Only the selection bits need to be reset') self.cFile.appendLine(self.resetPrototype()) self.cFile.openBrace() self.cFile.appendLine('uint8_t *bf = (uint8_t*) selection;') for i in range(bitfieldSize(len(self.variables))): self.cFile.appendLine('bf[{n}] = 0; //Clear byte {x} of {y}'.format(n=i,x=i+1,y=bitfieldSize(len(self.variables)))) self.cFile.closeBrace() self.cFile.appendLine() """ Functions for copying data out of a struct and into a linear buffer """ def copyAllPrototype(self): return self.createFunctionPrototype('CopyAllToBuffer',bits=False,extra=[('*dest','void')]) #create a function to copy ALL parameters across, conserving data format def createCopyAllToFunction(self): self.cFile.appendLine(comment="Copy ALL data in the log struct to the provided address") self.cFile.appendLine(comment="Data will be copied even if the associated selection bit is cleared") self.cFile.appendLine(self.copyAllPrototype()) self.cFile.openBrace() self.cFile.appendLine('uint8_t *ptr = (uint8_t*) dest; //Pointer for keeping track of data addressing') self.cFile.appendLine() for var in self.variables: self.copyVarToBuffer(var) self.cFile.appendLine() self.cFile.closeBrace() self.cFile.appendLine() def copySelectedPrototype(self): return self.createFunctionPrototype('CopyDataToBuffer',extra=[('*dest','void')], returnType='uint16_t') #create a function that copies across ONLY the bits that are set def createCopyDataToFunction(self): self.cFile.appendLine(comment="Copy across data whose selection bit is set in the provided bitfield") self.cFile.appendLine(comment="Only data selected will be copied (in sequence)") self.cFile.appendLine(comment="Ensure a copy of the selection bits is stored for decoding") self.cFile.appendLine(self.copySelectedPrototype()) self.cFile.openBrace() self.cFile.appendLine('uint8_t *ptr = (uint8_t*) dest; //Pointer for keeping track of data addressing') self.cFile.appendLine('uint8_t *bf = (uint8_t*) selection; //Pointer for keeping track of the bitfield') self.cFile.appendLine('uint16_t count = 0; //Variable for keeping track of how many bytes were copied') self.cFile.appendLine() self.cFile.appendLine(comment='Copy the selection for keeping track of data') self.copyBitfieldToBuffer(count=True) self.cFile.appendLine() self.cFile.appendLine(comment='Check each variable in the logging struct to see if it should be added') for var in self.variables: self.cFile.appendLine('if ({test})'.format(test=var.getBit('selection'))) self.cFile.openBrace() self.copyVarToBuffer(var, count=True) self.cFile.closeBrace() self.cFile.appendLine() self.cFile.appendLine('return count; //Return the number of bytes that were actually copied') self.cFile.closeBrace() self.cFile.appendLine() def copyBitfieldToBuffer(self, count=False): #bitfield is called 'selection' locally #size of the bitfield bf_size = bitfieldSize(len(self.variables)) for i in range(bf_size): self.cFile.appendLine('*(ptr++) = bf[{i}];'.format(i = i)) if count: self.cFile.appendLine('count += {size};'.format(size=bf_size)) def copyBitfieldFromBuffer(self, count=False): bf_size = bitfieldSize(len(self.variables)) for i in range(bf_size): self.cFile.appendLine('bf[{i}] = *(ptr++);'.format(i=i)) if count: self.cFile.appendLine('count += {size};'.format(size=bf_size)) def copyVarToBuffer(self, var, struct='data->', pointer='&ptr', count=False): self.cFile.appendLine('Copy{sign}{bits}ToBuffer({struct}{name}, {ptr});'.format( sign='I' if var.isSigned() else 'U', bits=var.bytes*8, struct=struct, name=var.name, ptr = pointer), comment= "Copy the '{var}' variable ({n} bytes)".format(var=var.name,n=var.bytes)) if count: self.cFile.appendLine('count += {size};'.format(size=var.bytes)) def copyVarFromBuffer(self, var, struct='data->',pointer='&ptr',count=False): self.cFile.appendLine('Copy{sign}{bits}FromBuffer({struct}{name}, {ptr});'.format( sign='I' if var.isSigned() else 'U', bits=var.bytes*8, struct=struct, name=var.name, ptr = pointer, ), comment="Copy the '{var}' variable ({n} bytes)".format(var=var.name,n=var.bytes)) if count: self.cFile.appendLine('count += {size};'.format(size=var.bytes)) """ Functions for copying data back out of a buffer """ def copyAllFromPrototype(self): return self.createFunctionPrototype( 'CopyAllFromBuffer', bits = False, extra = [('*src','void')]) def createCopyAllFromFunction(self): self.cFile.appendLine(comment="Copy across *all* data from a buffer") self.cFile.appendLine(comment="Data will be copied even if it is invalid (selection bit is cleared)") self.cFile.appendLine(self.copyAllFromPrototype()) self.cFile.openBrace() self.cFile.appendLine('uint8_t *ptr = (uint8_t*) src; //Pointer for keeping track of data addressing') self.cFile.appendLine() for var in self.variables: self.copyVarFromBuffer(var) self.cFile.appendLine() self.cFile.closeBrace() self.cFile.appendLine() def copyDataFromPrototype(self): return self.createFunctionPrototype('CopyDataFromBuffer', returnType='uint16_t', extra = [('*src','void')]) def createCopyDataFromFunction(self): self.cFile.appendLine(comment="Copy across *selected* data from a buffer") self.cFile.appendLine(self.copyDataFromPrototype()) self.cFile.openBrace() self.cFile.appendLine('uint8_t *ptr = (uint8_t*) src; //Pointer for keeping track of data addressing') self.cFile.appendLine('uint8_t *bf = (uint8_t*) selection; //Pointer for keeping track of the bitfield') self.cFile.appendLine('uint16_t count = 0; //Variable for keeping track of how many bytes were copied') self.cFile.appendLine() self.cFile.appendLine(comment='Copy the selection bits') self.copyBitfieldFromBuffer(count=True) self.cFile.appendLine() self.cFile.appendLine(comment='Only copy across variables that have actually been stored in the buffer') for var in self.variables: self.cFile.appendLine('if ({test})'.format(test=var.getBit('selection'))) self.cFile.openBrace() self.copyVarFromBuffer(var,count=True) self.cFile.closeBrace() self.cFile.appendLine() self.cFile.appendLine('return count; //Return the number of bytes that were actually copied') self.cFile.closeBrace() self.cFile.appendLine() #enumerate through all the varibles in the struct, perform 'function' for each def createCaseEnumeration(self, vars=None, blankFunction=None, returnFunction=None): if not vars: vars = self.variables for var in vars: self.cFile.addCase(var.getEnumString()) if blankFunction: blank = blankFunction(var) if not blank.endswith(';'): blank += ';' self.cFile.appendLine(blank) if returnFunction: self.cFile.returnFromCase(returnFunction(var)) else: self.cFile.breakFromCase() def titleByIndexPrototype(self): return 'char* Log{pref}_GetTitleByIndex(uint8_t index)'.format(pref=self.prefix) def titleByIndexFunction(self): self.cFile.appendLine(comment='Get the title of a variable based on its enumerated value') self.cFile.appendLine(self.titleByIndexPrototype()) self.cFile.openBrace() self.cFile.startSwitch('index') #add case labels #function to return the index fn = lambda var: 'Log{prefix}_{var}Title()'.format(prefix=self.prefix,var=var.name) self.createCaseEnumeration(returnFunction = fn) self.cFile.endSwitch() self.cFile.appendLine(comment='Default return value') self.cFile.appendLine('return "";') self.cFile.closeBrace() self.cFile.appendLine() def unitsByIndexPrototype(self): return 'char* Log{pref}_GetUnitsByIndex(uint8_t index)'.format(pref=self.prefix) def unitsByIndexFunction(self): self.cFile.appendLine(comment='Get the units of a variable based on its enumerated value') self.cFile.appendLine(self.unitsByIndexPrototype()) self.cFile.openBrace() self.cFile.startSwitch('index') fn = lambda var: 'Log{prefix}_{var}Units()'.format(prefix=self.prefix,var=var.name) self.createCaseEnumeration(returnFunction = fn) self.cFile.endSwitch() self.cFile.appendLine(comment='Default return value') self.cFile.appendLine('return "";') self.cFile.closeBrace() self.cFile.appendLine() def valueByIndexPrototype(self): return self.createFunctionPrototype('GetValueByIndex',bits=False,extra=[('index','uint8_t'), ('*str','char')]) def valueByIndexFunction(self): self.cFile.appendLine(comment='Get a string-representation of a given variable, based on its enumerated value') self.cFile.appendLine(self.valueByIndexPrototype()) self.cFile.openBrace() self.cFile.startSwitch('index') fn = lambda var: 'Log{prefix}_Decode{name}(data,str)'.format(prefix=self.prefix.capitalize(),name=var.name) self.createCaseEnumeration(blankFunction=fn) self.cFile.endSwitch() self.cFile.closeBrace() self.cFile.appendLine() #function to turn an event into a string #pass a pointer to where the event data starts #pointer will be auto-incremented #returns 'true' if an event was extracted, else false def eventsToStringPrototype(self): return 'bool Log{pref}_EventToString(uint8_t **ptr, char *str)'.format(pref=self.prefix) def eventsToStringFunction(self): self.cFile.startComment() self.cFile.appendLine('Extract an event from a buffer, given a pointer to the buffer, and a pointer to where the event will be strung') self.cFile.appendLine('Function will auto-increment the pointer as necessary') self.cFile.appendLine('Returns true if event was extracted and formatted as string, else returns false') self.cFile.finishComment() self.cFile.appendLine(self.eventsToStringPrototype()) self.cFile.openBrace() self.cFile.appendLine() self.cFile.appendLine('#error this needs to be completed') self.cFile.startSwitch('TBD') #function for formatting a given even to a string fn = lambda var: 'Log{pref}_EventToString_{name}(ptr,str)'.format(pref=var.prefix,name=var.name) self.createCaseEnumeration(vars = self.events, blankFunction = fn) self.cFile.addCase('default') self.cFile.returnFromCase(value='false') self.cFile.endSwitch() self.cFile.appendLine('return true;',comment='Default return case') self.cFile.closeBrace() #func for formatting an individual func to a string def eventToStringFunc(self, evt): self.cFile.appendLine(comment='Format a {evt} event into a readable string'.format(evt=evt.name)) self.cFile.appendLine(comment='Auto-increment the **ptr pointer') self.cFile.appendLine(evt.toStringPrototype()) self.cFile.openBrace() #define vars for this event for v in evt.variables: #local var for temp storage of data self.cFile.appendLine('{fmt} {name};'.format(fmt=v.format,name=v.name),comment="Temporary storage for '{var}' variable".format(var=v.name)) self.cFile.appendLine() if len(evt.variables) > 0: self.cFile.appendLine(comment='Copy the event variables from the buffer') for v in evt.variables: self.copyVarFromBuffer(v,struct='&',pointer='ptr') self.cFile.appendLine() #compile a list of variables associated with this event fmts = " ".join([v.getStringCast() for v in evt.variables]) vars = ", ".join([v.name for v in evt.variables]) self.cFile.appendLine('sprintf(str,"Event: {evt}{sep}{formats}"{comma}{vars});'.format( evt = evt.getEnumString(), sep = ' -> ' if len(fmts) > 0 else '', formats = fmts, comma = ', ' if len(vars) > 0 else '', vars = vars)) self.cFile.closeBrace() self.cFile.appendLine() #function to determine the size of the selected data def getSelectionSizePrototype(self): return self.createFunctionPrototype('GetSelectionSize',data=False,returnType='uint16_t') def getSelectionSizeFunction(self): self.cFile.appendLine(comment='Get the total size of the selected variables') self.cFile.appendLine(self.getSelectionSizePrototype()) self.cFile.openBrace() self.cFile.appendLine('uint16_t size = 0;') self.cFile.appendLine() for var in self.variables: self.cFile.appendLine('if ({test})'.format(test=var.getBit('selection'))) self.cFile.openBrace() self.cFile.appendLine('size += {n};'.format(n=var.bytes)) self.cFile.closeBrace() self.cFile.appendLine() self.cFile.appendLine('return size;') self.cFile.closeBrace() self.cFile.appendLine()
def _set_website_snippet_static_javascript_file(self, module): """ Function to set the module hook file :param module: :return: """ cw = CodeWriter() cw.cur_indent = 4 * cw.default_dent if module.generate_website_snippet_generic_model: lst_model_search = ( module.generate_website_snippet_generic_model.split(";") ) lst_model_id_search = [] for s_model in lst_model_search: model_id = self.env["ir.model"].search( [("model", "=", s_model)] ) if model_id: lst_model_id_search.append(model_id[0]) else: _logger.warning(f"Model not existing : {s_model}") for model_id in lst_model_id_search: for field_id in model_id.field_id: if field_id.name not in MAGIC_FIELDS: cw.emit(f'if (data["{field_id.name}"]) {{') with cw.indent(): with cw.indent(): cw.emit( f'self.$(".{field_id.name}_value").text(data["{field_id.name}"]);' ) cw.emit("}") else: cw.emit("var data_json = data;") cw.emit('var hello = data_json["hello"];') cw.emit(f'self.$(".{module.name}_value").text(hello);') code = cw.render() content = ( f"odoo.define('{module.name}.animation', function (require)" """ { 'use strict'; var sAnimation = require('website.content.snippets.animation'); sAnimation.registry.""" f"{module.name}" """ = sAnimation.Class.extend({ """ f"selector: '.o_{module.name}'," """ start: function () { var self = this; var def = this._rpc({route: '""" f"/{module.name}/helloworld" """'}).then(function (data) { if (data.error) { return; } if (_.isEmpty(data)) { return; } """ + code + """ }); return $.when(this._super.apply(this, arguments), def); } }) }); """ ) file_path = os.path.join( "static", "src", "js", f"website.{module.name}.animation.js" ) self.code_generator_data.write_file_str(file_path, content)
def setUp(self): self.cw = CodeWriter()
def main(): config = get_config() cw = CodeWriter() mydoc = minidom.parse(config.file) if not mydoc: print(f"Error, cannot parse {config.file}") sys.exit(1) cw.emit("from lxml.builder import E") cw.emit("from lxml import etree as ET") cw.emit("from code_writer import CodeWriter") cw.emit("") cw.emit('print(\'<?xml version="1.0" encoding="utf-8"?>\')') cw.emit('print("<odoo>")') lst_function = [] comment_for_next_group = None for odoo in mydoc.getElementsByTagName("odoo"): for ir_view_item in odoo.childNodes: if ir_view_item.nodeType == Node.ELEMENT_NODE: # Show part of xml fct_name = "ma_fonction" lst_function.append(fct_name) cw.emit(f"def {fct_name}():") with cw.indent(): cw.emit('"""') for line in transform_string_to_list( ir_view_item.toprettyxml() ): cw.emit(line) cw.emit('"""') # Show comment if comment_for_next_group: cw.emit( "print('<!--" f" {comment_for_next_group.strip()} -->')" ) comment_for_next_group = None attributes_root = dict(ir_view_item.attributes.items()) lst_out = code_writer_deep_xml(ir_view_item) generate_code = GenerateCode() generate_code.generate_code(lst_out) child_root = generate_code.result code = ( "root =" f" E.{ir_view_item.tagName}({str(attributes_root)}," f" {child_root})" ) for line in code.split("\n"): cw.emit(line) cw.emit("content = ET.tostring(root, pretty_print=True)") cw.emit() cw.emit("cw = CodeWriter()") cw.emit( 'for line in content.decode("utf-8").split("\\n"):' ) with cw.indent(): cw.emit("with cw.indent():") with cw.indent(): cw.emit("cw.emit(line)") cw.emit("print(cw.render())") cw.emit(f"{fct_name}()") elif ir_view_item.nodeType == Node.COMMENT_NODE: comment_for_next_group = ir_view_item.data else: # print(ir_view_item) pass cw.emit('print("</odoo>")') output = cw.render() if config.output: with open(config.output, "w") as file: file.write(output) else: print(output)
def generate(self): for file_path, lst_info in self.dct_cb.items(): cw = CodeWriter() lst_header = [b for a in lst_info for b in a[0]] # Fix divergence import try: index_pos = lst_header.index("import odoo.http as http") lst_header.pop(index_pos) lst_header.append("from odoo import http") except: pass set_header = set(lst_header) lst_cb = [a[1] for a in lst_info] enable_logger = any([a[3] for a in lst_info]) lst_inherit_class = list(set([a[2] for a in lst_info])) if len(lst_inherit_class) > 1: _logger.error( "Cannot support multiple class in the same python file:" f" '{lst_inherit_class}', filepath: '{file_path}'") continue str_inherit_class = lst_inherit_class[0] for line in set_header: cw.emit(line) if enable_logger: cw.emit("import logging") cw.emit("_logger = logging.getLogger(__name__)") cw.emit( "class" f" {self._module.name.replace('_', ' ').title().replace(' ', '')}Controller({str_inherit_class}):" ) with cw.indent(): for cb in lst_cb: cb(self._module, cw) out = cw.render() l_model = out.split("\n") self._code_generator_data.write_file_lst_content( file_path, l_model)
except IndexError: example_usage('improper arguments') if '.vm' in input: if input in os.listdir(): vm_files = [input] else: example_usage('file not found') else: if input in os.getcwd(): vm_files = get_all_VM_files(os.getcwd()) if len(vm_files) == 0: example_usage('no vm files found') else: try: os.chdir(input) vm_files = get_all_VM_files(os.getcwd()) if len(vm_files) == 0: example_usage('no vm files in specified directory') except FileNotFoundError: example_usage('no such directory') # create a CodeWriter instance cw = CodeWriter(vm_files, output, boot) # perform translation cw.translate() # close the output of the CodeWriter cw.close()
def main(): # If there is an invalid number of arguments the program stops. if len(sys.argv) != 2: print("ERROR: Invalid number of arguments. Expected: file_name.vm ") exit(1) # The VM translator accepts directories or vm files to be translated into assembly files. elif not os.path.isdir(sys.argv[1]) and sys.argv[1][-3:] != ".vm": print("ERROR: Invalid argument. Expected: directory or vm file") exit(1) # Get the name of the file to be parsed from the arguments. input_file = sys.argv[1] if os.path.isdir(input_file): # Split the file path file_path = input_file.split("/") if input_file.endswith("/"): # Creates the code writer with the given directory code_writer = CodeWriter("{}/{}".format(input_file, file_path[-2])) read_directory(input_file, code_writer) code_writer.close() else: # Creates the code writer with the given directory code_writer = CodeWriter("{}/{}".format(input_file, file_path[-1])) read_directory(input_file, code_writer) code_writer.close() else: # Creates the code writer with the input file excluding the .vm part code_writer = CodeWriter(input_file[0:-3]) read_file(input_file, code_writer) code_writer.close()
class TestCodeWriter(TestCase): def setUp(self): self.cw = CodeWriter() def process_commands(self, commands): for _ in commands: command = VMCommand(_) command.parse_command() self.cw.process_command(command) def test_write_push_constant(self): """ test push constant [0-9]* """ # need to update SP, ie RAM[0] asm_command = ['@7', 'D=A', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] commands = ['push constant 7'] self.process_commands(commands) self.assertListEqual(asm_command, self.cw.assm) def test_write_two_push_constant(self): """ push contant [0-9]* twice in a row""" asm_command = ['@7', 'D=A', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] command = VMCommand('push constant 7') command.parse_command() self.cw.process_command(command) self.assertEqual(asm_command, self.cw.assm) command = VMCommand('push constant 8') command.parse_command() self.cw.process_command(command) asm_command = ['@8', 'D=A', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] self.assertEqual(asm_command, self.cw.assm) def test_write_add_command(self): """ test popping top two items off of stack, adding them, and putting the result back on the stack """ # put 7 & 8 on the stack to add commands = ['push constant 7', 'push constant 8', 'add'] self.process_commands(commands); assm_command = ['@SP', 'A=M-1', 'D=M', '@SP', 'M=M-1', '@SP', 'A=M-1', 'M=M+D'] self.assertListEqual(assm_command, self.cw.assm) def test_write_arithmetic_eq(self): """ test eq """ commands = ['push constant 20', 'push constant 20', 'eq'] self.process_commands(commands) assm_command = ['@SP', 'A=M-1', 'D=M', '@SP', 'M=M-1', '@SP', 'A=M-1', 'D=M-D', '@SP', 'M=M-1', '@L%s' % 0, 'D;JEQ', '@L%s' % 1, '(L%s)' % 1, '@SP', 'A=M', 'M=0', '@L%s' % 2, '0;JMP', '(L%s)' % 0, '@SP', 'A=M', 'M=-1', '@L%s' % 2, '0;JMP', '(L%s)' % 2, '@SP', 'M=M+1'] self.assertListEqual(assm_command, self.cw.assm) def test_neg(self): """ test taking negative of top item on stack """ commands = ['push constant 10'] self.process_commands(commands) command = VMCommand('neg') command.parse_command() self.cw.process_command(command) assm_command = ['@SP', 'A=M-1', 'MD=-M'] self.assertListEqual(assm_command, self.cw.assm) def test_pop_to_diff_stack(self): """ test popping to segment. 0 arg2 """ # push ten onto global stack commands=['push constant 10', 'pop local 0' ] self.process_commands(commands) # pop it off and it goes into local assm_command = ['@LCL', 'D=M', '@0', 'D=A+D', '@R5', 'M=D', '@SP', 'A=M-1', 'D=M', '@R5', 'A=M', 'M=D', '@SP', 'M=M-1'] self.assertListEqual(assm_command, self.cw.assm) def test_pop_non0_to_diff_stack(self): """ test pushing to segment. non 0 arg2 """ # push ten onto global stack commands = ['push constant 10', 'pop local 8'] self.process_commands(commands) assm_command = ['@LCL', 'D=M', '@8', 'D=A+D', '@R5', 'M=D', '@SP', 'A=M-1', 'D=M', '@R5', 'A=M', 'M=D', '@SP', 'M=M-1'] self.assertListEqual(assm_command, self.cw.assm) def test_pop_from_segment(self): """ test pushing from segment onto """ prep_commands=['push constant 12', 'pop local 1', 'push constant 21'] for _ in prep_commands: command = VMCommand(_) command.parse_command() command = VMCommand('push local 1') command.parse_command() self.cw.process_command(command) assm_command = ['@LCL', 'D=M', '@1', 'A=A+D', 'D=M', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] self.assertListEqual(assm_command, self.cw.assm) def test_pop_from_temp(self): """ test popping from TMP segment """ prep_commands = ['push constant 510'] for _ in prep_commands: command = VMCommand(_) command.parse_command() self.cw.process_command(command) command = VMCommand('pop temp 6') command.parse_command() self.cw.process_command(command) assm_command = ['@SP', 'A=M-1', 'D=M', '@11', 'M=D', '@SP', 'M=M-1'] self.assertListEqual(assm_command, self.cw.assm) def test_push_from_temp(self): """ test pushing from TMP segment """ prep_commands = ['push constant 510', 'pop temp 6', 'push constant 415'] for _ in prep_commands: command = VMCommand(_) command.parse_command() self.cw.process_command(command) command = VMCommand('push temp 6') command.parse_command() self.cw.process_command(command) assm_command = ['@11', 'D=M', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] self.assertListEqual(assm_command, self.cw.assm) def test_push_from_segment(self): """ test pushing from segment onto global stack """ commands = ['push constant 510', 'pop local 6', 'push local 6'] self.process_commands(commands) assm_command = ['@LCL', 'D=M', '@6', 'A=A+D', 'D=M', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] self.assertListEqual(assm_command, self.cw.assm) def test_pop_from_pointer(self): """ test popping to pointer """ commands = ['push constant 3040', 'pop pointer 0'] self.process_commands(commands) assm_command = ['@SP', 'A=M-1', 'D=M', '@3', 'M=D', '@SP', 'M=M-1'] self.assertListEqual(assm_command, self.cw.assm) def test_push_from_pointer(self): """ test pushing to pointer """ commands = ['push constant 3040', 'pop pointer 0', 'push pointer 0'] self.process_commands(commands) assm_command = ['@3', 'D=M', '@SP', 'A=M', 'M=D', '@SP', 'M=M+1'] self.assertListEqual(assm_command, self.cw.assm)
def main(): argument = sys.argv[1] if argument.endswith('.vm'): asm_filename = argument.replace('.vm', '.asm') asm_file = open(asm_filename, 'a') code_writer = CodeWriter(asm_file) open_vm_file(argument, code_writer) code_writer.close() else: if argument.endswith('/'): argument = argument[0:-1] foldername = os.path.basename(argument) asm_file = open('%s/%s.asm' % (argument, foldername), 'a') code_writer = CodeWriter(asm_file) code_writer.write_comment('write init') code_writer.write_init() files = glob.glob('%s/*.vm' % argument) for file in files: open_vm_file(file, code_writer) code_writer.close()
class jackVisitor(jackGrammarVisitor): """Clase que hereda del visitor para ir escribiendo en lenguaje de maquina virtual""" def __init__(self): """Inciializa una tabald e simbolos y un ecritor de codigo junto con variables auxiliares""" self.symbolTable = SymbolTable() self.contWhile = -1 self.contIf = -1 self.nombreClase = "" self.kindMetodo = "" self.nombreMetodo = "" self.vmWriter = CodeWriter() self.vmWriter.vm = "" self.nArgs = 0 def visitClasses(self, ctx): """Obtiene y guarda el nombre de la clase actualmente compilada""" self.nombreClase = ctx.children[1].children[0].getText() return self.visitChildren(ctx) def visitClassVarDec(self, ctx): """Guarda en la tabla de simbolos cada uno de los fields variables taticas declaradas """ kind = ctx.children[0].getText() tipo = ctx.children[1].children[0].getText() i = 2 while ctx.children[i].getText() != ';': name = ctx.children[i].getText() if name == ',': pass else: self.symbolTable.define(name, tipo, kind) i +=1 return self.visitChildren(ctx) def visitTypes(self, ctx): return self.visitChildren(ctx) def visitSubroutineDec(self, ctx): """Inicializa en la tabla de simbolos una subrotina, y en caso de se un metodo agrega this como parametro""" self.kindMetodo = ctx.children[0].getText() self.nombreMetodo = ctx.children[2].children[0].getText() self.symbolTable.startSubroutine() if self.kindMetodo == 'method': self.symbolTable.define('this', self.nombreMetodo, 'argument') return self.visitChildren(ctx) def visitParameterList(self, ctx): """Agrega a la tabla de simbolos de la subroutina cada uno de los parametros """ if ctx.getChildCount() > 0: tipo = ctx.children[0].children[0].getText() nombre = ctx.children[1].children[0].getText() self.symbolTable.define(nombre, tipo, 'argument') i = 2 while i < len(ctx.children)-1 and ctx.children[i].getText() != ')': tipo = ctx.children[i+1].getText() nombre = ctx.children[i+2].getText() self.symbolTable.define(nombre, tipo, 'argument') i+=3 return self.visitChildren(ctx) def visitSubroutineBody(self, ctx): """Despues de contar las variables locales escribe la funcion en maquina virtual y dependiendo del tipo de funcion hace los llamados, push y pop correspondientes""" i = 1 while ctx.children[i].children[0].getText() == "var": self.visit(ctx.children[i]) i += 1 funcion = self.nombreClase +'.'+ self.nombreMetodo numLcl = self.symbolTable.varCount('local') self.vmWriter.writeFunction(funcion, numLcl) if self.kindMetodo == 'constructor': numFields = self.symbolTable.varCount('field') self.vmWriter.writePush('constant', numFields) self.vmWriter.writeCall('Memory.alloc', 1) self.vmWriter.writePop('pointer', 0) elif self.kindMetodo == 'method': self.vmWriter.writePush('argument', 0) self.vmWriter.writePop('pointer', 0) while i < ctx.getChildCount(): self.visit(ctx.children[i]) i += 1 def visitVarDec(self, ctx): """Inicializa en la tabla de simbolos todas las variables locales de la subrutina para poder escribir la función""" tipo = ctx.children[1].children[0].getText() nombre = ctx.children[2].getText() self.symbolTable.define(nombre, tipo, 'local') i = 3 while ctx.children[i].getText() != ';': nombre = ctx.children[i].getText() if nombre == ',': pass else: self.symbolTable.define(nombre, tipo, 'local') i += 1 return self.visitChildren(ctx) """Llamados en los que no es necesario escribir codigo de VM""" def visitClassName(self, ctx): return self.visitChildren(ctx) def visitSubroutineName(self, ctx): return self.visitChildren(ctx) def visitVarName(self, ctx): return self.visitChildren(ctx) def visitStatements(self, ctx): return self.visitChildren(ctx) def visitStatement(self, ctx): return self.visitChildren(ctx) def visitLetStatement(self, ctx): """Realiza los push y pop necesarios para guardar un valor y asignarle una posiicon en memoria""" nombre = ctx.children[1].getText() tipo = self.symbolTable.kindOf(nombre) index = self.symbolTable.indexOf(nombre) if tipo == None: tipo = self.symbolTable.kindOf(nombre) index = self.symbolTable.indexOf(nombre) if ctx.children[2].getText() == '[': self.visit(ctx.children[3]) self.vmWriter.writePush(tipo,index) self.vmWriter.writeArithmetic('add') self.visit(ctx.children[6]) self.vmWriter.writePop('temp', 0) self.vmWriter.writePop('pointer', 1) self.vmWriter.writePush('temp', 0) self.vmWriter.writePop('that', 0) else: self.visit(ctx.children[3]) self.vmWriter.writePop(tipo,index) def visitIfStatement(self, ctx): """Escribe los labels necesarios para manejar el flujo del programa de a cuerdo a lo indicado por la expresión""" self.contIf += 1 cont = self.contIf self.visit(ctx.children[2]) self.vmWriter.writeIf('IF_TRUE' + str(cont)) self.vmWriter.writeGoto('IF_FALSE' + str(cont)) self.vmWriter.writeLabel('IF_TRUE' + str(cont)) self.visit(ctx.children[5]) if ctx.getChildCount() > 7 : if str(ctx.children[7]) == 'else': self.vmWriter.writeGoto('IF_END' + str(cont)) self.vmWriter.writeLabel('IF_FALSE' + str(cont)) self.visit(ctx.children[9]) self.vmWriter.writeLabel('IF_END' + str(cont)) else: self.vmWriter.writeLabel('IF_FALSE' + str(cont)) def visitWhileStatement(self, ctx): """Similar al if, escribe labels para que el flujo del programa se repita hasta que una condicion no se cumpla""" self.contWhile += 1 contW = self.contWhile self.vmWriter.writeLabel('WHILE_EXP' + str(contW)) self.visit(ctx.children[2]) self.vmWriter.writeArithmetic('not') self.vmWriter.writeIf('WHILE_END' + str(contW)) self.visit(ctx.children[5]) self.vmWriter.writeGoto('WHILE_EXP' + str(contW)) self.vmWriter.writeLabel('WHILE_END' + str(contW)) def visitDoStatement(self, ctx): """Hago el llamado y posteriormente vuelvo a la función de donde hice el llamado""" self.visitChildren(ctx) self.vmWriter.writePop('temp', 0) def visitReturnStatement(self, ctx): """Obtengo valor de retorno, si no hay, el valor de retorno es 0""" if ctx.children[1].getText() != ';': self.visit(ctx.children[1]) else: self.vmWriter.writePush('constant', 0) self.vmWriter.writeReturn() def visitExpression(self, ctx): """Separo al expresion por partes para irla compilando""" self.visit(ctx.children[0]) i = 2 while i < ctx.getChildCount(): self.visit(ctx.children[i]) self.visit(ctx.children[i-1]) i +=2 def visitTerm(self, ctx): """Determino el tipo de termino,si es un tipo de dato o un valor de un arreglo, dependiendo de esto obtengo su valor si está en la tabla de simbolos o lo busco en un arreglo o busco el siguiente etrmino con el que opera y lo guardo en memoria""" term = ctx.children[0].getText() if ctx.getChildCount() == 1: if term.isdigit(): self.vmWriter.writePush('constant', term) elif term.startswith('"'): term = term.strip('"') tam = len(term) self.vmWriter.writePush('constant', tam) self.vmWriter.writeCall('String.new', 1) for char in term: self.vmWriter.writePush('constant', ord(char)) self.vmWriter.writeCall('String.appendChar', 2) elif term in ['true', 'false', 'null', 'this']: self.visitChildren(ctx) elif term in self.symbolTable.subrutina.keys(): tipo = self.symbolTable.kindOf(term) index = self.symbolTable.indexOf(term) self.vmWriter.writePush(tipo,index) elif term in self.symbolTable.clase.keys(): tipo = self.symbolTable.kindOf(term) index = self.symbolTable.indexOf(term) self.vmWriter.writePush(tipo,index) else: self.visitChildren(ctx) else: var = ctx.children[0].getText() if ctx.children[1].getText() == '[': index = self.symbolTable.indexOf(var) segment = self.symbolTable.kindOf(var) self.visit(ctx.children[2]) self.vmWriter.writePush(segment, index) self.vmWriter.writeArithmetic('add') self.vmWriter.writePop('pointer', '1') self.vmWriter.writePush('that', '0') elif term == '(': self.visitChildren(ctx) elif term == '-': self.visit(ctx.children[1]) self.visit(ctx.children[0]) elif term == '~': self.visit(ctx.children[1]) self.visit(ctx.children[0]) def visitSubroutineCall(self, ctx): """Ubica la subrutina de acuerdo a la clase en la que se encuentre y escribe en VM el respectivo llamado con su paso de parametros""" nombre = ctx.children[0].children[0].getText() funcion = nombre args = 0 if ctx.children[1].getText() == '.': nombreSubrutina = ctx.children[2].children[0].getText() tipo = self.symbolTable.typeOf(nombre) if tipo != None: kind = self.symbolTable.kindOf(nombre) index = self.symbolTable.indexOf(nombre) self.vmWriter.writePush(kind, index) funcion = tipo + '.' + nombreSubrutina args += 1 else: funcion = nombre + '.' + nombreSubrutina elif ctx.children[1].getText() == '(': funcion = self.nombreClase + '.' + nombre args += 1 self.vmWriter.writePush('pointer', 0) self.visitChildren(ctx) args = args +self.nArgs self.vmWriter.writeCall(funcion, args) def visitExpressionList(self, ctx): """Evalua cada expresion indivudualmente""" self.nArgs = 0 if ctx.getChildCount() > 0: self.nArgs = 1 self.visit(ctx.children[0]) i = 2 while i < ctx.getChildCount(): self.visit(ctx.children[i]) self.visit(ctx.children[i-1]) self.nArgs += 1 i += 2 def visitOp(self, ctx): """Genera el comando de VM respectivo dependiendo del operador""" op = ctx.children[0].getText() if op == "+": self.vmWriter.writeArithmetic('add') elif op == "-": self.vmWriter.writeArithmetic('sub') elif op == "*": self.vmWriter.writeArithmetic('call Math.multiply 2') elif op == "/": self.vmWriter.writeArithmetic('call Math.divide 2') elif op == "&": self.vmWriter.writeArithmetic('and') elif op == "|": self.vmWriter.writeArithmetic('or') elif op == ">": self.vmWriter.writeArithmetic('gt') elif op == "<": self.vmWriter.writeArithmetic('lt') elif op == "=": self.vmWriter.writeArithmetic('eq') return self.visitChildren(ctx) def visitUnaryop(self, ctx): """Determina el comando de VM para cada operaodr unario""" op = ctx.children[0].getText() if op == "~": self.vmWriter.writeArithmetic('not') elif op == "-": self.vmWriter.writeArithmetic('neg') def visitKeywordconstant(self, ctx): """Escribe el comando de VM para poder hacer uso de una palabra reservada espcifica""" keyword = ctx.children[0].getText() if keyword == 'this': self.vmWriter.writePush('pointer', 0) elif keyword in ['false','null']: self.vmWriter.writePush('constant', 0) elif keyword == 'true': self.vmWriter.writePush('constant', 0) self.vmWriter.writeArithmetic('not') return self.visitChildren(ctx) def crearArchivo(self,path): """Abre el archivo .vm donde se escribirán lso comandos de máquina virtual""" filewrite = path.split('.jack') #Reemplazo el .jack con .xml si lo tiene filewritef = filewrite[0]+'.vm' #Sino le agrego el . codigoVM = self.vmWriter.vm archivo = filewritef try: file = open(archivo,'w') #Abro el file en modo escribir except FileNotFoundError: print('ERROR:No hay directorio existente para escribir') exit(1) file.write(codigoVM)
class VMTranslator: def __init__(self, src: str): self.asm_file, self.vm_files = self._parse_files(src) print("Translate to %s." % self.asm_file) self.code_writer = CodeWriter(self.asm_file) def translates(self): for vm_file in self.vm_files: self._translate(vm_file) def _parse_files(self, file_path: str) -> (str, list): if not os.path.exists(file_path): raise IOError("No such file or directory.") if os.path.isfile(file_path) and file_path.endswith(VM_EXT): asm_file = file_path.replace(VM_EXT, ASM_EXT) vm_files = [file_path] elif os.path.isdir(file_path): dir_path = file_path[:-1] if file_path[-1] == "/" else file_path asm_file = dir_path + "/" + os.path.basename(dir_path) + ASM_EXT vm_files = self._find_all_files_with_ext(dir_path, "vm") else: raise IOError("No such file or directory.") return asm_file, vm_files def _find_all_files_with_ext(self, dir_path: str, ext: str) -> list: ext_files = [] suffix = os.extsep + ext.lower() for cur_dir, _, files in os.walk(dir_path): for file in files: if file.lower().endswith(suffix): ext_files.append(os.path.join(cur_dir, file)) return ext_files def _translate(self, vm_file: str): parser = Parser(vm_file) self.code_writer.set_filename(vm_file) self.code_writer.write("// ---------- %s ----------" % self.code_writer.current_vm_file) while parser.next_line(): self.code_writer.write("// " + parser.command_line()) if parser.command_type() == "C_ARITHMETIC": self.code_writer.write_arithmetic(parser.argn(0)) elif parser.command_type() == "C_PUSH": self.code_writer.write_push(parser.argn(1), parser.argn(2)) elif parser.command_type() == "C_POP": self.code_writer.write_pop(parser.argn(1), parser.argn(2)) elif parser.command_type() == "C_LABEL": self.code_writer.write_label(parser.argn(1)) elif parser.command_type() == "C_GOTO": self.code_writer.write_goto(parser.argn(1)) elif parser.command_type() == "C_IF_GOTO": self.code_writer.write_if_goto(parser.argn(1)) elif parser.command_type() == "C_FUNCTION": self.code_writer.write_function(parser.argn(1), int(parser.argn(2))) elif parser.command_type() == "C_CALL": self.code_writer.write_call(parser.argn(1), int(parser.argn(2))) elif parser.command_type() == "C_RETURN": self.code_writer.write_return() self.code_writer.write("") # empty line self.code_writer.write("// ------------------------------\n")
"pointer": MemorySegType.M_POINTER, "temp": MemorySegType.M_TEMP } if __name__ == "__main__": if len(sys.argv) != 2: print(f"Usage: {sys.argv[0]} <{sys.argv[1]}>") files = [] if sys.argv[1].endswith('.vm'): files.append(sys.argv[1]) elif os.path.isdir(sys.argv[1]): files.extend(glob.glob("*.vm")) cw = CodeWriter(sys.argv[1].strip(".vm") + ".asm") print(f"Creating {sys.argv[1].strip('.vm') + '.asm'} ...") for f in files: p = Parser(f) cw.file_name = f while p.advance(): if p.command_type == CommandType.C_ARITHMETIC: cw.write_arithmetic(p.arg1()) elif p.command_type == CommandType.C_PUSH: cw.write_push_pop(CommandType.C_PUSH, segment_map[p.arg1()], p.arg2()) elif p.command_type == CommandType.C_POP: cw.write_push_pop(CommandType.C_POP, segment_map[p.arg1()], p.arg2())
def generate_python_init_file(self, cg_module): for component, lst_module in self._dct_import_dir.items(): init_path = os.path.join(component, "__init__.py") if not component: lst_module = [a for a in self._dct_import_dir.keys() if a] lst_module.sort() cw = CodeWriter() if cg_module.license == "AGPL-3": cw.emit("# License AGPL-3.0 or later" " (https://www.gnu.org/licenses/agpl)") cw.emit() elif cg_module.license == "LGPL-3": cw.emit("# License LGPL-3.0 or later" " (https://www.gnu.org/licenses/lgpl)") cw.emit() else: _logger.warning(f"License {cg_module.license} not supported.") if component: for module in lst_module: cw.emit(f"from . import {module}") elif lst_module: cw.emit(f"from . import {', '.join(lst_module)}") for extra_import in self._dct_extra_module_init_path.get( component, []): cw.emit(extra_import) self.write_file_str(init_path, cw.render())
def __init__(self, src: str): self.asm_file, self.vm_files = self._parse_files(src) print("Translate to %s." % self.asm_file) self.code_writer = CodeWriter(self.asm_file)
from os import listdir from parser import Parser from code_writer import CodeWriter # TODO: make this command line arguments FILENAME='StaticsTest' BASE = '/Users/plum/Desktop/codes/nand2tetris/projects/08/FunctionCalls/StaticsTest/' READ_ADDRESS = '{0}'.format(BASE) WRITE_ADDRESS = '{0}{1}.asm'.format(BASE, FILENAME) if __name__ == '__main__': c = CodeWriter(WRITE_ADDRESS) files = [f for f in listdir(READ_ADDRESS) if f.find('.vm') != -1] sys_init = files.index('Sys.vm') rest = [f for f in files if files.index(f) != sys_init] c.write_init() for filename in [files[sys_init]] + rest: # order matters # only parse .vm files if filename.find('.vm') != -1: c.set_filename(filename) p = Parser(BASE + filename) while p.has_more_lines(): p.advance() command = p.command_type() arg_1 = p.arg_1() arg_2 = p.arg_2() if command in ['C_PUSH', 'C_POP']: c.write_push_pop(command, arg_1, arg_2) if command == 'C_ARITHMETIC':
import os import sys from parser import Parser from code_writer import CodeWriter vm_file = sys.argv[1] writer = CodeWriter(vm_file + '.asm') path = '' if os.path.isdir(vm_file): path = vm_file vm_files = os.listdir(vm_file) else: vm_files = [vm_file] for vm_file in vm_files: print 'parsing:', vm_file with open(os.path.join(path, vm_file)) as f: writer.set_filename(vm_file.split('.')[0]) parser = Parser(f, writer) for instr in parser.parse(): print instr