FFI: Fix line info for result conversion errors in callbacks.
[luajit-2.0.git] / dynasm / dynasm.lua
blob8ff9851324731dffc58e7d484133bd3f68ebff5f
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 ------------------------------------------------------------------------------
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.
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:
30 The above copyright notice and this permission notice shall be
31 included in all copies or substantial portions of the Software.
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.
41 [ MIT license: http://www.opensource.org/licenses/mit-license.php ]
42 ]],
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
57 ------------------------------------------------------------------------------
59 -- Program options.
60 local g_opt = {}
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
66 -- Write buffer for output file.
67 local g_wbuffer, g_capbuffer
69 ------------------------------------------------------------------------------
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
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
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
93 -- Dummy action flush function. Replaced with arch-specific function later.
94 local function wflush(term)
95 end
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)
109 ------------------------------------------------------------------------------
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)
116 -- Emit a fatal error. Processing stops.
117 local function wfatal(msg)
118 g_errcount = "fatal"
119 werror(msg)
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))
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")
139 else
140 -- Fatal error.
141 stderr:write(...)
142 return true -- Stop processing.
146 ------------------------------------------------------------------------------
148 -- Map holding all option handlers.
149 local opt_map = {}
150 local opt_current
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)
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, "'.")
166 args.argn = argn + 1
167 return p
170 ------------------------------------------------------------------------------
172 -- Core pseudo-opcodes.
173 local map_coreop = {}
174 -- Dummy opcode map. Replaced by arch-specific map.
175 local map_op = {}
177 -- Forward declarations.
178 local dostmt
179 local readfile
181 ------------------------------------------------------------------------------
183 -- Map for defines (initially empty, chains to arch-specific map).
184 local map_def = {}
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
193 map_coreop[".define_1"] = map_coreop[".define_2"]
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")
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")
218 -- Helper for definesubst.
219 local gotsubst
221 local function definesubst_one(word)
222 local subst = map_def[word]
223 if subst then gotsubst = word; return subst else return word end
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
234 if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end
235 return stmt
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
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))
251 out:write("\n")
254 ------------------------------------------------------------------------------
256 -- Support variables for conditional assembly.
257 local condlevel = 0
258 local condstack = {}
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
270 err = res
272 wfatal("bad condition: "..err)
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)
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
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
316 stmtskip()
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()
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
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")
343 ------------------------------------------------------------------------------
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
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
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"]
380 ------------------------------------------------------------------------------
382 -- Support variables for macros.
383 local mac_capture, mac_lineno, mac_name
384 local mac_active = {}
385 local mac_list = {}
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.."'")
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.."'")
402 if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
403 mdup[mp] = true
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)")
410 if mac_capture then wfatal("recursive macro definition") end
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
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)
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")
455 if mcom then wcomment("}"..mcom) end
456 mac_active[opname] = nil
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")
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")
478 out:write("\n")
481 out:write("\n")
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")
492 ------------------------------------------------------------------------------
494 -- Support variables for captures.
495 local cap_lineno, cap_name
496 local cap_buffers = {}
497 local cap_used = {}
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.."'")
507 if cap_name then
508 wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
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
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
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.."'")
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
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")
556 out:write(" ", bar, "\n\n")
559 out:write("\n")
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
569 for name in pairs(cap_buffers) do
570 if not cap_used[name] then
571 wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
576 ------------------------------------------------------------------------------
578 -- Sections names.
579 local map_sections = {}
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.."'")
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
597 wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
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))
606 out:write("\n")
609 ------------------------------------------------------------------------------
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)
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
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)
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)
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
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)
660 if type(s) == "table" then
661 for _,s2 in ipairs(s) do
662 out:write(format(" %-12s %s\n", name, s2))
664 else
665 out:write(format(" %-12s %s\n", name, s))
669 out:write("\n")
670 exit(0)
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
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")
687 ------------------------------------------------------------------------------
689 -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
690 map_coreop[".nop_*"] = function(params)
691 if not params then return "[ignored...]" end
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])
700 map_coreop[".fatal_1"] = function(params)
701 if not params then return "message" end
702 wfatal(params[1])
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)
716 ------------------------------------------------------------------------------
718 -- Helper for splitstmt.
719 local splitlvl
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 "
734 return c
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
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
748 -- Split off opcode.
749 local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
750 if not op then werror("bad statement syntax") end
752 -- Split parameters.
753 local params = {}
754 for p in gmatch(other, "%s*(%Z+)%z?") do
755 params[#params+1] = gsub(p, "%s+$", "")
757 if #params > 16 then werror("too many parameters") end
759 params.op = op
760 return op, params
763 -- Process a single statement.
764 dostmt = function(stmt)
765 -- Ignore empty statements.
766 if match(stmt, "^%s*$") then return end
768 -- Capture macro defs before substitution.
769 if mac_capture then return mac_capture(stmt) end
770 stmt = definesubst(stmt)
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
780 -- Split into (pseudo-)opcode and params.
781 local op, params = splitstmt(stmt)
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.."'")
793 werror("unknown statement `"..op.."'")
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)
804 -- Process a single line.
805 local function doline(line)
806 if g_opt.flushline then wflush() end
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
818 g_indent = indent -- Remember current line indentation.
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)
828 dostmt(aline)
829 return
832 -- Echo assembler line as a comment.
833 if g_opt.comment then
834 wsync()
835 wcomment(aline)
838 -- Strip assembler comments.
839 aline = gsub(aline, "//.*$", "")
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)
849 ------------------------------------------------------------------------------
851 -- Write DynASM header.
852 local function dasmhead(out)
853 out:write(format([[
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".
861 #if DASM_VERSION != %d
862 #error "Version mismatch between DynASM and included encoding engine"
863 #endif
865 ]], _info.url,
866 _info.version, g_arch._info.arch, g_arch._info.version,
867 g_fname, _info.vernum))
870 -- Read input file.
871 readfile = function(fin)
872 g_indent = ""
873 g_lineno = 0
874 g_synclineno = -1
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
883 wflush()
885 -- Close input file.
886 assert(fin == stdin or fin:close())
889 -- Write output file.
890 local function writefile(outfile)
891 local fout
893 -- Open output file.
894 if outfile == nil or outfile == "-" then
895 fout = stdout
896 else
897 fout = assert(io.open(outfile, "w"))
900 -- Write all buffered lines
901 wdumplines(fout, g_wbuffer)
903 -- Close output file.
904 assert(fout == stdout or fout:close())
906 -- Optionally dump definitions.
907 dumpdef(fout == stdout and stderr or stdout)
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
917 -- Put header.
918 wline(dasmhead)
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"))
929 readfile(fin)
931 -- Check for errors.
932 if not g_arch then
933 wprinterr(g_fname, ":*: error: missing .arch directive\n")
935 checkconds()
936 checkmacros()
937 checkcaptures()
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)
947 -- Write output file.
948 writefile(outfile)
951 ------------------------------------------------------------------------------
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[[
959 Usage: dynasm [OPTION]... INFILE.dasc|-
961 -h, --help Display this help text.
962 -V, --version Display version and copyright information.
964 -o, --outfile FILE Output file name (default is stdout).
965 -I, --include DIR Add directory to the include search path.
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).
972 -L, --nolineno Suppress CPP line number information in output.
973 -F, --flushline Flush action list for every line.
975 -D NAME[=SUBST] Define a substitution.
976 -U NAME Undefine a substitution.
978 -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
979 -A, --dumparch ARCH Load architecture ARCH and dump description.
981 exit(0)
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)
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
1002 ------------------------------------------------------------------------------
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",
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")
1020 f(args)
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 = { "" }
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)
1047 until false
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
1055 opt_map.help()
1058 -- Translate a single input file to a single output file
1059 -- TODO: Handle multiple files?
1060 translate(args[args.argn], g_opt.outfile)
1063 ------------------------------------------------------------------------------
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
1072 -- Start DynASM.
1073 parseargs{...}
1075 ------------------------------------------------------------------------------