def compiler(showSource, input_file, output_file): """This function goes through the classic phases of a modern compiler, each phase organized in its own module. The phases are: parsing: handled using the ply package - the parser module includes a lexer, and it builds an abstract syntax tree (AST). symbol collection: collects function, parameter, and variables names, and stores these in a symbol table. code generation: from the AST and symbol table, code is produced in an intermediate representation, quite close to the final assembler code. emit: the slightly abstract intermediate code is transformed to assembler code. """ # Read and verify ASCII input: encodingError = False try: if input_file: with open(input_file) as f: text = f.read() else: text = sys.stdin.read() try: text.encode("ascii") except UnicodeEncodeError: # Check for non-ascii encodingError = True except UnicodeDecodeError: # Check for unicode encodingError = True if encodingError: error_message("Set-Up", "The input is not in ASCII.", 1) # Parse input text: parser.parse(text) # the_program is the resulting AST: if interfacing_parser.parsing_error: exit() the_program = interfacing_parser.the_program if showSource: # Pretty print program: pp = ASTPrettyPrinterVisitor() the_program.accept(pp) return pp.getPrettyProgram() else: # Collect names of functions, parameters, and local variables: symbols_collector = ASTSymbolVisitor() the_program.accept(symbols_collector) symbol_table = symbols_collector.getSymbolTable() # Type check use of functions, parameters, and local variables: type_checker = ASTTypeCheckingVisitor(symbol_table) the_program.accept(type_checker) # Assign unique labels to functions: pre_intermediate_code_generator = ASTPreCodeGenerationVisitor() the_program.accept(pre_intermediate_code_generator) # Generate intermediate code: intermediate_code_generator = ASTCodeGenerationVisitor( symbol_table, pre_intermediate_code_generator.getLabelsGenerator()) the_program.accept(intermediate_code_generator) intermediate_code = intermediate_code_generator.get_code() # Emit the target code: emitter = Emit(intermediate_code, pre_intermediate_code_generator.getLabelsGenerator()) emitter.emit() code = emitter.get_code() return code