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")
76 elseif (_match(l
,"^|%s*[Ll][Ee][Tt]%s*(%w+)%s*=%s*(.-)%s*$"))
78 local var
, val
= _match(l
, "^|%s*[Ll][Ee][Tt]%s*(%w+)%s*=%s*(.-)%s*$")
79 prog
= prog
.. _fmt("ENV.%s = ENV:handleExpr(%q, %q, %d)\n", var
, val
, l
, lineno
)
82 print(lineno
.. ": illegal commandline "..l
)
84 elseif _match(l
,"^%s*$") then
87 prog
= prog
.. _fmt("ENV:handleLine(%q, %d)",l
, lineno
) .. "\n"
91 if (#progstats
.scopes
> 0) then
93 print(lineno
.. ": not all scopes have been closed")
95 if errors
then return end
96 progcode
= loadstring(prog
)
98 print("cannot compile program")
102 function ENV
.handleLine(self
, line
, lineno
)
103 local function replacer(expr
)
104 local repfnc
= loadstring("return "..expr
)
107 print(lineno
.. ": illegal expression "..expr
)
110 _setfenv(repfnc
, self
)
111 return repfnc() or ""
114 local function filter(expr
)
115 local repfnc
= loadstring("return "..expr
)
118 print(lineno
.. ": illegal expression "..expr
)
121 _setfenv(repfnc
, self
)
122 return repfnc() and "" or "??"
125 line
= _gsub(line
, "$(%b())", replacer
)
127 if _match(line
, "^(%d+):") then
128 local m
= _match(line
, "^(%d+):")
129 if m
~= "32" and m
~= "64" then
131 print(lineno
.. ": illegal architecture "..m
)
134 if self
.arch
~= m
then return end
135 line
= _sub(line
, #m
+ 2)
138 line
= _gsub(line
, "%?(%b())", filter
)
139 if (_sub(line
,1,2) == "??") then return end
140 if self
.tgt
== "nasm" then
141 line
= _gsub(line
, "%b{}", "")
142 line
= _gsub(line
, "[<>]", "")
144 if self
.tgt
== "jitcs" then
145 line
= _gsub(line
, "%b<>", "")
146 line
= _gsub(line
, "[{}]", "")
151 function ENV
.handleExpr(self
, line
, lineno
)
152 local function replacer(expr
)
153 local repfnc
= loadstring("return "..expr
)
156 print(lineno
.. ": illegal expression "..expr
)
159 _setfenv(repfnc
, self
)
160 return repfnc() or ""
163 line
= _gsub(line
, "$(%b())", replacer
)
166 function ENV
.write(self
, line
)
167 if self
.tgt
== "jitcs" and self
.lst
and _sub(line
,1,1) ~= ":" and not _match(line
,"^%s*$") then
168 self
.lstpos
= self
.lstpos
+ 1
169 line
= line
.. " ==> " .. (self
.lst
[self
.lstpos
] or "")
172 self
.file
:write(line
)
173 self
.file
:write("\n")
179 return tonumber(Y
) == 64 and "64:" or ""
182 if Y
== "DEF" then return "" end
186 if M
== "S" then return "32" end
187 if M
== "D" then return "64" end
190 function ENV
.MVHSZ(Y
, D
)
191 if tonumber(Y
) == 128 or tonumber(Y
) == 256 or tonumber(Y
) == 512 then
192 return tostring(tonumber(Y
) / (D
and tonumber(D
) or 2))
194 print("VSZ error", Y
)
198 if Y
== "DEF" then return "R" end
199 if tonumber(Y
) == 8 then return "B" end
200 if tonumber(Y
) == 16 then return "H" end
201 if tonumber(Y
) == 32 then return "W" end
202 if tonumber(Y
) == 64 then return "D" end
203 print("RSZ error", Y
)
207 if tonumber(Y
) == 128 then return "X" end
208 if tonumber(Y
) == 256 then return "Y" end
209 if tonumber(Y
) == 512 then return "Z" end
210 print("VSZ error", Y
)
214 if tonumber(Y
) == 128 then return "X" end
215 if tonumber(Y
) == 256 then return "X" end
216 if tonumber(Y
) == 512 then return "Y" end
217 print("VHSZ error", Y
)
220 function ENV
.VOSZ(Y
,N
)
221 if tonumber(Y
) == tonumber(N
) then return "" end
225 -- if Y == "DEF" then return "ERROR" end
226 if tonumber(Y
) == 8 then return "B" end
227 if tonumber(Y
) == 16 then return "W" end
228 if tonumber(Y
) == 32 then return "D" end
229 if tonumber(Y
) == 64 then return "Q" end
232 function ENV
.NASMSZ(Y
)
233 if Y
== "DEF" then Y
= ENV
.arch
end
234 if tonumber(Y
) == 8 then return "byte" end
235 if tonumber(Y
) == 16 then return "word" end
236 if tonumber(Y
) == 32 then return "dword" end
237 if tonumber(Y
) == 64 then return "qword" end
238 if tonumber(Y
) == 128 then return "oword" end
239 if tonumber(Y
) == 256 then return "yword" end
242 function ENV
.MAX(A
,B
)
243 if A
== "DEF" then A
= ENV
.arch
end
244 if B
== "DEF" then B
= ENV
.arch
end
245 return tonumber(A
) > tonumber(B
) and A
or B
247 ENV
.RNAME_Table_R2R
= {ECX
= "RCX", EAX
= "RAX", EBX
= "RBX", EDX
= "RDX",
248 YMM0
= "XMM0", YMM1
= "XMM1", YMM2
= "XMM2", YMM3
= "XMM3"}
249 ENV
.RNAME_Table_R2N
= {
250 RAX
= {["8"] = "AL", ["16"] = "AX", ["32"] = "EAX", ["64"]= "RAX"},
251 RBX
= {["8"] = "BL", ["16"] = "BX", ["32"] = "EBX", ["64"]= "RBX"},
252 RCX
= {["8"] = "CL", ["16"] = "CX", ["32"] = "ECX", ["64"]= "RCX"},
253 RDX
= {["8"] = "DL", ["16"] = "DX", ["32"] = "EDX", ["64"]= "RDX"},
255 function ENV
.RCONST(I
, Y
)
256 if Y
== "DEF" then Y
= ENV
.arch
end
257 return math
.mod(I
, math
.pow(2,math
.min(tonumber(Y
),32)))
259 function ENV
.RNAME(R
, SZ
)
260 if SZ
== "DEF" then SZ
= ENV
.arch
end
261 R
= ENV
.RNAME_Table_R2R
[R
] or R
262 return ENV
.RNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
264 function ENV
.RNAMEDEF(R
, SZ
)
265 if SZ
== "DEF" then SZ
= 64 end
266 R
= ENV
.RNAME_Table_R2R
[R
] or R
267 return ENV
.RNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
269 ENV
.VNAME_Table_R2N
= {
270 XMM0
= {["64"] = "XMM0", ["128"] = "XMM0", ["256"] = "YMM0", ["512"] = "ZMM0"},
271 XMM1
= {["64"] = "XMM1", ["128"] = "XMM1", ["256"] = "YMM1", ["512"] = "ZMM1"},
272 XMM2
= {["64"] = "XMM2", ["128"] = "XMM2", ["256"] = "YMM2", ["512"] = "ZMM2"},
273 XMM3
= {["64"] = "XMM3", ["128"] = "XMM3", ["256"] = "YMM3", ["512"] = "ZMM3"},
274 XMM4
= {["64"] = "XMM4", ["128"] = "XMM4", ["256"] = "YMM4", ["512"] = "ZMM4"},
276 function ENV
.VNAME(R
, SZ
)
277 if SZ
== "DEF" then SZ
= ENV
.arch
end
278 R
= ENV
.RNAME_Table_R2R
[R
] or R
279 return ENV
.VNAME_Table_R2N
[R
][tostring(SZ
)] or "ERROR"
281 function ENV
.VHNAME(R
, SZ
)
282 if SZ
== "DEF" then SZ
= ENV
.arch
end
283 R
= ENV
.RNAME_Table_R2R
[R
] or R
284 return ENV
.VNAME_Table_R2N
[R
][tostring(tonumber(SZ
)/2)] or "ERROR"
287 local function readnasmlist(v
)
289 for l
in _gmatch(readfile(v
), "([^\r\n]*)[\r\n]") do
290 local line
, addr
, opcodes
, cmd
= _match(l
,
291 "^([ %d][ %d][ %d][ %d][ %d][ %d])"
292 .. " ([ %x][ %x][ %x][ %x][ %x][ %x][ %x][ %x])"
295 if opcodes
and #opcodes
> 0 then result
[#result
+ 1] = opcodes
end
300 ENV
.arch
= tostring(N
)
303 _setfenv(progcode
, ENV
)
304 if ALG
== "ins2nasm" then
305 ENV
.file
= _open(nasmfile
, "w")
307 ENV
:write(" bits " .. ENV
.arch
)
309 ENV
:write("%define RAX EAX")
310 ENV
:write("%define RBX EBX")
311 ENV
:write("%define RCX ECX")
312 ENV
:write("%define RDX EDX")
317 elseif ALG
== "nasm2as" then
318 local lst
= readnasmlist(nasmlstfile
)
320 ENV
.file
= _open(asfile
, "w")
322 ENV
:write("<== test")
323 ENV
:write("@fun: void -> void")
324 ENV
:write("@strategy: direct")
330 if ENV
.lstpos
~= #ENV
.lst
then
331 print("length difference between nasm and jitcs versions ("..N
.."bit)")