1 ------------------------------------------------------------------------------
2 -- DynASM. A dynamic assembler for code generation engines.
3 -- Originally designed and implemented for LuaJIT.
5 -- Copyright (C) 2005-2011 Mike Pall. All rights reserved.
6 -- See below for full copyright notice.
7 ------------------------------------------------------------------------------
9 -- Application information.
12 description
= "A dynamic assembler for code generation engines",
15 release
= "2011-05-05",
17 url
= "http://luajit.org/dynasm.html",
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 ]
45 -- Cache library functions.
46 local type, pairs
, ipairs
= type, pairs
, ipairs
47 local pcall
, error, assert = pcall
, error, assert
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
52 local insert
, remove, concat
, sort = _t
.insert
, _t
.remove, _t
.concat
, _t
.sort
55 local stdin
, stdout
, stderr
= io
.stdin
, io
.stdout
, io
.stderr
57 ------------------------------------------------------------------------------
62 -- Global state for current file.
63 local g_fname
, g_curline
, g_indent
, g_lineno
, g_synclineno
, g_arch
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
78 -- Write assembler line as a comment, if requestd.
79 local function wcomment(aline
)
81 wline(g_opt
.comment
..aline
..g_opt
.endcomment
, true)
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
93 -- Dummy action flush function. Replaced with arch-specific function later.
94 local function wflush(term
)
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"))
103 -- Special callback to dynamically insert lines after end of processing.
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
)
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
132 g_errcount
= g_errcount
+ 1
133 if g_errcount
< 21 then -- Seems to be a reasonable limit.
135 elseif g_errcount
== 21 then
136 stderr
:write(g_fname
,
137 ":*: warning: too many errors (suppressed further messages).\n")
142 return true -- Stop processing.
146 ------------------------------------------------------------------------------
148 -- Map holding all option handlers.
152 -- Print error and exit with error status.
153 local function opterror(...)
154 stderr
:write("dynasm.lua: ERROR: ", ...)
159 -- Get option parameter.
160 local function optparam(args
)
161 local argn
= args
.argn
164 opterror("missing parameter for option `", opt_current
, "'.")
170 ------------------------------------------------------------------------------
172 -- Core pseudo-opcodes.
173 local map_coreop
= {}
174 -- Dummy opcode map. Replaced by arch-specific map.
177 -- Forward declarations.
181 ------------------------------------------------------------------------------
183 -- Map for defines (initially empty, chains to arch-specific map).
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
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_]*)=(.*)$")
200 map_def
[name
] = subst
201 elseif match(namesubst
, "^[%a_][%w_]*$") then
202 map_def
[namesubst
] = "1"
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
214 opterror("bad define")
218 -- Helper for definesubst.
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.
231 stmt
= gsub(stmt
, "#?[%w_]+", definesubst_one
)
232 if not gotsubst
then break end
234 if gotsubst
then wfatal("recursive define involving `"..gotsubst
.."'") end
239 local function dumpdefines(out
, lvl
)
241 for name
in pairs(map_def
) do
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
))
254 ------------------------------------------------------------------------------
256 -- Support variables for conditional assembly.
260 -- Evaluate condition with a Lua expression. Substitutions already performed.
261 local function cond_eval(cond
)
262 local func
, err
= loadstring("return "..cond
)
264 setfenv(func
, {}) -- No globals. All unknown identifiers evaluate to nil.
265 local ok
, res
= pcall(func
)
267 if res
== 0 then return false end -- Oh well.
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
279 dostmt
= function(stmt
)
280 local op
= match(stmt
, "^%s*(%S+)")
284 if op
== ".endif" then lvl
= lvl
- 1 end
285 elseif op
== ".elif" or op
== ".else" or op
== ".endif" then
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])
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
]
308 if res
== "else" then wfatal(".elif after .else") end
310 res
= cond_eval(params
[1])
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"
325 if res
== "else" then wfatal(".else after .else") end
330 map_coreop
[".endif_0"] = function(params
)
331 local lvl
= condlevel
332 if lvl
== 0 then wfatal(".endif without .if") end
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")
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"))
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
= {}
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.
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
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.
414 mac_lineno
= g_lineno
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
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.
434 for i
,mp
in ipairs(mparams
) do subst
[mp
] = params
[i
] end
436 if g_opt
.maccomment
and g_opt
.comment
then
437 mcom
= " MACRO "..name
.." ("..#mparams
..")"
440 -- Loop through all captured statements
441 for _
,stmt
in ipairs(lines
) do
442 -- Substitute macro parameters.
443 local st
= gsub(stmt
, "[%w_]+", subst
)
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
)
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
)
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
, ", ")))
475 for _
,line
in ipairs(lines
) do
476 out
:write(" |", line
, "\n")
484 -- Check for unfinished macro definitions.
485 local function checkmacros()
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
= {}
500 map_coreop
[".capture_1"] = function(params
)
501 if not params
then return "name" end
503 local name
= params
[1]
504 if not match(name
, "^[%a_][%w_]*$") then
505 wfatal("bad capture name `"..name
.."'")
508 wfatal("already capturing to `"..cap_name
.."' since line "..cap_lineno
)
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
520 map_coreop
[".endcapture_0"] = function(params
)
522 if not cap_name
then wfatal(".endcapture without a valid .capture") end
529 -- Dump a capture buffer.
530 map_coreop
[".dumpcapture_1"] = function(params
)
531 if not params
then return "name" end
533 local name
= params
[1]
534 if not match(name
, "^[%a_][%w_]*$") then
535 wfatal("bad capture name `"..name
.."'")
537 cap_used
[name
] = true
539 local buf
= cap_buffers
[name
]
540 if buf
then wdumplines(out
, buf
) end
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
))
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")
562 -- Check for unfinished or unused captures.
563 local function checkcaptures()
565 wprinterr(g_fname
, ":", cap_lineno
,
566 ": error: unfinished .capture `", cap_name
,"'\n")
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 ------------------------------------------------------------------------------
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
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
))
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
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
)
626 local err
= loadarch(name
)
627 if err
then opterror(err
) end
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
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
))
642 out
:write("Pseudo-Opcodes:\n")
643 for _
,sname
in ipairs(t
) do
644 local name
, nparam
= match(sname
, "^(.+)_([0-9%*])$")
646 if pseudo
and sub(name
, 1, 1) ~= "." then
647 out
:write("\nOpcodes:\n")
650 local f
= map_op
[sname
]
652 if nparam
~= "*" then nparam
= nparam
+ 0 end
655 elseif type(f
) == "string" then
656 s
= map_op
[".template__"](nil, f
, nparam
)
660 if type(s
) == "table" then
661 for _
,s2
in ipairs(s
) do
662 out
:write(format(" %-12s %s\n", name
, s2
))
665 out
:write(format(" %-12s %s\n", name
, s
))
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
700 map_coreop
[".fatal_1"] = function(params
)
701 if not params
then return "message" end
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
713 dumpcaptures(out
, lvl
)
716 ------------------------------------------------------------------------------
718 -- Helper for splitstmt.
721 local function splitstmt_one(c
)
723 splitlvl
= ")"..splitlvl
725 splitlvl
= "]"..splitlvl
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
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.
745 stmt
= gsub(stmt
, "[,%(%)%[%]{}]", splitstmt_one
)
746 if splitlvl
~= "" then werror("unbalanced () or []") end
749 local op
, other
= match(stmt
, "^%s*([^%s%z]+)%s*(.*)$")
750 if not op
then werror("bad statement syntax") end
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
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)
776 if sub(tail
, 1, 2) == "//" then wcomment(tail
) else wline(tail
, true) end
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
.."_*"]
786 if not g_arch
then wfatal("first statement must be .arch") end
787 -- Improve error report.
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
)
804 -- Process a single line.
805 local function doline(line
)
806 if g_opt
.flushline
then wflush() end
809 local indent
, aline
= match(line
, "^(%s*)%|(.*)$")
811 -- No, plain C code line, need to flush first.
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
824 elseif g_opt
.comment
then
832 -- Echo assembler line as a comment.
833 if g_opt
.comment
then
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
849 ------------------------------------------------------------------------------
851 -- Write DynASM header.
852 local function dasmhead(out
)
855 ** This file has been pre-processed with DynASM.
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"
866 _info
.version
, g_arch
._info
.arch
, g_arch
._info
.version
,
867 g_fname
, _info
.vernum
))
871 readfile
= function(fin
)
876 -- Process all lines.
877 for line
in fin
:lines() do
878 g_lineno
= g_lineno
+ 1
880 local ok
, err
= pcall(doline
, line
)
881 if not ok
and wprinterr(err
, "\n") then return true end
886 assert(fin
== stdin
or fin
:close())
889 -- Write output file.
890 local function writefile(outfile
)
894 if outfile
== nil or outfile
== "-" then
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
)
922 if infile
== "-" then
927 fin
= assert(io
.open(infile
, "r"))
933 wprinterr(g_fname
, ":*: error: missing .arch directive\n")
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")
947 -- Write output file.
951 ------------------------------------------------------------------------------
954 function opt_map
.help()
955 stdout
:write("DynASM -- ", _info
.description
, ".\n")
956 stdout
:write("DynASM ", _info
.version
, " ", _info
.release
, " ", _info
.url
, "\n")
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.
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
))
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.
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]]
1018 opterror("unrecognized option `", opt_current
, "'. Try `--help'.\n")
1024 local function parseargs(args
)
1026 g_opt
.comment
= "//|"
1027 g_opt
.endcomment
= ""
1030 g_opt
.include
= { "" }
1032 -- Process all option arguments.
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
1041 -- Loop through short options.
1042 for o
in gmatch(opt
, ".") do parseopt(o
, args
) end
1049 -- Check for proper number of arguments.
1050 local nargs
= #args
- args
.argn
+ 1
1053 if g_opt
.dumpdef
> 0 then return dumpdef(stdout
) end
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.
1067 if arg
and arg
[0] then
1068 local prefix
= match(arg
[0], "^(.*[/\\])")
1069 if prefix
then package
.path
= prefix
.."?.lua;"..package
.path
end
1075 ------------------------------------------------------------------------------