diff options
author | David Walter Seikel | 2014-01-13 21:08:31 +1000 |
---|---|---|
committer | David Walter Seikel | 2014-01-13 21:08:31 +1000 |
commit | 637177eb1397ef1800027bccd50dbdc1af29a15b (patch) | |
tree | 3670a48303d05fceb8bf3ec4ee2901b72fe62d4d /libraries/luajit-2.0/dynasm/dynasm.lua | |
parent | Update Irrlicht to 1.8.1. Include actual change markers this time. lol (diff) | |
download | SledjHamr-637177eb1397ef1800027bccd50dbdc1af29a15b.zip SledjHamr-637177eb1397ef1800027bccd50dbdc1af29a15b.tar.gz SledjHamr-637177eb1397ef1800027bccd50dbdc1af29a15b.tar.bz2 SledjHamr-637177eb1397ef1800027bccd50dbdc1af29a15b.tar.xz |
Remove LuaJIT source, we can use packaged LuaJIT 2.0 release now.
Also some cleanups related to the other library removals.
Diffstat (limited to 'libraries/luajit-2.0/dynasm/dynasm.lua')
-rw-r--r-- | libraries/luajit-2.0/dynasm/dynasm.lua | 1076 |
1 files changed, 0 insertions, 1076 deletions
diff --git a/libraries/luajit-2.0/dynasm/dynasm.lua b/libraries/luajit-2.0/dynasm/dynasm.lua deleted file mode 100644 index 8ff9851..0000000 --- a/libraries/luajit-2.0/dynasm/dynasm.lua +++ /dev/null | |||
@@ -1,1076 +0,0 @@ | |||
1 | ------------------------------------------------------------------------------ | ||
2 | -- DynASM. A dynamic assembler for code generation engines. | ||
3 | -- Originally designed and implemented for LuaJIT. | ||
4 | -- | ||
5 | -- Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
6 | -- See below for full copyright notice. | ||
7 | ------------------------------------------------------------------------------ | ||
8 | |||
9 | -- Application information. | ||
10 | local _info = { | ||
11 | name = "DynASM", | ||
12 | description = "A dynamic assembler for code generation engines", | ||
13 | version = "1.3.0", | ||
14 | vernum = 10300, | ||
15 | release = "2011-05-05", | ||
16 | author = "Mike Pall", | ||
17 | url = "http://luajit.org/dynasm.html", | ||
18 | license = "MIT", | ||
19 | copyright = [[ | ||
20 | Copyright (C) 2005-2011 Mike Pall. All rights reserved. | ||
21 | |||
22 | Permission is hereby granted, free of charge, to any person obtaining | ||
23 | a copy of this software and associated documentation files (the | ||
24 | "Software"), to deal in the Software without restriction, including | ||
25 | without limitation the rights to use, copy, modify, merge, publish, | ||
26 | distribute, sublicense, and/or sell copies of the Software, and to | ||
27 | permit persons to whom the Software is furnished to do so, subject to | ||
28 | the following conditions: | ||
29 | |||
30 | The above copyright notice and this permission notice shall be | ||
31 | included in all copies or substantial portions of the Software. | ||
32 | |||
33 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
34 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
35 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
36 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | ||
37 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
38 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | ||
39 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
40 | |||
41 | [ MIT license: http://www.opensource.org/licenses/mit-license.php ] | ||
42 | ]], | ||
43 | } | ||
44 | |||
45 | -- Cache library functions. | ||
46 | local type, pairs, ipairs = type, pairs, ipairs | ||
47 | local pcall, error, assert = pcall, error, assert | ||
48 | local _s = string | ||
49 | local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub | ||
50 | local format, rep, upper = _s.format, _s.rep, _s.upper | ||
51 | local _t = table | ||
52 | local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort | ||
53 | local exit = os.exit | ||
54 | local io = io | ||
55 | local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr | ||
56 | |||
57 | ------------------------------------------------------------------------------ | ||
58 | |||
59 | -- Program options. | ||
60 | local g_opt = {} | ||
61 | |||
62 | -- Global state for current file. | ||
63 | local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch | ||
64 | local g_errcount = 0 | ||
65 | |||
66 | -- Write buffer for output file. | ||
67 | local g_wbuffer, g_capbuffer | ||
68 | |||
69 | ------------------------------------------------------------------------------ | ||
70 | |||
71 | -- Write an output line (or callback function) to the buffer. | ||
72 | local function wline(line, needindent) | ||
73 | local buf = g_capbuffer or g_wbuffer | ||
74 | buf[#buf+1] = needindent and g_indent..line or line | ||
75 | g_synclineno = g_synclineno + 1 | ||
76 | end | ||
77 | |||
78 | -- Write assembler line as a comment, if requestd. | ||
79 | local function wcomment(aline) | ||
80 | if g_opt.comment then | ||
81 | wline(g_opt.comment..aline..g_opt.endcomment, true) | ||
82 | end | ||
83 | end | ||
84 | |||
85 | -- Resync CPP line numbers. | ||
86 | local function wsync() | ||
87 | if g_synclineno ~= g_lineno and g_opt.cpp then | ||
88 | wline("# "..g_lineno..' "'..g_fname..'"') | ||
89 | g_synclineno = g_lineno | ||
90 | end | ||
91 | end | ||
92 | |||
93 | -- Dummy action flush function. Replaced with arch-specific function later. | ||
94 | local function wflush(term) | ||
95 | end | ||
96 | |||
97 | -- Dump all buffered output lines. | ||
98 | local function wdumplines(out, buf) | ||
99 | for _,line in ipairs(buf) do | ||
100 | if type(line) == "string" then | ||
101 | assert(out:write(line, "\n")) | ||
102 | else | ||
103 | -- Special callback to dynamically insert lines after end of processing. | ||
104 | line(out) | ||
105 | end | ||
106 | end | ||
107 | end | ||
108 | |||
109 | ------------------------------------------------------------------------------ | ||
110 | |||
111 | -- Emit an error. Processing continues with next statement. | ||
112 | local function werror(msg) | ||
113 | error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) | ||
114 | end | ||
115 | |||
116 | -- Emit a fatal error. Processing stops. | ||
117 | local function wfatal(msg) | ||
118 | g_errcount = "fatal" | ||
119 | werror(msg) | ||
120 | end | ||
121 | |||
122 | -- Print a warning. Processing continues. | ||
123 | local function wwarn(msg) | ||
124 | stderr:write(format("%s:%s: warning: %s:\n%s\n", | ||
125 | g_fname, g_lineno, msg, g_curline)) | ||
126 | end | ||
127 | |||
128 | -- Print caught error message. But suppress excessive errors. | ||
129 | local function wprinterr(...) | ||
130 | if type(g_errcount) == "number" then | ||
131 | -- Regular error. | ||
132 | g_errcount = g_errcount + 1 | ||
133 | if g_errcount < 21 then -- Seems to be a reasonable limit. | ||
134 | stderr:write(...) | ||
135 | elseif g_errcount == 21 then | ||
136 | stderr:write(g_fname, | ||
137 | ":*: warning: too many errors (suppressed further messages).\n") | ||
138 | end | ||
139 | else | ||
140 | -- Fatal error. | ||
141 | stderr:write(...) | ||
142 | return true -- Stop processing. | ||
143 | end | ||
144 | end | ||
145 | |||
146 | ------------------------------------------------------------------------------ | ||
147 | |||
148 | -- Map holding all option handlers. | ||
149 | local opt_map = {} | ||
150 | local opt_current | ||
151 | |||
152 | -- Print error and exit with error status. | ||
153 | local function opterror(...) | ||
154 | stderr:write("dynasm.lua: ERROR: ", ...) | ||
155 | stderr:write("\n") | ||
156 | exit(1) | ||
157 | end | ||
158 | |||
159 | -- Get option parameter. | ||
160 | local function optparam(args) | ||
161 | local argn = args.argn | ||
162 | local p = args[argn] | ||
163 | if not p then | ||
164 | opterror("missing parameter for option `", opt_current, "'.") | ||
165 | end | ||
166 | args.argn = argn + 1 | ||
167 | return p | ||
168 | end | ||
169 | |||
170 | ------------------------------------------------------------------------------ | ||
171 | |||
172 | -- Core pseudo-opcodes. | ||
173 | local map_coreop = {} | ||
174 | -- Dummy opcode map. Replaced by arch-specific map. | ||
175 | local map_op = {} | ||
176 | |||
177 | -- Forward declarations. | ||
178 | local dostmt | ||
179 | local readfile | ||
180 | |||
181 | ------------------------------------------------------------------------------ | ||
182 | |||
183 | -- Map for defines (initially empty, chains to arch-specific map). | ||
184 | local map_def = {} | ||
185 | |||
186 | -- Pseudo-opcode to define a substitution. | ||
187 | map_coreop[".define_2"] = function(params, nparams) | ||
188 | if not params then return nparams == 1 and "name" or "name, subst" end | ||
189 | local name, def = params[1], params[2] or "1" | ||
190 | if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end | ||
191 | map_def[name] = def | ||
192 | end | ||
193 | map_coreop[".define_1"] = map_coreop[".define_2"] | ||
194 | |||
195 | -- Define a substitution on the command line. | ||
196 | function opt_map.D(args) | ||
197 | local namesubst = optparam(args) | ||
198 | local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") | ||
199 | if name then | ||
200 | map_def[name] = subst | ||
201 | elseif match(namesubst, "^[%a_][%w_]*$") then | ||
202 | map_def[namesubst] = "1" | ||
203 | else | ||
204 | opterror("bad define") | ||
205 | end | ||
206 | end | ||
207 | |||
208 | -- Undefine a substitution on the command line. | ||
209 | function opt_map.U(args) | ||
210 | local name = optparam(args) | ||
211 | if match(name, "^[%a_][%w_]*$") then | ||
212 | map_def[name] = nil | ||
213 | else | ||
214 | opterror("bad define") | ||
215 | end | ||
216 | end | ||
217 | |||
218 | -- Helper for definesubst. | ||
219 | local gotsubst | ||
220 | |||
221 | local function definesubst_one(word) | ||
222 | local subst = map_def[word] | ||
223 | if subst then gotsubst = word; return subst else return word end | ||
224 | end | ||
225 | |||
226 | -- Iteratively substitute defines. | ||
227 | local function definesubst(stmt) | ||
228 | -- Limit number of iterations. | ||
229 | for i=1,100 do | ||
230 | gotsubst = false | ||
231 | stmt = gsub(stmt, "#?[%w_]+", definesubst_one) | ||
232 | if not gotsubst then break end | ||
233 | end | ||
234 | if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end | ||
235 | return stmt | ||
236 | end | ||
237 | |||
238 | -- Dump all defines. | ||
239 | local function dumpdefines(out, lvl) | ||
240 | local t = {} | ||
241 | for name in pairs(map_def) do | ||
242 | t[#t+1] = name | ||
243 | end | ||
244 | sort(t) | ||
245 | out:write("Defines:\n") | ||
246 | for _,name in ipairs(t) do | ||
247 | local subst = map_def[name] | ||
248 | if g_arch then subst = g_arch.revdef(subst) end | ||
249 | out:write(format(" %-20s %s\n", name, subst)) | ||
250 | end | ||
251 | out:write("\n") | ||
252 | end | ||
253 | |||
254 | ------------------------------------------------------------------------------ | ||
255 | |||
256 | -- Support variables for conditional assembly. | ||
257 | local condlevel = 0 | ||
258 | local condstack = {} | ||
259 | |||
260 | -- Evaluate condition with a Lua expression. Substitutions already performed. | ||
261 | local function cond_eval(cond) | ||
262 | local func, err = loadstring("return "..cond) | ||
263 | if func then | ||
264 | setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. | ||
265 | local ok, res = pcall(func) | ||
266 | if ok then | ||
267 | if res == 0 then return false end -- Oh well. | ||
268 | return not not res | ||
269 | end | ||
270 | err = res | ||
271 | end | ||
272 | wfatal("bad condition: "..err) | ||
273 | end | ||
274 | |||
275 | -- Skip statements until next conditional pseudo-opcode at the same level. | ||
276 | local function stmtskip() | ||
277 | local dostmt_save = dostmt | ||
278 | local lvl = 0 | ||
279 | dostmt = function(stmt) | ||
280 | local op = match(stmt, "^%s*(%S+)") | ||
281 | if op == ".if" then | ||
282 | lvl = lvl + 1 | ||
283 | elseif lvl ~= 0 then | ||
284 | if op == ".endif" then lvl = lvl - 1 end | ||
285 | elseif op == ".elif" or op == ".else" or op == ".endif" then | ||
286 | dostmt = dostmt_save | ||
287 | dostmt(stmt) | ||
288 | end | ||
289 | end | ||
290 | end | ||
291 | |||
292 | -- Pseudo-opcodes for conditional assembly. | ||
293 | map_coreop[".if_1"] = function(params) | ||
294 | if not params then return "condition" end | ||
295 | local lvl = condlevel + 1 | ||
296 | local res = cond_eval(params[1]) | ||
297 | condlevel = lvl | ||
298 | condstack[lvl] = res | ||
299 | if not res then stmtskip() end | ||
300 | end | ||
301 | |||
302 | map_coreop[".elif_1"] = function(params) | ||
303 | if not params then return "condition" end | ||
304 | if condlevel == 0 then wfatal(".elif without .if") end | ||
305 | local lvl = condlevel | ||
306 | local res = condstack[lvl] | ||
307 | if res then | ||
308 | if res == "else" then wfatal(".elif after .else") end | ||
309 | else | ||
310 | res = cond_eval(params[1]) | ||
311 | if res then | ||
312 | condstack[lvl] = res | ||
313 | return | ||
314 | end | ||
315 | end | ||
316 | stmtskip() | ||
317 | end | ||
318 | |||
319 | map_coreop[".else_0"] = function(params) | ||
320 | if condlevel == 0 then wfatal(".else without .if") end | ||
321 | local lvl = condlevel | ||
322 | local res = condstack[lvl] | ||
323 | condstack[lvl] = "else" | ||
324 | if res then | ||
325 | if res == "else" then wfatal(".else after .else") end | ||
326 | stmtskip() | ||
327 | end | ||
328 | end | ||
329 | |||
330 | map_coreop[".endif_0"] = function(params) | ||
331 | local lvl = condlevel | ||
332 | if lvl == 0 then wfatal(".endif without .if") end | ||
333 | condlevel = lvl - 1 | ||
334 | end | ||
335 | |||
336 | -- Check for unfinished conditionals. | ||
337 | local function checkconds() | ||
338 | if g_errcount ~= "fatal" and condlevel ~= 0 then | ||
339 | wprinterr(g_fname, ":*: error: unbalanced conditional\n") | ||
340 | end | ||
341 | end | ||
342 | |||
343 | ------------------------------------------------------------------------------ | ||
344 | |||
345 | -- Search for a file in the given path and open it for reading. | ||
346 | local function pathopen(path, name) | ||
347 | local dirsep = match(package.path, "\\") and "\\" or "/" | ||
348 | for _,p in ipairs(path) do | ||
349 | local fullname = p == "" and name or p..dirsep..name | ||
350 | local fin = io.open(fullname, "r") | ||
351 | if fin then | ||
352 | g_fname = fullname | ||
353 | return fin | ||
354 | end | ||
355 | end | ||
356 | end | ||
357 | |||
358 | -- Include a file. | ||
359 | map_coreop[".include_1"] = function(params) | ||
360 | if not params then return "filename" end | ||
361 | local name = params[1] | ||
362 | -- Save state. Ugly, I know. but upvalues are fast. | ||
363 | local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent | ||
364 | -- Read the included file. | ||
365 | local fatal = readfile(pathopen(g_opt.include, name) or | ||
366 | wfatal("include file `"..name.."' not found")) | ||
367 | -- Restore state. | ||
368 | g_synclineno = -1 | ||
369 | g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi | ||
370 | if fatal then wfatal("in include file") end | ||
371 | end | ||
372 | |||
373 | -- Make .include and conditionals initially available, too. | ||
374 | map_op[".include_1"] = map_coreop[".include_1"] | ||
375 | map_op[".if_1"] = map_coreop[".if_1"] | ||
376 | map_op[".elif_1"] = map_coreop[".elif_1"] | ||
377 | map_op[".else_0"] = map_coreop[".else_0"] | ||
378 | map_op[".endif_0"] = map_coreop[".endif_0"] | ||
379 | |||
380 | ------------------------------------------------------------------------------ | ||
381 | |||
382 | -- Support variables for macros. | ||
383 | local mac_capture, mac_lineno, mac_name | ||
384 | local mac_active = {} | ||
385 | local mac_list = {} | ||
386 | |||
387 | -- Pseudo-opcode to define a macro. | ||
388 | map_coreop[".macro_*"] = function(mparams) | ||
389 | if not mparams then return "name [, params...]" end | ||
390 | -- Split off and validate macro name. | ||
391 | local name = remove(mparams, 1) | ||
392 | if not name then werror("missing macro name") end | ||
393 | if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]+$")) then | ||
394 | wfatal("bad macro name `"..name.."'") | ||
395 | end | ||
396 | -- Validate macro parameter names. | ||
397 | local mdup = {} | ||
398 | for _,mp in ipairs(mparams) do | ||
399 | if not match(mp, "^[%a_][%w_]*$") then | ||
400 | wfatal("bad macro parameter name `"..mp.."'") | ||
401 | end | ||
402 | if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end | ||
403 | mdup[mp] = true | ||
404 | end | ||
405 | -- Check for duplicate or recursive macro definitions. | ||
406 | local opname = name.."_"..#mparams | ||
407 | if map_op[opname] or map_op[name.."_*"] then | ||
408 | wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") | ||
409 | end | ||
410 | if mac_capture then wfatal("recursive macro definition") end | ||
411 | |||
412 | -- Enable statement capture. | ||
413 | local lines = {} | ||
414 | mac_lineno = g_lineno | ||
415 | mac_name = name | ||
416 | mac_capture = function(stmt) -- Statement capture function. | ||
417 | -- Stop macro definition with .endmacro pseudo-opcode. | ||
418 | if not match(stmt, "^%s*.endmacro%s*$") then | ||
419 | lines[#lines+1] = stmt | ||
420 | return | ||
421 | end | ||
422 | mac_capture = nil | ||
423 | mac_lineno = nil | ||
424 | mac_name = nil | ||
425 | mac_list[#mac_list+1] = opname | ||
426 | -- Add macro-op definition. | ||
427 | map_op[opname] = function(params) | ||
428 | if not params then return mparams, lines end | ||
429 | -- Protect against recursive macro invocation. | ||
430 | if mac_active[opname] then wfatal("recursive macro invocation") end | ||
431 | mac_active[opname] = true | ||
432 | -- Setup substitution map. | ||
433 | local subst = {} | ||
434 | for i,mp in ipairs(mparams) do subst[mp] = params[i] end | ||
435 | local mcom | ||
436 | if g_opt.maccomment and g_opt.comment then | ||
437 | mcom = " MACRO "..name.." ("..#mparams..")" | ||
438 | wcomment("{"..mcom) | ||
439 | end | ||
440 | -- Loop through all captured statements | ||
441 | for _,stmt in ipairs(lines) do | ||
442 | -- Substitute macro parameters. | ||
443 | local st = gsub(stmt, "[%w_]+", subst) | ||
444 | st = definesubst(st) | ||
445 | st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. | ||
446 | if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end | ||
447 | -- Emit statement. Use a protected call for better diagnostics. | ||
448 | local ok, err = pcall(dostmt, st) | ||
449 | if not ok then | ||
450 | -- Add the captured statement to the error. | ||
451 | wprinterr(err, "\n", g_indent, "| ", stmt, | ||
452 | "\t[MACRO ", name, " (", #mparams, ")]\n") | ||
453 | end | ||
454 | end | ||
455 | if mcom then wcomment("}"..mcom) end | ||
456 | mac_active[opname] = nil | ||
457 | end | ||
458 | end | ||
459 | end | ||
460 | |||
461 | -- An .endmacro pseudo-opcode outside of a macro definition is an error. | ||
462 | map_coreop[".endmacro_0"] = function(params) | ||
463 | wfatal(".endmacro without .macro") | ||
464 | end | ||
465 | |||
466 | -- Dump all macros and their contents (with -PP only). | ||
467 | local function dumpmacros(out, lvl) | ||
468 | sort(mac_list) | ||
469 | out:write("Macros:\n") | ||
470 | for _,opname in ipairs(mac_list) do | ||
471 | local name = sub(opname, 1, -3) | ||
472 | local params, lines = map_op[opname]() | ||
473 | out:write(format(" %-20s %s\n", name, concat(params, ", "))) | ||
474 | if lvl > 1 then | ||
475 | for _,line in ipairs(lines) do | ||
476 | out:write(" |", line, "\n") | ||
477 | end | ||
478 | out:write("\n") | ||
479 | end | ||
480 | end | ||
481 | out:write("\n") | ||
482 | end | ||
483 | |||
484 | -- Check for unfinished macro definitions. | ||
485 | local function checkmacros() | ||
486 | if mac_capture then | ||
487 | wprinterr(g_fname, ":", mac_lineno, | ||
488 | ": error: unfinished .macro `", mac_name ,"'\n") | ||
489 | end | ||
490 | end | ||
491 | |||
492 | ------------------------------------------------------------------------------ | ||
493 | |||
494 | -- Support variables for captures. | ||
495 | local cap_lineno, cap_name | ||
496 | local cap_buffers = {} | ||
497 | local cap_used = {} | ||
498 | |||
499 | -- Start a capture. | ||
500 | map_coreop[".capture_1"] = function(params) | ||
501 | if not params then return "name" end | ||
502 | wflush() | ||
503 | local name = params[1] | ||
504 | if not match(name, "^[%a_][%w_]*$") then | ||
505 | wfatal("bad capture name `"..name.."'") | ||
506 | end | ||
507 | if cap_name then | ||
508 | wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) | ||
509 | end | ||
510 | cap_name = name | ||
511 | cap_lineno = g_lineno | ||
512 | -- Create or continue a capture buffer and start the output line capture. | ||
513 | local buf = cap_buffers[name] | ||
514 | if not buf then buf = {}; cap_buffers[name] = buf end | ||
515 | g_capbuffer = buf | ||
516 | g_synclineno = 0 | ||
517 | end | ||
518 | |||
519 | -- Stop a capture. | ||
520 | map_coreop[".endcapture_0"] = function(params) | ||
521 | wflush() | ||
522 | if not cap_name then wfatal(".endcapture without a valid .capture") end | ||
523 | cap_name = nil | ||
524 | cap_lineno = nil | ||
525 | g_capbuffer = nil | ||
526 | g_synclineno = 0 | ||
527 | end | ||
528 | |||
529 | -- Dump a capture buffer. | ||
530 | map_coreop[".dumpcapture_1"] = function(params) | ||
531 | if not params then return "name" end | ||
532 | wflush() | ||
533 | local name = params[1] | ||
534 | if not match(name, "^[%a_][%w_]*$") then | ||
535 | wfatal("bad capture name `"..name.."'") | ||
536 | end | ||
537 | cap_used[name] = true | ||
538 | wline(function(out) | ||
539 | local buf = cap_buffers[name] | ||
540 | if buf then wdumplines(out, buf) end | ||
541 | end) | ||
542 | g_synclineno = 0 | ||
543 | end | ||
544 | |||
545 | -- Dump all captures and their buffers (with -PP only). | ||
546 | local function dumpcaptures(out, lvl) | ||
547 | out:write("Captures:\n") | ||
548 | for name,buf in pairs(cap_buffers) do | ||
549 | out:write(format(" %-20s %4s)\n", name, "("..#buf)) | ||
550 | if lvl > 1 then | ||
551 | local bar = rep("=", 76) | ||
552 | out:write(" ", bar, "\n") | ||
553 | for _,line in ipairs(buf) do | ||
554 | out:write(" ", line, "\n") | ||
555 | end | ||
556 | out:write(" ", bar, "\n\n") | ||
557 | end | ||
558 | end | ||
559 | out:write("\n") | ||
560 | end | ||
561 | |||
562 | -- Check for unfinished or unused captures. | ||
563 | local function checkcaptures() | ||
564 | if cap_name then | ||
565 | wprinterr(g_fname, ":", cap_lineno, | ||
566 | ": error: unfinished .capture `", cap_name,"'\n") | ||
567 | return | ||
568 | end | ||
569 | for name in pairs(cap_buffers) do | ||
570 | if not cap_used[name] then | ||
571 | wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") | ||
572 | end | ||
573 | end | ||
574 | end | ||
575 | |||
576 | ------------------------------------------------------------------------------ | ||
577 | |||
578 | -- Sections names. | ||
579 | local map_sections = {} | ||
580 | |||
581 | -- Pseudo-opcode to define code sections. | ||
582 | -- TODO: Data sections, BSS sections. Needs extra C code and API. | ||
583 | map_coreop[".section_*"] = function(params) | ||
584 | if not params then return "name..." end | ||
585 | if #map_sections > 0 then werror("duplicate section definition") end | ||
586 | wflush() | ||
587 | for sn,name in ipairs(params) do | ||
588 | local opname = "."..name.."_0" | ||
589 | if not match(name, "^[%a][%w_]*$") or | ||
590 | map_op[opname] or map_op["."..name.."_*"] then | ||
591 | werror("bad section name `"..name.."'") | ||
592 | end | ||
593 | map_sections[#map_sections+1] = name | ||
594 | wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) | ||
595 | map_op[opname] = function(params) g_arch.section(sn-1) end | ||
596 | end | ||
597 | wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) | ||
598 | end | ||
599 | |||
600 | -- Dump all sections. | ||
601 | local function dumpsections(out, lvl) | ||
602 | out:write("Sections:\n") | ||
603 | for _,name in ipairs(map_sections) do | ||
604 | out:write(format(" %s\n", name)) | ||
605 | end | ||
606 | out:write("\n") | ||
607 | end | ||
608 | |||
609 | ------------------------------------------------------------------------------ | ||
610 | |||
611 | -- Load architecture-specific module. | ||
612 | local function loadarch(arch) | ||
613 | if not match(arch, "^[%w_]+$") then return "bad arch name" end | ||
614 | local ok, m_arch = pcall(require, "dasm_"..arch) | ||
615 | if not ok then return "cannot load module: "..m_arch end | ||
616 | g_arch = m_arch | ||
617 | wflush = m_arch.passcb(wline, werror, wfatal, wwarn) | ||
618 | m_arch.setup(arch, g_opt) | ||
619 | map_op, map_def = m_arch.mergemaps(map_coreop, map_def) | ||
620 | end | ||
621 | |||
622 | -- Dump architecture description. | ||
623 | function opt_map.dumparch(args) | ||
624 | local name = optparam(args) | ||
625 | if not g_arch then | ||
626 | local err = loadarch(name) | ||
627 | if err then opterror(err) end | ||
628 | end | ||
629 | |||
630 | local t = {} | ||
631 | for name in pairs(map_coreop) do t[#t+1] = name end | ||
632 | for name in pairs(map_op) do t[#t+1] = name end | ||
633 | sort(t) | ||
634 | |||
635 | local out = stdout | ||
636 | local _arch = g_arch._info | ||
637 | out:write(format("%s version %s, released %s, %s\n", | ||
638 | _info.name, _info.version, _info.release, _info.url)) | ||
639 | g_arch.dumparch(out) | ||
640 | |||
641 | local pseudo = true | ||
642 | out:write("Pseudo-Opcodes:\n") | ||
643 | for _,sname in ipairs(t) do | ||
644 | local name, nparam = match(sname, "^(.+)_([0-9%*])$") | ||
645 | if name then | ||
646 | if pseudo and sub(name, 1, 1) ~= "." then | ||
647 | out:write("\nOpcodes:\n") | ||
648 | pseudo = false | ||
649 | end | ||
650 | local f = map_op[sname] | ||
651 | local s | ||
652 | if nparam ~= "*" then nparam = nparam + 0 end | ||
653 | if nparam == 0 then | ||
654 | s = "" | ||
655 | elseif type(f) == "string" then | ||
656 | s = map_op[".template__"](nil, f, nparam) | ||
657 | else | ||
658 | s = f(nil, nparam) | ||
659 | end | ||
660 | if type(s) == "table" then | ||
661 | for _,s2 in ipairs(s) do | ||
662 | out:write(format(" %-12s %s\n", name, s2)) | ||
663 | end | ||
664 | else | ||
665 | out:write(format(" %-12s %s\n", name, s)) | ||
666 | end | ||
667 | end | ||
668 | end | ||
669 | out:write("\n") | ||
670 | exit(0) | ||
671 | end | ||
672 | |||
673 | -- Pseudo-opcode to set the architecture. | ||
674 | -- Only initially available (map_op is replaced when called). | ||
675 | map_op[".arch_1"] = function(params) | ||
676 | if not params then return "name" end | ||
677 | local err = loadarch(params[1]) | ||
678 | if err then wfatal(err) end | ||
679 | end | ||
680 | |||
681 | -- Dummy .arch pseudo-opcode to improve the error report. | ||
682 | map_coreop[".arch_1"] = function(params) | ||
683 | if not params then return "name" end | ||
684 | wfatal("duplicate .arch statement") | ||
685 | end | ||
686 | |||
687 | ------------------------------------------------------------------------------ | ||
688 | |||
689 | -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. | ||
690 | map_coreop[".nop_*"] = function(params) | ||
691 | if not params then return "[ignored...]" end | ||
692 | end | ||
693 | |||
694 | -- Pseudo-opcodes to raise errors. | ||
695 | map_coreop[".error_1"] = function(params) | ||
696 | if not params then return "message" end | ||
697 | werror(params[1]) | ||
698 | end | ||
699 | |||
700 | map_coreop[".fatal_1"] = function(params) | ||
701 | if not params then return "message" end | ||
702 | wfatal(params[1]) | ||
703 | end | ||
704 | |||
705 | -- Dump all user defined elements. | ||
706 | local function dumpdef(out) | ||
707 | local lvl = g_opt.dumpdef | ||
708 | if lvl == 0 then return end | ||
709 | dumpsections(out, lvl) | ||
710 | dumpdefines(out, lvl) | ||
711 | if g_arch then g_arch.dumpdef(out, lvl) end | ||
712 | dumpmacros(out, lvl) | ||
713 | dumpcaptures(out, lvl) | ||
714 | end | ||
715 | |||
716 | ------------------------------------------------------------------------------ | ||
717 | |||
718 | -- Helper for splitstmt. | ||
719 | local splitlvl | ||
720 | |||
721 | local function splitstmt_one(c) | ||
722 | if c == "(" then | ||
723 | splitlvl = ")"..splitlvl | ||
724 | elseif c == "[" then | ||
725 | splitlvl = "]"..splitlvl | ||
726 | elseif c == "{" then | ||
727 | splitlvl = "}"..splitlvl | ||
728 | elseif c == ")" or c == "]" or c == "}" then | ||
729 | if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end | ||
730 | splitlvl = sub(splitlvl, 2) | ||
731 | elseif splitlvl == "" then | ||
732 | return " \0 " | ||
733 | end | ||
734 | return c | ||
735 | end | ||
736 | |||
737 | -- Split statement into (pseudo-)opcode and params. | ||
738 | local function splitstmt(stmt) | ||
739 | -- Convert label with trailing-colon into .label statement. | ||
740 | local label = match(stmt, "^%s*(.+):%s*$") | ||
741 | if label then return ".label", {label} end | ||
742 | |||
743 | -- Split at commas and equal signs, but obey parentheses and brackets. | ||
744 | splitlvl = "" | ||
745 | stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) | ||
746 | if splitlvl ~= "" then werror("unbalanced () or []") end | ||
747 | |||
748 | -- Split off opcode. | ||
749 | local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") | ||
750 | if not op then werror("bad statement syntax") end | ||
751 | |||
752 | -- Split parameters. | ||
753 | local params = {} | ||
754 | for p in gmatch(other, "%s*(%Z+)%z?") do | ||
755 | params[#params+1] = gsub(p, "%s+$", "") | ||
756 | end | ||
757 | if #params > 16 then werror("too many parameters") end | ||
758 | |||
759 | params.op = op | ||
760 | return op, params | ||
761 | end | ||
762 | |||
763 | -- Process a single statement. | ||
764 | dostmt = function(stmt) | ||
765 | -- Ignore empty statements. | ||
766 | if match(stmt, "^%s*$") then return end | ||
767 | |||
768 | -- Capture macro defs before substitution. | ||
769 | if mac_capture then return mac_capture(stmt) end | ||
770 | stmt = definesubst(stmt) | ||
771 | |||
772 | -- Emit C code without parsing the line. | ||
773 | if sub(stmt, 1, 1) == "|" then | ||
774 | local tail = sub(stmt, 2) | ||
775 | wflush() | ||
776 | if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end | ||
777 | return | ||
778 | end | ||
779 | |||
780 | -- Split into (pseudo-)opcode and params. | ||
781 | local op, params = splitstmt(stmt) | ||
782 | |||
783 | -- Get opcode handler (matching # of parameters or generic handler). | ||
784 | local f = map_op[op.."_"..#params] or map_op[op.."_*"] | ||
785 | if not f then | ||
786 | if not g_arch then wfatal("first statement must be .arch") end | ||
787 | -- Improve error report. | ||
788 | for i=0,9 do | ||
789 | if map_op[op.."_"..i] then | ||
790 | werror("wrong number of parameters for `"..op.."'") | ||
791 | end | ||
792 | end | ||
793 | werror("unknown statement `"..op.."'") | ||
794 | end | ||
795 | |||
796 | -- Call opcode handler or special handler for template strings. | ||
797 | if type(f) == "string" then | ||
798 | map_op[".template__"](params, f) | ||
799 | else | ||
800 | f(params) | ||
801 | end | ||
802 | end | ||
803 | |||
804 | -- Process a single line. | ||
805 | local function doline(line) | ||
806 | if g_opt.flushline then wflush() end | ||
807 | |||
808 | -- Assembler line? | ||
809 | local indent, aline = match(line, "^(%s*)%|(.*)$") | ||
810 | if not aline then | ||
811 | -- No, plain C code line, need to flush first. | ||
812 | wflush() | ||
813 | wsync() | ||
814 | wline(line, false) | ||
815 | return | ||
816 | end | ||
817 | |||
818 | g_indent = indent -- Remember current line indentation. | ||
819 | |||
820 | -- Emit C code (even from macros). Avoids echo and line parsing. | ||
821 | if sub(aline, 1, 1) == "|" then | ||
822 | if not mac_capture then | ||
823 | wsync() | ||
824 | elseif g_opt.comment then | ||
825 | wsync() | ||
826 | wcomment(aline) | ||
827 | end | ||
828 | dostmt(aline) | ||
829 | return | ||
830 | end | ||
831 | |||
832 | -- Echo assembler line as a comment. | ||
833 | if g_opt.comment then | ||
834 | wsync() | ||
835 | wcomment(aline) | ||
836 | end | ||
837 | |||
838 | -- Strip assembler comments. | ||
839 | aline = gsub(aline, "//.*$", "") | ||
840 | |||
841 | -- Split line into statements at semicolons. | ||
842 | if match(aline, ";") then | ||
843 | for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end | ||
844 | else | ||
845 | dostmt(aline) | ||
846 | end | ||
847 | end | ||
848 | |||
849 | ------------------------------------------------------------------------------ | ||
850 | |||
851 | -- Write DynASM header. | ||
852 | local function dasmhead(out) | ||
853 | out:write(format([[ | ||
854 | /* | ||
855 | ** This file has been pre-processed with DynASM. | ||
856 | ** %s | ||
857 | ** DynASM version %s, DynASM %s version %s | ||
858 | ** DO NOT EDIT! The original file is in "%s". | ||
859 | */ | ||
860 | |||
861 | #if DASM_VERSION != %d | ||
862 | #error "Version mismatch between DynASM and included encoding engine" | ||
863 | #endif | ||
864 | |||
865 | ]], _info.url, | ||
866 | _info.version, g_arch._info.arch, g_arch._info.version, | ||
867 | g_fname, _info.vernum)) | ||
868 | end | ||
869 | |||
870 | -- Read input file. | ||
871 | readfile = function(fin) | ||
872 | g_indent = "" | ||
873 | g_lineno = 0 | ||
874 | g_synclineno = -1 | ||
875 | |||
876 | -- Process all lines. | ||
877 | for line in fin:lines() do | ||
878 | g_lineno = g_lineno + 1 | ||
879 | g_curline = line | ||
880 | local ok, err = pcall(doline, line) | ||
881 | if not ok and wprinterr(err, "\n") then return true end | ||
882 | end | ||
883 | wflush() | ||
884 | |||
885 | -- Close input file. | ||
886 | assert(fin == stdin or fin:close()) | ||
887 | end | ||
888 | |||
889 | -- Write output file. | ||
890 | local function writefile(outfile) | ||
891 | local fout | ||
892 | |||
893 | -- Open output file. | ||
894 | if outfile == nil or outfile == "-" then | ||
895 | fout = stdout | ||
896 | else | ||
897 | fout = assert(io.open(outfile, "w")) | ||
898 | end | ||
899 | |||
900 | -- Write all buffered lines | ||
901 | wdumplines(fout, g_wbuffer) | ||
902 | |||
903 | -- Close output file. | ||
904 | assert(fout == stdout or fout:close()) | ||
905 | |||
906 | -- Optionally dump definitions. | ||
907 | dumpdef(fout == stdout and stderr or stdout) | ||
908 | end | ||
909 | |||
910 | -- Translate an input file to an output file. | ||
911 | local function translate(infile, outfile) | ||
912 | g_wbuffer = {} | ||
913 | g_indent = "" | ||
914 | g_lineno = 0 | ||
915 | g_synclineno = -1 | ||
916 | |||
917 | -- Put header. | ||
918 | wline(dasmhead) | ||
919 | |||
920 | -- Read input file. | ||
921 | local fin | ||
922 | if infile == "-" then | ||
923 | g_fname = "(stdin)" | ||
924 | fin = stdin | ||
925 | else | ||
926 | g_fname = infile | ||
927 | fin = assert(io.open(infile, "r")) | ||
928 | end | ||
929 | readfile(fin) | ||
930 | |||
931 | -- Check for errors. | ||
932 | if not g_arch then | ||
933 | wprinterr(g_fname, ":*: error: missing .arch directive\n") | ||
934 | end | ||
935 | checkconds() | ||
936 | checkmacros() | ||
937 | checkcaptures() | ||
938 | |||
939 | if g_errcount ~= 0 then | ||
940 | stderr:write(g_fname, ":*: info: ", g_errcount, " error", | ||
941 | (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", | ||
942 | " in input file -- no output file generated.\n") | ||
943 | dumpdef(stderr) | ||
944 | exit(1) | ||
945 | end | ||
946 | |||
947 | -- Write output file. | ||
948 | writefile(outfile) | ||
949 | end | ||
950 | |||
951 | ------------------------------------------------------------------------------ | ||
952 | |||
953 | -- Print help text. | ||
954 | function opt_map.help() | ||
955 | stdout:write("DynASM -- ", _info.description, ".\n") | ||
956 | stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") | ||
957 | stdout:write[[ | ||
958 | |||
959 | Usage: dynasm [OPTION]... INFILE.dasc|- | ||
960 | |||
961 | -h, --help Display this help text. | ||
962 | -V, --version Display version and copyright information. | ||
963 | |||
964 | -o, --outfile FILE Output file name (default is stdout). | ||
965 | -I, --include DIR Add directory to the include search path. | ||
966 | |||
967 | -c, --ccomment Use /* */ comments for assembler lines. | ||
968 | -C, --cppcomment Use // comments for assembler lines (default). | ||
969 | -N, --nocomment Suppress assembler lines in output. | ||
970 | -M, --maccomment Show macro expansions as comments (default off). | ||
971 | |||
972 | -L, --nolineno Suppress CPP line number information in output. | ||
973 | -F, --flushline Flush action list for every line. | ||
974 | |||
975 | -D NAME[=SUBST] Define a substitution. | ||
976 | -U NAME Undefine a substitution. | ||
977 | |||
978 | -P, --dumpdef Dump defines, macros, etc. Repeat for more output. | ||
979 | -A, --dumparch ARCH Load architecture ARCH and dump description. | ||
980 | ]] | ||
981 | exit(0) | ||
982 | end | ||
983 | |||
984 | -- Print version information. | ||
985 | function opt_map.version() | ||
986 | stdout:write(format("%s version %s, released %s\n%s\n\n%s", | ||
987 | _info.name, _info.version, _info.release, _info.url, _info.copyright)) | ||
988 | exit(0) | ||
989 | end | ||
990 | |||
991 | -- Misc. options. | ||
992 | function opt_map.outfile(args) g_opt.outfile = optparam(args) end | ||
993 | function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end | ||
994 | function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end | ||
995 | function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end | ||
996 | function opt_map.nocomment() g_opt.comment = false end | ||
997 | function opt_map.maccomment() g_opt.maccomment = true end | ||
998 | function opt_map.nolineno() g_opt.cpp = false end | ||
999 | function opt_map.flushline() g_opt.flushline = true end | ||
1000 | function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end | ||
1001 | |||
1002 | ------------------------------------------------------------------------------ | ||
1003 | |||
1004 | -- Short aliases for long options. | ||
1005 | local opt_alias = { | ||
1006 | h = "help", ["?"] = "help", V = "version", | ||
1007 | o = "outfile", I = "include", | ||
1008 | c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", | ||
1009 | L = "nolineno", F = "flushline", | ||
1010 | P = "dumpdef", A = "dumparch", | ||
1011 | } | ||
1012 | |||
1013 | -- Parse single option. | ||
1014 | local function parseopt(opt, args) | ||
1015 | opt_current = #opt == 1 and "-"..opt or "--"..opt | ||
1016 | local f = opt_map[opt] or opt_map[opt_alias[opt]] | ||
1017 | if not f then | ||
1018 | opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") | ||
1019 | end | ||
1020 | f(args) | ||
1021 | end | ||
1022 | |||
1023 | -- Parse arguments. | ||
1024 | local function parseargs(args) | ||
1025 | -- Default options. | ||
1026 | g_opt.comment = "//|" | ||
1027 | g_opt.endcomment = "" | ||
1028 | g_opt.cpp = true | ||
1029 | g_opt.dumpdef = 0 | ||
1030 | g_opt.include = { "" } | ||
1031 | |||
1032 | -- Process all option arguments. | ||
1033 | args.argn = 1 | ||
1034 | repeat | ||
1035 | local a = args[args.argn] | ||
1036 | if not a then break end | ||
1037 | local lopt, opt = match(a, "^%-(%-?)(.+)") | ||
1038 | if not opt then break end | ||
1039 | args.argn = args.argn + 1 | ||
1040 | if lopt == "" then | ||
1041 | -- Loop through short options. | ||
1042 | for o in gmatch(opt, ".") do parseopt(o, args) end | ||
1043 | else | ||
1044 | -- Long option. | ||
1045 | parseopt(opt, args) | ||
1046 | end | ||
1047 | until false | ||
1048 | |||
1049 | -- Check for proper number of arguments. | ||
1050 | local nargs = #args - args.argn + 1 | ||
1051 | if nargs ~= 1 then | ||
1052 | if nargs == 0 then | ||
1053 | if g_opt.dumpdef > 0 then return dumpdef(stdout) end | ||
1054 | end | ||
1055 | opt_map.help() | ||
1056 | end | ||
1057 | |||
1058 | -- Translate a single input file to a single output file | ||
1059 | -- TODO: Handle multiple files? | ||
1060 | translate(args[args.argn], g_opt.outfile) | ||
1061 | end | ||
1062 | |||
1063 | ------------------------------------------------------------------------------ | ||
1064 | |||
1065 | -- Add the directory dynasm.lua resides in to the Lua module search path. | ||
1066 | local arg = arg | ||
1067 | if arg and arg[0] then | ||
1068 | local prefix = match(arg[0], "^(.*[/\\])") | ||
1069 | if prefix then package.path = prefix.."?.lua;"..package.path end | ||
1070 | end | ||
1071 | |||
1072 | -- Start DynASM. | ||
1073 | parseargs{...} | ||
1074 | |||
1075 | ------------------------------------------------------------------------------ | ||
1076 | |||