-
-
Notifications
You must be signed in to change notification settings - Fork 88
/
Copy pathsimc.py
147 lines (113 loc) · 5.12 KB
/
simc.py
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# Import sys, os and pprint module
import sys
import os
import pprint
# Module to import global helpers
from .global_helpers import error
# Module to import Symbol Table class
from .symbol_table import SymbolTable
# Module for using lexical analyzer
from .lexical_analyzer import LexicalAnalyzer
# Module for using parser
from .parser.simc_parser import parse
# Module for using compiler
from .compiler import compile
from .scope_resolve import ScopeResolver
def run():
filename = ""
pretty_printer = pprint.PrettyPrinter(indent=4)
# Check if filepath is provided or not
if len(sys.argv) >= 2:
filename = sys.argv[1]
# Check if extension of file is correct or not
if "." not in filename or filename.split(".")[-1] != "simc":
error("Incorrect file extension", -1)
else:
error("Please provide simc file path", -1)
# Get the filename of c file to be generated
c_filename = "".join(filename.split(".")[:-1]) + ".c"
# Create symbol table
table = SymbolTable()
# Get tokens and list of modules from source code
lexical_analyzer = LexicalAnalyzer(filename, table)
tokens, module_source_paths = lexical_analyzer.lexical_analyze()
scope_resolver = ScopeResolver(tokens_list=tokens, symbol_table=table)
tokens, table = scope_resolver.resolve_scope(module_name="main")
# Get tokens for modules
all_module_tokens = {}
if len(module_source_paths) > 0:
for module_source_path in module_source_paths:
module_name = os.path.basename(module_source_path).split(".")[0]
lexical_analyzer.update_filename(module_source_path)
all_module_tokens[module_name], _ = lexical_analyzer.lexical_analyze()
scope_resolver.swap_tokens_and_table(
tokens_list=all_module_tokens[module_name], table=table
)
all_module_tokens[module_name], table = scope_resolver.resolve_scope(
module_name=module_name
)
# Option to check out tokens
if len(sys.argv) > 2 and sys.argv[2] == "token":
# Print source code tokens
for token in tokens:
print(token)
# Print module tokens
for module_name, module_tokens in all_module_tokens.items():
print("\n---Tokens for module " + module_name + "---")
for token in module_tokens:
print(token)
# Option to check symbol table after lexical analysis
if len(sys.argv) > 2 and sys.argv[2] == "table_after_lexing":
# print(table)
pretty_printer.pprint(table.symbol_table)
# Parse the modules first as these function definitions will be important during source parsing
all_module_opcodes = {}
for module_name, module_tokens in all_module_tokens.items():
all_module_opcodes[module_name] = parse(module_tokens, table)
# Get opcodes for source code from parser
op_codes = parse(tokens, table)
# Remove opcodes of unused functions from modules
all_module_opcodes_pruned = {}
for module_name, module_opcodes in all_module_opcodes.items():
all_module_opcodes_pruned[module_name] = []
i = 0
# Loops through all the opcodes of specific module and checks for functions which weren't called from source code
while i < len(module_opcodes):
if module_opcodes[i].type == "func_decl":
func_name = module_opcodes[i].val.split("---")[0].strip()
func_symbol_table_val = table.symbol_table.get(
table.get_by_symbol(func_name)
)
func_ret_type = func_symbol_table_val[1]
# Skip all functions whose return type is not_known meaning they weren't called
if func_ret_type == "not_known" or type(func_ret_type) == list:
beg_idx = i
while module_opcodes[i].type != "scope_over":
i += 1
else:
all_module_opcodes_pruned[module_name].append(module_opcodes[i])
else:
all_module_opcodes_pruned[module_name].append(module_opcodes[i])
i += 1
# Option to check out opcodes
if len(sys.argv) > 2 and sys.argv[2] == "opcode":
# Print source code opcodes
for op_code in op_codes:
print(op_code)
# Print module opcodes
for module_name, module_opcodes in all_module_opcodes_pruned.items():
print("\n---OpCodes for module " + module_name + "---")
for op_code in module_opcodes:
print(op_code)
# Option to check symbol table after parsing
if len(sys.argv) > 2 and sys.argv[2] == "table_after_parsing":
# print(table)
pretty_printer.pprint(table.symbol_table)
# Compile to C code
compile(op_codes, c_filename, table)
# Compile the module functions, this can be done in any order
for module_name, module_opcodes in all_module_opcodes_pruned.items():
module_c_filename = module_name + ".h"
compile(module_opcodes, module_c_filename, table)
print("\033[92mC code generated at %s!" % c_filename, end="")
print(" \033[m")