-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathpycer.py
More file actions
104 lines (83 loc) · 2.6 KB
/
Copy pathpycer.py
File metadata and controls
104 lines (83 loc) · 2.6 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
# Commandline Interface for PyCer Compiler
import argparse, os, re
from io import StringIO
from py2c.bytecode_walker import translate
from py2c.translator_c import TranslatorC
from py2c.chelpers import cpprelude
def gen_arg_parser() -> argparse.ArgumentParser:
"""
Generate an argument parser for the 'pycer' command-line tool.
Returns:
An instance of the ArgumentParser class.
"""
parser = argparse.ArgumentParser(
prog='pycer',
description='Python to C Compiler'
)
parser.add_argument(
'File',
metavar='file',
type=str,
help="The File to compile"
)
parser.add_argument(
"-S",
"--source",
action="store_true",
help="only Compiles Python to C source code"
)
parser.add_argument(
"-v",
"--version",
action="version",
version="v1.0.0",
help="shows version info of PyCer"
)
parser.add_argument(
"cflags",
nargs=argparse.REMAINDER,
help="Flags to the C compiler"
)
return parser
def translate2C(source_code: str) -> str:
"""
Translates the given source code using a TranslatorC object.
Args:
source_code: The source code to be translated.
Returns:
The translated code as a string.
"""
file_stdout = StringIO()
translator = TranslatorC(save_to=file_stdout)
translate(translator, source_code)
return file_stdout.getvalue()
def post_process(py2c_src: str) -> str:
"""
Remove the leading whitespace before the string "c" in the given Python to C source code.
Args:
py2c_src (str): The Python to C source code.
Returns:
str: The modified Python to C source code.
"""
pattern = r"([ ]*)\"c\s*(.*?)\";"
result = re.sub(pattern, r"\1\2;", py2c_src, count=0)
pattern = r"/\*\s*c\s*(.*?)\s*\*/"
result = re.sub(pattern, r"\1\n", result, flags=re.DOTALL, count=0)
result = "extern \"C\" {\n" + result + "\n}\n"
return cpprelude + result
if __name__ == "__main__":
args = gen_arg_parser().parse_args()
cfname = args.File[:-3] + '.cpp'
cflags = ' '.join(args.cflags)
cfname = f"_{cfname}" if not args.source else cfname
with open(args.File) as f:
source_code = f.read()
with open(cfname, 'w') as f:
py2c_src = translate2C(source_code)
py2c_src = py2c_src.replace("PTR", "*")
f.write(post_process(py2c_src))
if not args.source:
if os.system(f"g++ {cfname} -o {args.File[:-3]} {cflags}") != 0:
os.remove(cfname)
exit(-1)
os.remove(cfname)