#! /usr/bin/env python """ Usage: cent (-h|--help) cent -i FILE cent -c [-k|--keep-c] FILE Options: -h --help Print this help screen -i Run the interpreter -c Run the compiler -k --keep-c Keep the generated C file alongside the binary FILE The file to compile/interpret """ import os import subprocess import sys import tempfile from docopt import docopt from rply.errors import LexingError from centvrion.errors import CentvrionError from centvrion.lexer import Lexer from centvrion.parser import Parser from centvrion.ast_nodes import Program from centvrion.compiler.emitter import compile_program def main(): args = docopt(__doc__) file_path = args["FILE"] with open(file_path, "r", encoding="utf-8") as file_pointer: program_text = file_pointer.read() + "\n" lexer = Lexer().get_lexer() parser = Parser() try: tokens = lexer.lex(program_text) program = parser.parse(tokens) except LexingError as e: pos = e.source_pos char = program_text[pos.idx] if pos.idx < len(program_text) else "?" sys.exit(f"CENTVRION error: Invalid character {char!r} at line {pos.lineno}, column {pos.colno}") except SyntaxError as e: sys.exit(f"CENTVRION error: {e}") if isinstance(program, Program): if args["-i"]: try: program.eval() except CentvrionError as e: sys.exit(f"CENTVRION error: {e}") else: c_source = compile_program(program) runtime_dir = os.path.join( os.path.dirname(__file__), "centvrion", "compiler", "runtime" ) runtime_c = os.path.join(runtime_dir, "cent_runtime.c") iason_c = os.path.join(runtime_dir, "cent_iason.c") out_path = os.path.splitext(file_path)[0] if args["--keep-c"]: tmp_path = out_path + ".c" with open(tmp_path, "w") as f: f.write(c_source) subprocess.run( ["gcc", "-O2", tmp_path, runtime_c, iason_c, "-o", out_path, "-lcurl", "-lmicrohttpd", "-lm"], check=True, ) else: with tempfile.NamedTemporaryFile(suffix=".c", delete=False, mode="w") as tmp: tmp.write(c_source) tmp_path = tmp.name try: subprocess.run( ["gcc", "-O2", tmp_path, runtime_c, iason_c, "-o", out_path, "-lcurl", "-lmicrohttpd", "-lm"], check=True, ) finally: os.unlink(tmp_path) else: raise Exception("Output not of type 'Program'", type(program)) if __name__ == "__main__": main()