Files
centvrion/cent
2026-04-22 11:11:58 +02:00

83 lines
2.3 KiB
Python
Executable File

#! /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}")
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_c = os.path.join(
os.path.dirname(__file__),
"centvrion", "compiler", "runtime", "cent_runtime.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, "-o", out_path, "-lcurl", "-lmicrohttpd"],
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, "-o", out_path, "-lcurl", "-lmicrohttpd"],
check=True,
)
finally:
os.unlink(tmp_path)
else:
raise Exception("Output not of type 'Program'", type(program))
if __name__ == "__main__":
main()