1 ------------------------------------------------------------------------------
2 -- DynASM. A dynamic assembler for code generation engines.
3 -- Originally designed and implemented for LuaJIT.
5 -- Copyright (C) 2005-2023 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
= "2021-05-02",
17 url
= "https://luajit.org/dynasm.html",
20 Copyright (C) 2005-2023 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: https://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("#line "..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
)
264 func
, err
= loadstring("return "..cond
, "=expr")
266 -- No globals. All unknown identifiers evaluate to nil.
267 func
, err
= load("return "..cond
, "=expr", "t", {})
271 setfenv(func
, {}) -- No globals. All unknown identifiers evaluate to nil.
273 local ok
, res
= pcall(func
)
275 if res
== 0 then return false end -- Oh well.
280 wfatal("bad condition: "..err
)
283 -- Skip statements until next conditional pseudo-opcode at the same level.
284 local function stmtskip()
285 local dostmt_save
= dostmt
287 dostmt
= function(stmt
)
288 local op
= match(stmt
, "^%s*(%S+)")
292 if op
== ".endif" then lvl
= lvl
- 1 end
293 elseif op
== ".elif" or op
== ".else" or op
== ".endif" then
300 -- Pseudo-opcodes for conditional assembly.
301 map_coreop
[".if_1"] = function(params
)
302 if not params
then return "condition" end
303 local lvl
= condlevel
+ 1
304 local res
= cond_eval(params
[1])
307 if not res
then stmtskip() end
310 map_coreop
[".elif_1"] = function(params
)
311 if not params
then return "condition" end
312 if condlevel
== 0 then wfatal(".elif without .if") end
313 local lvl
= condlevel
314 local res
= condstack
[lvl
]
316 if res
== "else" then wfatal(".elif after .else") end
318 res
= cond_eval(params
[1])
327 map_coreop
[".else_0"] = function(params
)
328 if condlevel
== 0 then wfatal(".else without .if") end
329 local lvl
= condlevel
330 local res
= condstack
[lvl
]
331 condstack
[lvl
] = "else"
333 if res
== "else" then wfatal(".else after .else") end
338 map_coreop
[".endif_0"] = function(params
)
339 local lvl
= condlevel
340 if lvl
== 0 then wfatal(".endif without .if") end
344 -- Check for unfinished conditionals.
345 local function checkconds()
346 if g_errcount
~= "fatal" and condlevel
~= 0 then
347 wprinterr(g_fname
, ":*: error: unbalanced conditional\n")
351 ------------------------------------------------------------------------------
353 -- Search for a file in the given path and open it for reading.
354 local function pathopen(path
, name
)
355 local dirsep
= package
and match(package
.path
, "\\") and "\\" or "/"
356 for _
,p
in ipairs(path
) do
357 local fullname
= p
== "" and name
or p
..dirsep
..name
358 local fin
= io
.open(fullname
, "r")
367 map_coreop
[".include_1"] = function(params
)
368 if not params
then return "filename" end
369 local name
= params
[1]
370 -- Save state. Ugly, I know. but upvalues are fast.
371 local gf
, gl
, gcl
, gi
= g_fname
, g_lineno
, g_curline
, g_indent
372 -- Read the included file.
373 local fatal
= readfile(pathopen(g_opt
.include
, name
) or
374 wfatal("include file `"..name
.."' not found"))
377 g_fname
, g_lineno
, g_curline
, g_indent
= gf
, gl
, gcl
, gi
378 if fatal
then wfatal("in include file") end
381 -- Make .include and conditionals initially available, too.
382 map_op
[".include_1"] = map_coreop
[".include_1"]
383 map_op
[".if_1"] = map_coreop
[".if_1"]
384 map_op
[".elif_1"] = map_coreop
[".elif_1"]
385 map_op
[".else_0"] = map_coreop
[".else_0"]
386 map_op
[".endif_0"] = map_coreop
[".endif_0"]
388 ------------------------------------------------------------------------------
390 -- Support variables for macros.
391 local mac_capture
, mac_lineno
, mac_name
392 local mac_active
= {}
395 -- Pseudo-opcode to define a macro.
396 map_coreop
[".macro_*"] = function(mparams
)
397 if not mparams
then return "name [, params...]" end
398 -- Split off and validate macro name.
399 local name
= remove(mparams
, 1)
400 if not name
then werror("missing macro name") end
401 if not (match(name
, "^[%a_][%w_%.]*$") or match(name
, "^%.[%w_%.]*$")) then
402 wfatal("bad macro name `"..name
.."'")
404 -- Validate macro parameter names.
406 for _
,mp
in ipairs(mparams
) do
407 if not match(mp
, "^[%a_][%w_]*$") then
408 wfatal("bad macro parameter name `"..mp
.."'")
410 if mdup
[mp
] then wfatal("duplicate macro parameter name `"..mp
.."'") end
413 -- Check for duplicate or recursive macro definitions.
414 local opname
= name
.."_"..#mparams
415 if map_op
[opname
] or map_op
[name
.."_*"] then
416 wfatal("duplicate macro `"..name
.."' ("..#mparams
.." parameters)")
418 if mac_capture
then wfatal("recursive macro definition") end
420 -- Enable statement capture.
422 mac_lineno
= g_lineno
424 mac_capture
= function(stmt
) -- Statement capture function.
425 -- Stop macro definition with .endmacro pseudo-opcode.
426 if not match(stmt
, "^%s*.endmacro%s*$") then
427 lines
[#lines
+1] = stmt
433 mac_list
[#mac_list
+1] = opname
434 -- Add macro-op definition.
435 map_op
[opname
] = function(params
)
436 if not params
then return mparams
, lines
end
437 -- Protect against recursive macro invocation.
438 if mac_active
[opname
] then wfatal("recursive macro invocation") end
439 mac_active
[opname
] = true
440 -- Setup substitution map.
442 for i
,mp
in ipairs(mparams
) do subst
[mp
] = params
[i
] end
444 if g_opt
.maccomment
and g_opt
.comment
then
445 mcom
= " MACRO "..name
.." ("..#mparams
..")"
448 -- Loop through all captured statements
449 for _
,stmt
in ipairs(lines
) do
450 -- Substitute macro parameters.
451 local st
= gsub(stmt
, "[%w_]+", subst
)
453 st
= gsub(st
, "%s*%.%.%s*", "") -- Token paste a..b.
454 if mcom
and sub(st
, 1, 1) ~= "|" then wcomment(st
) end
455 -- Emit statement. Use a protected call for better diagnostics.
456 local ok
, err
= pcall(dostmt
, st
)
458 -- Add the captured statement to the error.
459 wprinterr(err
, "\n", g_indent
, "| ", stmt
,
460 "\t[MACRO ", name
, " (", #mparams
, ")]\n")
463 if mcom
then wcomment("}"..mcom
) end
464 mac_active
[opname
] = nil
469 -- An .endmacro pseudo-opcode outside of a macro definition is an error.
470 map_coreop
[".endmacro_0"] = function(params
)
471 wfatal(".endmacro without .macro")
474 -- Dump all macros and their contents (with -PP only).
475 local function dumpmacros(out
, lvl
)
477 out
:write("Macros:\n")
478 for _
,opname
in ipairs(mac_list
) do
479 local name
= sub(opname
, 1, -3)
480 local params
, lines
= map_op
[opname
]()
481 out
:write(format(" %-20s %s\n", name
, concat(params
, ", ")))
483 for _
,line
in ipairs(lines
) do
484 out
:write(" |", line
, "\n")
492 -- Check for unfinished macro definitions.
493 local function checkmacros()
495 wprinterr(g_fname
, ":", mac_lineno
,
496 ": error: unfinished .macro `", mac_name
,"'\n")
500 ------------------------------------------------------------------------------
502 -- Support variables for captures.
503 local cap_lineno
, cap_name
504 local cap_buffers
= {}
508 map_coreop
[".capture_1"] = function(params
)
509 if not params
then return "name" end
511 local name
= params
[1]
512 if not match(name
, "^[%a_][%w_]*$") then
513 wfatal("bad capture name `"..name
.."'")
516 wfatal("already capturing to `"..cap_name
.."' since line "..cap_lineno
)
519 cap_lineno
= g_lineno
520 -- Create or continue a capture buffer and start the output line capture.
521 local buf
= cap_buffers
[name
]
522 if not buf
then buf
= {}; cap_buffers
[name
] = buf
end
528 map_coreop
[".endcapture_0"] = function(params
)
530 if not cap_name
then wfatal(".endcapture without a valid .capture") end
537 -- Dump a capture buffer.
538 map_coreop
[".dumpcapture_1"] = function(params
)
539 if not params
then return "name" end
541 local name
= params
[1]
542 if not match(name
, "^[%a_][%w_]*$") then
543 wfatal("bad capture name `"..name
.."'")
545 cap_used
[name
] = true
547 local buf
= cap_buffers
[name
]
548 if buf
then wdumplines(out
, buf
) end
553 -- Dump all captures and their buffers (with -PP only).
554 local function dumpcaptures(out
, lvl
)
555 out
:write("Captures:\n")
556 for name
,buf
in pairs(cap_buffers
) do
557 out
:write(format(" %-20s %4s)\n", name
, "("..#buf
))
559 local bar
= rep("=", 76)
560 out
:write(" ", bar
, "\n")
561 for _
,line
in ipairs(buf
) do
562 out
:write(" ", line
, "\n")
564 out
:write(" ", bar
, "\n\n")
570 -- Check for unfinished or unused captures.
571 local function checkcaptures()
573 wprinterr(g_fname
, ":", cap_lineno
,
574 ": error: unfinished .capture `", cap_name
,"'\n")
577 for name
in pairs(cap_buffers
) do
578 if not cap_used
[name
] then
579 wprinterr(g_fname
, ":*: error: missing .dumpcapture ", name
,"\n")
584 ------------------------------------------------------------------------------
587 local map_sections
= {}
589 -- Pseudo-opcode to define code sections.
590 -- TODO: Data sections, BSS sections. Needs extra C code and API.
591 map_coreop
[".section_*"] = function(params
)
592 if not params
then return "name..." end
593 if #map_sections
> 0 then werror("duplicate section definition") end
595 for sn
,name
in ipairs(params
) do
596 local opname
= "."..name
.."_0"
597 if not match(name
, "^[%a][%w_]*$") or
598 map_op
[opname
] or map_op
["."..name
.."_*"] then
599 werror("bad section name `"..name
.."'")
601 map_sections
[#map_sections
+1] = name
602 wline(format("#define DASM_SECTION_%s\t%d", upper(name
), sn
-1))
603 map_op
[opname
] = function(params
) g_arch
.section(sn
-1) end
605 wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections
))
608 -- Dump all sections.
609 local function dumpsections(out
, lvl
)
610 out
:write("Sections:\n")
611 for _
,name
in ipairs(map_sections
) do
612 out
:write(format(" %s\n", name
))
617 ------------------------------------------------------------------------------
619 -- Replacement for customized Lua, which lacks the package library.
622 function require(name
)
623 local fp
= assert(io
.open(prefix
..name
..".lua"))
624 local s
= fp
:read("*a")
626 return assert(loadstring(s
, "@"..name
..".lua"))()
630 -- Load architecture-specific module.
631 local function loadarch(arch
)
632 if not match(arch
, "^[%w_]+$") then return "bad arch name" end
633 _G
._map_def
= map_def
634 local ok
, m_arch
= pcall(require
, "dasm_"..arch
)
635 if not ok
then return "cannot load module: "..m_arch
end
637 wflush
= m_arch
.passcb(wline
, werror
, wfatal
, wwarn
)
638 m_arch
.setup(arch
, g_opt
)
639 map_op
, map_def
= m_arch
.mergemaps(map_coreop
, map_def
)
642 -- Dump architecture description.
643 function opt_map
.dumparch(args
)
644 local name
= optparam(args
)
646 local err
= loadarch(name
)
647 if err
then opterror(err
) end
651 for name
in pairs(map_coreop
) do t
[#t
+1] = name
end
652 for name
in pairs(map_op
) do t
[#t
+1] = name
end
656 local _arch
= g_arch
._info
657 out
:write(format("%s version %s, released %s, %s\n",
658 _info
.name
, _info
.version
, _info
.release
, _info
.url
))
662 out
:write("Pseudo-Opcodes:\n")
663 for _
,sname
in ipairs(t
) do
664 local name
, nparam
= match(sname
, "^(.+)_([0-9%*])$")
666 if pseudo
and sub(name
, 1, 1) ~= "." then
667 out
:write("\nOpcodes:\n")
670 local f
= map_op
[sname
]
672 if nparam
~= "*" then nparam
= nparam
+ 0 end
675 elseif type(f
) == "string" then
676 s
= map_op
[".template__"](nil, f
, nparam
)
680 if type(s
) == "table" then
681 for _
,s2
in ipairs(s
) do
682 out
:write(format(" %-12s %s\n", name
, s2
))
685 out
:write(format(" %-12s %s\n", name
, s
))
693 -- Pseudo-opcode to set the architecture.
694 -- Only initially available (map_op is replaced when called).
695 map_op
[".arch_1"] = function(params
)
696 if not params
then return "name" end
697 local err
= loadarch(params
[1])
698 if err
then wfatal(err
) end
699 wline(format("#if DASM_VERSION != %d", _info
.vernum
))
700 wline('#error "Version mismatch between DynASM and included encoding engine"')
704 -- Dummy .arch pseudo-opcode to improve the error report.
705 map_coreop
[".arch_1"] = function(params
)
706 if not params
then return "name" end
707 wfatal("duplicate .arch statement")
710 ------------------------------------------------------------------------------
712 -- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
713 map_coreop
[".nop_*"] = function(params
)
714 if not params
then return "[ignored...]" end
717 -- Pseudo-opcodes to raise errors.
718 map_coreop
[".error_1"] = function(params
)
719 if not params
then return "message" end
723 map_coreop
[".fatal_1"] = function(params
)
724 if not params
then return "message" end
728 -- Dump all user defined elements.
729 local function dumpdef(out
)
730 local lvl
= g_opt
.dumpdef
731 if lvl
== 0 then return end
732 dumpsections(out
, lvl
)
733 dumpdefines(out
, lvl
)
734 if g_arch
then g_arch
.dumpdef(out
, lvl
) end
736 dumpcaptures(out
, lvl
)
739 ------------------------------------------------------------------------------
741 -- Helper for splitstmt.
744 local function splitstmt_one(c
)
746 splitlvl
= ")"..splitlvl
748 splitlvl
= "]"..splitlvl
750 splitlvl
= "}"..splitlvl
751 elseif c
== ")" or c
== "]" or c
== "}" then
752 if sub(splitlvl
, 1, 1) ~= c
then werror("unbalanced (), [] or {}") end
753 splitlvl
= sub(splitlvl
, 2)
754 elseif splitlvl
== "" then
760 -- Split statement into (pseudo-)opcode and params.
761 local function splitstmt(stmt
)
762 -- Convert label with trailing-colon into .label statement.
763 local label
= match(stmt
, "^%s*(.+):%s*$")
764 if label
then return ".label", {label
} end
766 -- Split at commas and equal signs, but obey parentheses and brackets.
768 stmt
= gsub(stmt
, "[,%(%)%[%]{}]", splitstmt_one
)
769 if splitlvl
~= "" then werror("unbalanced () or []") end
772 local op
, other
= match(stmt
, "^%s*([^%s%z]+)%s*(.*)$")
773 if not op
then werror("bad statement syntax") end
777 for p
in gmatch(other
, "%s*(%Z+)%z?") do
778 params
[#params
+1] = gsub(p
, "%s+$", "")
780 if #params
> 16 then werror("too many parameters") end
786 -- Process a single statement.
787 dostmt
= function(stmt
)
788 -- Ignore empty statements.
789 if match(stmt
, "^%s*$") then return end
791 -- Capture macro defs before substitution.
792 if mac_capture
then return mac_capture(stmt
) end
793 stmt
= definesubst(stmt
)
795 -- Emit C code without parsing the line.
796 if sub(stmt
, 1, 1) == "|" then
797 local tail
= sub(stmt
, 2)
799 if sub(tail
, 1, 2) == "//" then wcomment(tail
) else wline(tail
, true) end
803 -- Split into (pseudo-)opcode and params.
804 local op
, params
= splitstmt(stmt
)
806 -- Get opcode handler (matching # of parameters or generic handler).
807 local f
= map_op
[op
.."_"..#params
] or map_op
[op
.."_*"]
809 if not g_arch
then wfatal("first statement must be .arch") end
810 -- Improve error report.
812 if map_op
[op
.."_"..i
] then
813 werror("wrong number of parameters for `"..op
.."'")
816 werror("unknown statement `"..op
.."'")
819 -- Call opcode handler or special handler for template strings.
820 if type(f
) == "string" then
821 map_op
[".template__"](params
, f
)
827 -- Process a single line.
828 local function doline(line
)
829 if g_opt
.flushline
then wflush() end
832 local indent
, aline
= match(line
, "^(%s*)%|(.*)$")
834 -- No, plain C code line, need to flush first.
841 g_indent
= indent
-- Remember current line indentation.
843 -- Emit C code (even from macros). Avoids echo and line parsing.
844 if sub(aline
, 1, 1) == "|" then
845 if not mac_capture
then
847 elseif g_opt
.comment
then
855 -- Echo assembler line as a comment.
856 if g_opt
.comment
then
861 -- Strip assembler comments.
862 aline
= gsub(aline
, "//.*$", "")
864 -- Split line into statements at semicolons.
865 if match(aline
, ";") then
866 for stmt
in gmatch(aline
, "[^;]+") do dostmt(stmt
) end
872 ------------------------------------------------------------------------------
874 -- Write DynASM header.
875 local function dasmhead(out
)
878 ** This file has been pre-processed with DynASM.
880 ** DynASM version %s, DynASM %s version %s
881 ** DO NOT EDIT! The original file is in "%s".
885 _info
.version
, g_arch
._info
.arch
, g_arch
._info
.version
,
890 readfile
= function(fin
)
895 -- Process all lines.
896 for line
in fin
:lines() do
897 g_lineno
= g_lineno
+ 1
899 local ok
, err
= pcall(doline
, line
)
900 if not ok
and wprinterr(err
, "\n") then return true end
905 assert(fin
== stdin
or fin
:close())
908 -- Write output file.
909 local function writefile(outfile
)
913 if outfile
== nil or outfile
== "-" then
916 fout
= assert(io
.open(outfile
, "w"))
919 -- Write all buffered lines
920 wdumplines(fout
, g_wbuffer
)
922 -- Close output file.
923 assert(fout
== stdout
or fout
:close())
925 -- Optionally dump definitions.
926 dumpdef(fout
== stdout
and stderr
or stdout
)
929 -- Translate an input file to an output file.
930 local function translate(infile
, outfile
)
941 if infile
== "-" then
946 fin
= assert(io
.open(infile
, "r"))
952 wprinterr(g_fname
, ":*: error: missing .arch directive\n")
958 if g_errcount
~= 0 then
959 stderr
:write(g_fname
, ":*: info: ", g_errcount
, " error",
960 (type(g_errcount
) == "number" and g_errcount
> 1) and "s" or "",
961 " in input file -- no output file generated.\n")
966 -- Write output file.
970 ------------------------------------------------------------------------------
973 function opt_map
.help()
974 stdout
:write("DynASM -- ", _info
.description
, ".\n")
975 stdout
:write("DynASM ", _info
.version
, " ", _info
.release
, " ", _info
.url
, "\n")
978 Usage: dynasm [OPTION]... INFILE.dasc|-
980 -h, --help Display this help text.
981 -V, --version Display version and copyright information.
983 -o, --outfile FILE Output file name (default is stdout).
984 -I, --include DIR Add directory to the include search path.
986 -c, --ccomment Use /* */ comments for assembler lines.
987 -C, --cppcomment Use // comments for assembler lines (default).
988 -N, --nocomment Suppress assembler lines in output.
989 -M, --maccomment Show macro expansions as comments (default off).
991 -L, --nolineno Suppress CPP line number information in output.
992 -F, --flushline Flush action list for every line.
994 -D NAME[=SUBST] Define a substitution.
995 -U NAME Undefine a substitution.
997 -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
998 -A, --dumparch ARCH Load architecture ARCH and dump description.
1003 -- Print version information.
1004 function opt_map
.version()
1005 stdout
:write(format("%s version %s, released %s\n%s\n\n%s",
1006 _info
.name
, _info
.version
, _info
.release
, _info
.url
, _info
.copyright
))
1011 function opt_map
.outfile(args
) g_opt
.outfile
= optparam(args
) end
1012 function opt_map
.include(args
) insert(g_opt
.include
, 1, optparam(args
)) end
1013 function opt_map
.ccomment() g_opt
.comment
= "/*|"; g_opt
.endcomment
= " */" end
1014 function opt_map
.cppcomment() g_opt
.comment
= "//|"; g_opt
.endcomment
= "" end
1015 function opt_map
.nocomment() g_opt
.comment
= false end
1016 function opt_map
.maccomment() g_opt
.maccomment
= true end
1017 function opt_map
.nolineno() g_opt
.cpp
= false end
1018 function opt_map
.flushline() g_opt
.flushline
= true end
1019 function opt_map
.dumpdef() g_opt
.dumpdef
= g_opt
.dumpdef
+ 1 end
1021 ------------------------------------------------------------------------------
1023 -- Short aliases for long options.
1025 h
= "help", ["?"] = "help", V
= "version",
1026 o
= "outfile", I
= "include",
1027 c
= "ccomment", C
= "cppcomment", N
= "nocomment", M
= "maccomment",
1028 L
= "nolineno", F
= "flushline",
1029 P
= "dumpdef", A
= "dumparch",
1032 -- Parse single option.
1033 local function parseopt(opt
, args
)
1034 opt_current
= #opt
== 1 and "-"..opt
or "--"..opt
1035 local f
= opt_map
[opt
] or opt_map
[opt_alias
[opt]]
1037 opterror("unrecognized option `", opt_current
, "'. Try `--help'.\n")
1043 local function parseargs(args
)
1045 g_opt
.comment
= "//|"
1046 g_opt
.endcomment
= ""
1049 g_opt
.include
= { "" }
1051 -- Process all option arguments.
1054 local a
= args
[args
.argn
]
1055 if not a
then break end
1056 local lopt
, opt
= match(a
, "^%-(%-?)(.+)")
1057 if not opt
then break end
1058 args
.argn
= args
.argn
+ 1
1060 -- Loop through short options.
1061 for o
in gmatch(opt
, ".") do parseopt(o
, args
) end
1068 -- Check for proper number of arguments.
1069 local nargs
= #args
- args
.argn
+ 1
1072 if g_opt
.dumpdef
> 0 then return dumpdef(stdout
) end
1077 -- Translate a single input file to a single output file
1078 -- TODO: Handle multiple files?
1079 translate(args
[args
.argn
], g_opt
.outfile
)
1082 ------------------------------------------------------------------------------
1084 -- Add the directory dynasm.lua resides in to the Lua module search path.
1086 if arg
and arg
[0] then
1087 prefix
= match(arg
[0], "^(.*[/\\])")
1088 if package
and prefix
then package
.path
= prefix
.."?.lua;"..package
.path
end
1094 ------------------------------------------------------------------------------