-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathprogram.py
More file actions
107 lines (79 loc) · 2.82 KB
/
program.py
File metadata and controls
107 lines (79 loc) · 2.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import argparse
import subprocess
import json
from dataclasses import dataclass
from pathlib import Path
from typing import Self
from compiler import generate_assembly
from lexer import Lexer
from parser import Parser, Program
from tokens import Token, TokenEncoder
from collections.abc import Callable
class pipe[T, U]:
def __init__(self, func: Callable[[T], U]):
self.func = func
def __ror__(self, value: T) -> U:
return self.func(value)
def lex(source: str):
return Lexer(source).lex()
def parse(tokens: list[Token]) -> Program:
return Parser(tokens).parse_program()
def assemble(program: Program) -> list[str]:
return generate_assembly(program)
@dataclass
class ProgramArgs:
filepath: Path
compile: bool
debug_dump_tokens: bool
@classmethod
def from_args(cls, args: argparse.Namespace) -> Self:
filepath = Path(args.file)
do_compile = bool(args.compile)
do_dump_tokens = bool(args.debug_dump_tokens)
return cls(filepath, do_compile, do_dump_tokens)
def get_filename(self) -> str:
return self.filepath.stem
def get_assembly_filename(self) -> str:
return f"{self.get_filename()}.s"
def run(options: ProgramArgs) -> None:
with open(parsed_args.filepath, "r") as fp:
program_source = fp.read()
tokens = program_source | pipe(lex)
assembly = tokens | pipe(parse) | pipe(generate_assembly)
script_dir = Path(__file__).parent
# Create the assembly file in the same directory
assembly_filepath = script_dir / parsed_args.get_assembly_filename()
with open(assembly_filepath, "w") as fp:
for line in assembly:
fp.write(line)
fp.write("\n")
if options.compile:
command: list[str | Path] = [
"clang",
"-Wall",
"-Wextra",
assembly_filepath,
"-o",
options.get_filename(),
]
try:
result = subprocess.run(command, check=True, capture_output=True, text=True)
print("Compilation successful:")
print(result.stdout)
except subprocess.CalledProcessError as e:
print(f"Compilation failed with error code {e.returncode}:")
print(e.stderr)
if parsed_args.debug_dump_tokens:
tokens_json = json.dumps(tokens, cls=TokenEncoder)
print(tokens_json)
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument("file", help="Path to the source file.", type=str)
arg_parser.add_argument(
"--compile", help="Compile instead of just generating the assembly.", action="store_true"
)
arg_parser.add_argument(
"--debug-dump-tokens", help="Debug: Dump the internal token representation to stdout", action="store_true"
)
args = arg_parser.parse_args()
parsed_args = ProgramArgs.from_args(args)
run(parsed_args)