1 local _setfenv
, _ipairs
= setfenv
, ipairs
3 local _match
, _gmatch
, _fmt
= string.match
, string.gmatch
, string.format
4 local _gsub
, _sub
= string.gsub, string.sub
5 local _exec
= os
.execute
7 local function readfile(n
)
9 local ctnt
= f
:read("*a")
14 local validModes
= {ins2nasm32
= true, ins2nasm64
= true, nasm2as32
= true, nasm2as64
= true}
16 local MODE
, insfile
, p1
, p2
= ...
17 MODE
= string.lower(MODE
or "")
18 assert(validModes
[MODE
], "mode missing")
19 assert(insfile
, "insfile missing")
20 local nasmfile
, nasmlstfile
, asfile
21 if MODE
== "ins2nasm32" or MODE
== "nasm2as32" then
26 if MODE
== "ins2nasm32" or MODE
== "ins2nasm64" then
29 assert(nasmfile
, ".nasm file not given")
32 nasmlstfile
, asfile
= p1
, p2
33 assert(nasmlstfile
and asfile
, ".lst and .as file not given")
36 local prog
, progcode
= ""
37 local progstats
= { scopes
= {} }
40 for l
in _gmatch(readfile(insfile
), "([^\r\n]*)[\r\n]") do
42 if _match(l
, "^|") then
43 if (_match(l
, "^|%s*[Ff][Oo][Rr]%s*(%w+)%s*=%s*%[([^]]-)%]%s*[Dd][Oo]%s*$"))
45 local var
, list
= _match(l
, "^|%s*[Ff][Oo][Rr]%s*(%w+)%s*=%s*%[([^]]-)%]%s*[Dd][Oo]%s*$")
46 local list2
, list3
= {}, nil
47 for e
in _gmatch(list
, "([^,]+)") do
48 local e2
= _match(e
, "^%s*(%S+)%s*$")
50 list2
[#list2
+ 1] = e2
;
51 list3
= (list3
and (list3
..", ") or "").._fmt("%q", e2
)
55 local sn
= #progstats
.scopes
56 progstats
.scopes
[sn
+1] = {type = "for", start
= lineno
,
57 var
= var
, list
= list2
}
59 prog
= prog
.. "for k"..sn
..",v"..sn
.." in ipairs({"..list3
.."}) do\n"
60 prog
= prog
.. " ENV."..var
.." = v"..sn
.."\n"
63 print(lineno
.. ": illegal list in for statement")
67 elseif (_match(l
,"^|%s*[Ee][Nn][Dd][Ff][Oo][Rr]%s*$")) then
68 local sn
= #progstats
.scopes
69 if (sn
> 0 and progstats
.scopes
[sn
].type == "for") then
70 progstats
.scopes
[sn
] = nil
71 prog
= prog
.. "end\n"
74 print(lineno
.. ": endfor without for scope")
78 print(lineno
.. ": illegal commandline "..l
)
80 elseif _match(l
,"^%s*$") then
83 prog
= prog
.. _fmt("ENV:handleLine(%q, %d)",l
, lineno
) .. "\n"
87 if (#progstats
.scopes
> 0) then
89 print(lineno
.. ": not all scopes have been closed")
91 if errors
then return end
92 progcode
= loadstring(prog
)
94 print("cannot compile program")
98 function ENV
.handleLine(self
, line
, lineno
)
99 local function replacer(expr
)
100 local repfnc
= loadstring("return "..expr
)
103 print(lineno
.. ": illegal expression "..expr
)
106 _setfenv(repfnc
, self
)
107 return repfnc() or ""
110 local function filter(expr
)
111 local repfnc
= loadstring("return "..expr
)
114 print(lineno
.. ": illegal expression "..expr
)
117 _setfenv(repfnc
, self
)
118 return repfnc() and "" or "??"
121 line
= _gsub(line
, "$(%b())", replacer
)
123 if _match(line
, "^(%d+):") then
124 local m
= _match(line
, "^(%d+):")
125 if m
~= "32" and m
~= "64" then
127 print(lineno
.. ": illegal architecture "..m
)
130 if self
.arch
~= m
then return end
131 line
= _sub(line
, #m
+ 2)
134 line
= _gsub(line
, "%?(%b())", filter
)
135 if (_sub(line
,1,2) == "??") then return end
136 if self
.tgt
== "nasm" then
137 line
= _gsub(line
, "%b{}", "")
138 line
= _gsub(line
, "[<>]", "")
140 if self
.tgt
== "jitcs" then
141 line
= _gsub(line
, "%b<>", "")
142 line
= _gsub(line
, "[{}]", "")
147 function ENV
.write(self
, line
)
148 if self
.tgt
== "jitcs" and self
.lst
then
149 self
.lstpos
= self
.lstpos
+ 1
150 line
= line
.. " ==> " .. (self
.lst
[self
.lstpos
] or "")
153 self
.file
:write(line
)
154 self
.file
:write("\n")
160 return tonumber(Y
) == 64 and "64:" or ""
163 if Y
== "DEF" then return "" end
167 if M
== "S" then return "32" end
168 if M
== "D" then return "64" end
171 function ENV
.MVHSZ(Y
, D
)
172 if tonumber(Y
) == 128 or tonumber(Y
) == 256 or tonumber(Y
) == 512 then
173 return tostring(tonumber(Y
) / (D
and tonumber(D
) or 2))
175 print("VSZ error", Y
)
179 if Y
== "DEF" then return "R" end
180 if tonumber(Y
) == 8 then return "B" end
181 if tonumber(Y
) == 16 then return "H" end
182 if tonumber(Y
) == 32 then return "W" end
183 if tonumber(Y
) == 64 then return "D" end
184 print("RSZ error", Y
)
188 if tonumber(Y
) == 128 then return "X" end
189 if tonumber(Y
) == 256 then return "Y" end
190 if tonumber(Y
) == 512 then return "Z" end
191 print("VSZ error", Y
)
195 if tonumber(Y
) == 128 then return "X" end
196 if tonumber(Y
) == 256 then return "X" end
197 if tonumber(Y
) == 512 then return "Y" end
198 print("VHSZ error", Y
)
201 function ENV
.VOSZ(Y
,N
)
202 if tonumber(Y
) == tonumber(N
) then return "" end
206 -- if Y == "DEF" then return "ERROR" end
207 if tonumber(Y
) == 8 then return "B" end
208 if tonumber(Y
) == 16 then return "W" end
209 if tonumber(Y
) == 32 then return "D" end
210 if tonumber(Y
) == 64 then return "Q" end
213 function ENV
.NASMSZ(Y
)
214 if Y
== "DEF" then Y
= ENV
.arch
end
215 if tonumber(Y
) == 8 then return "byte" end
216 if tonumber(Y
) == 16 then return "word" end
217 if tonumber(Y
) == 32 then return "dword" end
218 if tonumber(Y
) == 64 then return "qword" end
219 if tonumber(Y
) == 128 then return "oword" end
220 if tonumber(Y
) == 256 then return "yword" end
223 function ENV
.MAX(A
,B
)
224 if A
== "DEF" then A
= ENV
.arch
end
225 if B
== "DEF" then B
= ENV
.arch
end
226 return tonumber(A
) > tonumber(B
) and A
or B
228 ENV
.RNAME_Table_R2R
= {ECX
= "RCX", EAX
= "RAX", EBX
= "RBX", EDX
= "RDX",
229 YMM0
= "XMM0", YMM1
= "XMM1", YMM2
= "XMM2", YMM3
= "XMM3"}
230 ENV
.RNAME_Table_R2N
= {
231 RAX
= {["8"] = "AL", ["16"] = "AX", ["32"] = "EAX", ["64"]= "RAX"},
232 RBX
= {["8"] = "BL", ["16"] = "BX", ["32"] = "EBX", ["64"]= "RBX"},
233 RCX
= {["8"] = "CL", ["16"] = "CX", ["32"] = "ECX", ["64"]= "RCX"},
234 RDX
= {["8"] = "DL", ["16"] = "DX", ["32"] = "EDX", ["64"]= "RDX"},
236 function ENV
.RCONST(I
, Y
)
237 if Y
== "DEF" then Y
= ENV
.arch
end
238 return math
.mod(I
, math
.pow(2,math
.min(tonumber(Y
),32)))
240 function ENV
.RNAME(R
, SZ
)
241 if SZ
== "DEF" then SZ
= ENV
.arch
end
242 R
= ENV
.RNAME_Table_R2R
[R
] or R
243 return ENV
.RNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
245 function ENV
.RNAMEDEF(R
, SZ
)
246 if SZ
== "DEF" then SZ
= 64 end
247 R
= ENV
.RNAME_Table_R2R
[R
] or R
248 return ENV
.RNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
250 ENV
.VNAME_Table_R2N
= {
251 XMM0
= {["64"] = "XMM0", ["128"] = "XMM0", ["256"] = "YMM0", ["512"] = "ZMM0"},
252 XMM1
= {["64"] = "XMM1", ["128"] = "XMM1", ["256"] = "YMM1", ["512"] = "ZMM1"},
253 XMM2
= {["64"] = "XMM2", ["128"] = "XMM2", ["256"] = "YMM2", ["512"] = "ZMM2"},
254 XMM3
= {["64"] = "XMM3", ["128"] = "XMM3", ["256"] = "YMM3", ["512"] = "ZMM3"},
255 XMM4
= {["64"] = "XMM4", ["128"] = "XMM4", ["256"] = "YMM4", ["512"] = "ZMM4"},
257 function ENV
.VNAME(R
, SZ
)
258 if SZ
== "DEF" then SZ
= ENV
.arch
end
259 R
= ENV
.RNAME_Table_R2R
[R
] or R
260 return ENV
.VNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
262 function ENV
.VHNAME(R
, SZ
)
263 if SZ
== "DEF" then SZ
= ENV
.arch
end
264 R
= ENV
.RNAME_Table_R2R
[R
] or R
265 return ENV
.VNAME_Table_R2N
[R
][tostring(tonumber(SZ
)/2)] or "ERROR"
268 local function readnasmlist(v
)
270 for l
in _gmatch(readfile(v
), "([^\r\n]*)[\r\n]") do
271 local line
, addr
, opcodes
, cmd
= _match(l
,
272 "^([ %d][ %d][ %d][ %d][ %d][ %d])"
273 .. " ([ %x][ %x][ %x][ %x][ %x][ %x][ %x][ %x])"
276 if opcodes
and #opcodes
> 0 then result
[#result
+ 1] = opcodes
end
281 ENV
.arch
= tostring(N
)
284 _setfenv(progcode
, ENV
)
285 if ALG
== "ins2nasm" then
286 ENV
.file
= _open(nasmfile
, "w")
288 ENV
:write(" bits " .. ENV
.arch
)
290 ENV
:write("%define RAX EAX")
291 ENV
:write("%define RBX EBX")
292 ENV
:write("%define RCX ECX")
293 ENV
:write("%define RDX EDX")
298 elseif ALG
== "nasm2as" then
299 local lst
= readnasmlist(nasmlstfile
)
301 ENV
.file
= _open(asfile
, "w")
303 ENV
:write("<== test")
304 ENV
:write("@fun: void -> void")
305 ENV
:write("@strategy: direct")
311 if ENV
.lstpos
~= #ENV
.lst
then
312 print("length difference between nasm and jitcs versions ("..N
.."bit)")