-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmet.py
170 lines (140 loc) · 3.79 KB
/
met.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
import re
import sys
import getopt
NOP = 0
CALL = 1
FALSE = 2
FFALSE = 3
FTRUE = 4
MATCH = 5
PRINT = 6
RETURN = 7
STOP = 8
THEN = 9
TRUE = 10
# must be in sync with calfe.py
ops = {
CALL: 'call',
FALSE: 'false',
FFALSE: 'fflag',
FTRUE: 'tflag',
MATCH: 'match',
PRINT: 'print',
RETURN: 'return',
STOP: 'stop',
THEN: 'then',
TRUE: 'true'}
ary = [
0, # no operand
1, # call addr
1, # false addr
0, # fflag
0, # tflag
1, # match item
1, # print item
0, # return
0, # stop
1, # then
1] # true addr
def no_comments(content):
ncontent = []
for line in content:
temp = re.sub('#.*', '', line)
ncontent.append(temp)
return ncontent
# no comments and other stuff
def prepare(content):
content = no_comments(content)
# no new lines
content = [' '.join(line.split()) for line in content]
# no white space
content = [line for line in content if line.strip()]
# group and "tokenize"
content = [line.split() for line in content if line]
return content
# replace the corresponing opcodes with numbers,
# and add arguments
def parse(line):
# check for command in ops .. first item in line
val = [i for i in ops if ops[i] == line[0]]
# if command not empty
if (val != []):
nline = []
i = val[0]
code = int(i) # convert command to it's int
ar = ary[i] # important if ary > 0
nline.append(code) # add command to list
if (ar == 1):
nline.append(line[1]) # add arg as is to list
return nline
else:
# don't touch
return line
# assemble binary
def assemble(inputfile, outputfile, verbose):
# read in file
with open(inputfile) as f:
content = f.readlines()
# prep
content = prepare(content)
# parse
ncontent = []
for item in range(len(content)):
line = content[item]
line = parse(line)
ncontent.append(line)
content = ncontent
if verbose:
print("parsed:", content)
# hunt for labels
ncontent = []
labels = {} # a dictionary of labels
offset = 0 # begin at address zero
for item in [val for sublist in content for val in sublist]:
islabel = (str(item)[-1] == ':') # ex. START:
if islabel:
matchlabel = (':' + item[:-1])
labels[matchlabel] = offset # ex. :START
else:
offset = offset + 1
ncontent.append(item)
# replace labels with their offset
ncontent = [labels[token] if token in labels else token for token in ncontent]
if verbose:
print("no labels:", ncontent)
# stringify the numbers for output
final = [str(int) for int in ncontent]
final = ','.join(final)
if verbose:
print("out to file:", final)
with open(outputfile, "w") as f:
f.write(final)
f.close()
return final
# call with parsing of args to assembler
def main(argv):
inputfile = ''
outputfile = ''
verbose = 0
try:
opts, args = getopt.getopt(argv,"vhi:o:",["ifile=","ofile="])
except getopt.GetoptError:
print('met.py -i <inputfile> -o <outputfile>')
sys.exit(2)
for opt, arg in opts:
if opt == '-v':
verbose = 1
if opt == '-h':
print('usage: met.py -i <inputfile> -o <outputfile>')
sys.exit()
elif opt in ("-i", "--ifile"):
inputfile = arg
elif opt in ("-o", "--ofile"):
outputfile = arg
if verbose == 1:
print("assembling ..")
assemble(inputfile, outputfile, verbose)
if verbose == 1:
print("done.")
if __name__ == "__main__":
main(sys.argv[1:])