aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/luajit-2.0/dynasm/dynasm.lua
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/luajit-2.0/dynasm/dynasm.lua')
-rw-r--r--libraries/luajit-2.0/dynasm/dynasm.lua1076
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.
10local _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 = [[
20Copyright (C) 2005-2011 Mike Pall. All rights reserved.
21
22Permission is hereby granted, free of charge, to any person obtaining
23a copy of this software and associated documentation files (the
24"Software"), to deal in the Software without restriction, including
25without limitation the rights to use, copy, modify, merge, publish,
26distribute, sublicense, and/or sell copies of the Software, and to
27permit persons to whom the Software is furnished to do so, subject to
28the following conditions:
29
30The above copyright notice and this permission notice shall be
31included in all copies or substantial portions of the Software.
32
33THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
34EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
35MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
36IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
37CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
38TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
39SOFTWARE 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.
46local type, pairs, ipairs = type, pairs, ipairs
47local pcall, error, assert = pcall, error, assert
48local _s = string
49local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub
50local format, rep, upper = _s.format, _s.rep, _s.upper
51local _t = table
52local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort
53local exit = os.exit
54local io = io
55local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr
56
57------------------------------------------------------------------------------
58
59-- Program options.
60local g_opt = {}
61
62-- Global state for current file.
63local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch
64local g_errcount = 0
65
66-- Write buffer for output file.
67local g_wbuffer, g_capbuffer
68
69------------------------------------------------------------------------------
70
71-- Write an output line (or callback function) to the buffer.
72local 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
76end
77
78-- Write assembler line as a comment, if requestd.
79local function wcomment(aline)
80 if g_opt.comment then
81 wline(g_opt.comment..aline..g_opt.endcomment, true)
82 end
83end
84
85-- Resync CPP line numbers.
86local 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
91end
92
93-- Dummy action flush function. Replaced with arch-specific function later.
94local function wflush(term)
95end
96
97-- Dump all buffered output lines.
98local 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
107end
108
109------------------------------------------------------------------------------
110
111-- Emit an error. Processing continues with next statement.
112local function werror(msg)
113 error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0)
114end
115
116-- Emit a fatal error. Processing stops.
117local function wfatal(msg)
118 g_errcount = "fatal"
119 werror(msg)
120end
121
122-- Print a warning. Processing continues.
123local function wwarn(msg)
124 stderr:write(format("%s:%s: warning: %s:\n%s\n",
125 g_fname, g_lineno, msg, g_curline))
126end
127
128-- Print caught error message. But suppress excessive errors.
129local 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
144end
145
146------------------------------------------------------------------------------
147
148-- Map holding all option handlers.
149local opt_map = {}
150local opt_current
151
152-- Print error and exit with error status.
153local function opterror(...)
154 stderr:write("dynasm.lua: ERROR: ", ...)
155 stderr:write("\n")
156 exit(1)
157end
158
159-- Get option parameter.
160local 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
168end
169
170------------------------------------------------------------------------------
171
172-- Core pseudo-opcodes.
173local map_coreop = {}
174-- Dummy opcode map. Replaced by arch-specific map.
175local map_op = {}
176
177-- Forward declarations.
178local dostmt
179local readfile
180
181------------------------------------------------------------------------------
182
183-- Map for defines (initially empty, chains to arch-specific map).
184local map_def = {}
185
186-- Pseudo-opcode to define a substitution.
187map_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
192end
193map_coreop[".define_1"] = map_coreop[".define_2"]
194
195-- Define a substitution on the command line.
196function 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
206end
207
208-- Undefine a substitution on the command line.
209function 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
216end
217
218-- Helper for definesubst.
219local gotsubst
220
221local function definesubst_one(word)
222 local subst = map_def[word]
223 if subst then gotsubst = word; return subst else return word end
224end
225
226-- Iteratively substitute defines.
227local 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
236end
237
238-- Dump all defines.
239local 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")
252end
253
254------------------------------------------------------------------------------
255
256-- Support variables for conditional assembly.
257local condlevel = 0
258local condstack = {}
259
260-- Evaluate condition with a Lua expression. Substitutions already performed.
261local 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)
273end
274
275-- Skip statements until next conditional pseudo-opcode at the same level.
276local 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
290end
291
292-- Pseudo-opcodes for conditional assembly.
293map_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
300end
301
302map_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()
317end
318
319map_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
328end
329
330map_coreop[".endif_0"] = function(params)
331 local lvl = condlevel
332 if lvl == 0 then wfatal(".endif without .if") end
333 condlevel = lvl - 1
334end
335
336-- Check for unfinished conditionals.
337local function checkconds()
338 if g_errcount ~= "fatal" and condlevel ~= 0 then
339 wprinterr(g_fname, ":*: error: unbalanced conditional\n")
340 end
341end
342
343------------------------------------------------------------------------------
344
345-- Search for a file in the given path and open it for reading.
346local 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
356end
357
358-- Include a file.
359map_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
371end
372
373-- Make .include and conditionals initially available, too.
374map_op[".include_1"] = map_coreop[".include_1"]
375map_op[".if_1"] = map_coreop[".if_1"]
376map_op[".elif_1"] = map_coreop[".elif_1"]
377map_op[".else_0"] = map_coreop[".else_0"]
378map_op[".endif_0"] = map_coreop[".endif_0"]
379
380------------------------------------------------------------------------------
381
382-- Support variables for macros.
383local mac_capture, mac_lineno, mac_name
384local mac_active = {}
385local mac_list = {}
386
387-- Pseudo-opcode to define a macro.
388map_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
459end
460
461-- An .endmacro pseudo-opcode outside of a macro definition is an error.
462map_coreop[".endmacro_0"] = function(params)
463 wfatal(".endmacro without .macro")
464end
465
466-- Dump all macros and their contents (with -PP only).
467local 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")
482end
483
484-- Check for unfinished macro definitions.
485local function checkmacros()
486 if mac_capture then
487 wprinterr(g_fname, ":", mac_lineno,
488 ": error: unfinished .macro `", mac_name ,"'\n")
489 end
490end
491
492------------------------------------------------------------------------------
493
494-- Support variables for captures.
495local cap_lineno, cap_name
496local cap_buffers = {}
497local cap_used = {}
498
499-- Start a capture.
500map_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
517end
518
519-- Stop a capture.
520map_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
527end
528
529-- Dump a capture buffer.
530map_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
543end
544
545-- Dump all captures and their buffers (with -PP only).
546local 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")
560end
561
562-- Check for unfinished or unused captures.
563local 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
574end
575
576------------------------------------------------------------------------------
577
578-- Sections names.
579local map_sections = {}
580
581-- Pseudo-opcode to define code sections.
582-- TODO: Data sections, BSS sections. Needs extra C code and API.
583map_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))
598end
599
600-- Dump all sections.
601local 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")
607end
608
609------------------------------------------------------------------------------
610
611-- Load architecture-specific module.
612local 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)
620end
621
622-- Dump architecture description.
623function 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)
671end
672
673-- Pseudo-opcode to set the architecture.
674-- Only initially available (map_op is replaced when called).
675map_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
679end
680
681-- Dummy .arch pseudo-opcode to improve the error report.
682map_coreop[".arch_1"] = function(params)
683 if not params then return "name" end
684 wfatal("duplicate .arch statement")
685end
686
687------------------------------------------------------------------------------
688
689-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
690map_coreop[".nop_*"] = function(params)
691 if not params then return "[ignored...]" end
692end
693
694-- Pseudo-opcodes to raise errors.
695map_coreop[".error_1"] = function(params)
696 if not params then return "message" end
697 werror(params[1])
698end
699
700map_coreop[".fatal_1"] = function(params)
701 if not params then return "message" end
702 wfatal(params[1])
703end
704
705-- Dump all user defined elements.
706local 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)
714end
715
716------------------------------------------------------------------------------
717
718-- Helper for splitstmt.
719local splitlvl
720
721local 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
735end
736
737-- Split statement into (pseudo-)opcode and params.
738local 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
761end
762
763-- Process a single statement.
764dostmt = 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
802end
803
804-- Process a single line.
805local 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
847end
848
849------------------------------------------------------------------------------
850
851-- Write DynASM header.
852local 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))
868end
869
870-- Read input file.
871readfile = 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())
887end
888
889-- Write output file.
890local 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)
908end
909
910-- Translate an input file to an output file.
911local 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)
949end
950
951------------------------------------------------------------------------------
952
953-- Print help text.
954function 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
959Usage: 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)
982end
983
984-- Print version information.
985function 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)
989end
990
991-- Misc. options.
992function opt_map.outfile(args) g_opt.outfile = optparam(args) end
993function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
994function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
995function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
996function opt_map.nocomment() g_opt.comment = false end
997function opt_map.maccomment() g_opt.maccomment = true end
998function opt_map.nolineno() g_opt.cpp = false end
999function opt_map.flushline() g_opt.flushline = true end
1000function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
1001
1002------------------------------------------------------------------------------
1003
1004-- Short aliases for long options.
1005local 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.
1014local 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)
1021end
1022
1023-- Parse arguments.
1024local 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)
1061end
1062
1063------------------------------------------------------------------------------
1064
1065-- Add the directory dynasm.lua resides in to the Lua module search path.
1066local arg = arg
1067if arg and arg[0] then
1068 local prefix = match(arg[0], "^(.*[/\\])")
1069 if prefix then package.path = prefix.."?.lua;"..package.path end
1070end
1071
1072-- Start DynASM.
1073parseargs{...}
1074
1075------------------------------------------------------------------------------
1076