aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/LuaJIT-1.1.7/dynasm/dynasm.lua
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/LuaJIT-1.1.7/dynasm/dynasm.lua')
-rw-r--r--libraries/LuaJIT-1.1.7/dynasm/dynasm.lua1070
1 files changed, 0 insertions, 1070 deletions
diff --git a/libraries/LuaJIT-1.1.7/dynasm/dynasm.lua b/libraries/LuaJIT-1.1.7/dynasm/dynasm.lua
deleted file mode 100644
index 264a4bb..0000000
--- a/libraries/LuaJIT-1.1.7/dynasm/dynasm.lua
+++ /dev/null
@@ -1,1070 +0,0 @@
1------------------------------------------------------------------------------
2-- DynASM. A dynamic assembler for code generation engines.
3-- Originally designed and implemented for LuaJIT.
4--
5-- Copyright (C) 2005-2008 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.1.4",
14 vernum = 10104,
15 release = "2008-01-29",
16 author = "Mike Pall",
17 url = "http://luajit.org/dynasm.html",
18 license = "MIT",
19 copyright = [[
20Copyright (C) 2005-2008 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 initially available, too.
374map_op[".include_1"] = map_coreop[".include_1"]
375
376------------------------------------------------------------------------------
377
378-- Support variables for macros.
379local mac_capture, mac_lineno, mac_name
380local mac_active = {}
381local mac_list = {}
382
383-- Pseudo-opcode to define a macro.
384map_coreop[".macro_*"] = function(mparams)
385 if not mparams then return "name [, params...]" end
386 -- Split off and validate macro name.
387 local name = remove(mparams, 1)
388 if not name then werror("missing macro name") end
389 if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]+$")) then
390 wfatal("bad macro name `"..name.."'")
391 end
392 -- Validate macro parameter names.
393 local mdup = {}
394 for _,mp in ipairs(mparams) do
395 if not match(mp, "^[%a_][%w_]*$") then
396 wfatal("bad macro parameter name `"..mp.."'")
397 end
398 if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end
399 mdup[mp] = true
400 end
401 -- Check for duplicate or recursive macro definitions.
402 local opname = name.."_"..#mparams
403 if map_op[opname] or map_op[name.."_*"] then
404 wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)")
405 end
406 if mac_capture then wfatal("recursive macro definition") end
407
408 -- Enable statement capture.
409 local lines = {}
410 mac_lineno = g_lineno
411 mac_name = name
412 mac_capture = function(stmt) -- Statement capture function.
413 -- Stop macro definition with .endmacro pseudo-opcode.
414 if not match(stmt, "^%s*.endmacro%s*$") then
415 lines[#lines+1] = stmt
416 return
417 end
418 mac_capture = nil
419 mac_lineno = nil
420 mac_name = nil
421 mac_list[#mac_list+1] = opname
422 -- Add macro-op definition.
423 map_op[opname] = function(params)
424 if not params then return mparams, lines end
425 -- Protect against recursive macro invocation.
426 if mac_active[opname] then wfatal("recursive macro invocation") end
427 mac_active[opname] = true
428 -- Setup substitution map.
429 local subst = {}
430 for i,mp in ipairs(mparams) do subst[mp] = params[i] end
431 local mcom
432 if g_opt.maccomment and g_opt.comment then
433 mcom = " MACRO "..name.." ("..#mparams..")"
434 wcomment("{"..mcom)
435 end
436 -- Loop through all captured statements
437 for _,stmt in ipairs(lines) do
438 -- Substitute macro parameters.
439 local st = gsub(stmt, "[%w_]+", subst)
440 st = definesubst(st)
441 st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b.
442 if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end
443 -- Emit statement. Use a protected call for better diagnostics.
444 local ok, err = pcall(dostmt, st)
445 if not ok then
446 -- Add the captured statement to the error.
447 wprinterr(err, "\n", g_indent, "| ", stmt,
448 "\t[MACRO ", name, " (", #mparams, ")]\n")
449 end
450 end
451 if mcom then wcomment("}"..mcom) end
452 mac_active[opname] = nil
453 end
454 end
455end
456
457-- An .endmacro pseudo-opcode outside of a macro definition is an error.
458map_coreop[".endmacro_0"] = function(params)
459 wfatal(".endmacro without .macro")
460end
461
462-- Dump all macros and their contents (with -PP only).
463local function dumpmacros(out, lvl)
464 sort(mac_list)
465 out:write("Macros:\n")
466 for _,opname in ipairs(mac_list) do
467 local name = sub(opname, 1, -3)
468 local params, lines = map_op[opname]()
469 out:write(format(" %-20s %s\n", name, concat(params, ", ")))
470 if lvl > 1 then
471 for _,line in ipairs(lines) do
472 out:write(" |", line, "\n")
473 end
474 out:write("\n")
475 end
476 end
477 out:write("\n")
478end
479
480-- Check for unfinished macro definitions.
481local function checkmacros()
482 if mac_capture then
483 wprinterr(g_fname, ":", mac_lineno,
484 ": error: unfinished .macro `", mac_name ,"'\n")
485 end
486end
487
488------------------------------------------------------------------------------
489
490-- Support variables for captures.
491local cap_lineno, cap_name
492local cap_buffers = {}
493local cap_used = {}
494
495-- Start a capture.
496map_coreop[".capture_1"] = function(params)
497 if not params then return "name" end
498 wflush()
499 local name = params[1]
500 if not match(name, "^[%a_][%w_]*$") then
501 wfatal("bad capture name `"..name.."'")
502 end
503 if cap_name then
504 wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno)
505 end
506 cap_name = name
507 cap_lineno = g_lineno
508 -- Create or continue a capture buffer and start the output line capture.
509 local buf = cap_buffers[name]
510 if not buf then buf = {}; cap_buffers[name] = buf end
511 g_capbuffer = buf
512 g_synclineno = 0
513end
514
515-- Stop a capture.
516map_coreop[".endcapture_0"] = function(params)
517 wflush()
518 if not cap_name then wfatal(".endcapture without a valid .capture") end
519 cap_name = nil
520 cap_lineno = nil
521 g_capbuffer = nil
522 g_synclineno = 0
523end
524
525-- Dump a capture buffer.
526map_coreop[".dumpcapture_1"] = function(params)
527 if not params then return "name" end
528 wflush()
529 local name = params[1]
530 if not match(name, "^[%a_][%w_]*$") then
531 wfatal("bad capture name `"..name.."'")
532 end
533 cap_used[name] = true
534 wline(function(out)
535 local buf = cap_buffers[name]
536 if buf then wdumplines(out, buf) end
537 end)
538 g_synclineno = 0
539end
540
541-- Dump all captures and their buffers (with -PP only).
542local function dumpcaptures(out, lvl)
543 out:write("Captures:\n")
544 for name,buf in pairs(cap_buffers) do
545 out:write(format(" %-20s %4s)\n", name, "("..#buf))
546 if lvl > 1 then
547 local bar = rep("=", 76)
548 out:write(" ", bar, "\n")
549 for _,line in ipairs(buf) do
550 out:write(" ", line, "\n")
551 end
552 out:write(" ", bar, "\n\n")
553 end
554 end
555 out:write("\n")
556end
557
558-- Check for unfinished or unused captures.
559local function checkcaptures()
560 if cap_name then
561 wprinterr(g_fname, ":", cap_lineno,
562 ": error: unfinished .capture `", cap_name,"'\n")
563 return
564 end
565 for name in pairs(cap_buffers) do
566 if not cap_used[name] then
567 wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n")
568 end
569 end
570end
571
572------------------------------------------------------------------------------
573
574-- Sections names.
575local map_sections = {}
576
577-- Pseudo-opcode to define code sections.
578-- TODO: Data sections, BSS sections. Needs extra C code and API.
579map_coreop[".section_*"] = function(params)
580 if not params then return "name..." end
581 if #map_sections > 0 then werror("duplicate section definition") end
582 wflush()
583 for sn,name in ipairs(params) do
584 local opname = "."..name.."_0"
585 if not match(name, "^[%a][%w_]*$") or
586 map_op[opname] or map_op["."..name.."_*"] then
587 werror("bad section name `"..name.."'")
588 end
589 map_sections[#map_sections+1] = name
590 wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1))
591 map_op[opname] = function(params) g_arch.section(sn-1) end
592 end
593 wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections))
594end
595
596-- Dump all sections.
597local function dumpsections(out, lvl)
598 out:write("Sections:\n")
599 for _,name in ipairs(map_sections) do
600 out:write(format(" %s\n", name))
601 end
602 out:write("\n")
603end
604
605------------------------------------------------------------------------------
606
607-- Load architecture-specific module.
608local function loadarch(arch)
609 if not match(arch, "^[%w_]+$") then return "bad arch name" end
610 local ok, m_arch = pcall(require, "dasm_"..arch)
611 if not ok then return "cannot load module: "..m_arch end
612 g_arch = m_arch
613 wflush = m_arch.passcb(wline, werror, wfatal, wwarn)
614 m_arch.setup(arch, g_opt)
615 map_op, map_def = m_arch.mergemaps(map_coreop, map_def)
616end
617
618-- Dump architecture description.
619function opt_map.dumparch(args)
620 local name = optparam(args)
621 if not g_arch then
622 local err = loadarch(name)
623 if err then opterror(err) end
624 end
625
626 local t = {}
627 for name in pairs(map_coreop) do t[#t+1] = name end
628 for name in pairs(map_op) do t[#t+1] = name end
629 sort(t)
630
631 local out = stdout
632 local _arch = g_arch._info
633 out:write(format("%s version %s, released %s, %s\n",
634 _info.name, _info.version, _info.release, _info.url))
635 g_arch.dumparch(out)
636
637 local pseudo = true
638 out:write("Pseudo-Opcodes:\n")
639 for _,sname in ipairs(t) do
640 local name, nparam = match(sname, "^(.+)_([0-9%*])$")
641 if name then
642 if pseudo and sub(name, 1, 1) ~= "." then
643 out:write("\nOpcodes:\n")
644 pseudo = false
645 end
646 local f = map_op[sname]
647 local s
648 if nparam ~= "*" then nparam = nparam + 0 end
649 if nparam == 0 then
650 s = ""
651 elseif type(f) == "string" then
652 s = map_op[".template__"](nil, f, nparam)
653 else
654 s = f(nil, nparam)
655 end
656 if type(s) == "table" then
657 for _,s2 in ipairs(s) do
658 out:write(format(" %-12s %s\n", name, s2))
659 end
660 else
661 out:write(format(" %-12s %s\n", name, s))
662 end
663 end
664 end
665 out:write("\n")
666 exit(0)
667end
668
669-- Pseudo-opcode to set the architecture.
670-- Only initially available (map_op is replaced when called).
671map_op[".arch_1"] = function(params)
672 if not params then return "name" end
673 local err = loadarch(params[1])
674 if err then wfatal(err) end
675end
676
677-- Dummy .arch pseudo-opcode to improve the error report.
678map_coreop[".arch_1"] = function(params)
679 if not params then return "name" end
680 wfatal("duplicate .arch statement")
681end
682
683------------------------------------------------------------------------------
684
685-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'.
686map_coreop[".nop_*"] = function(params)
687 if not params then return "[ignored...]" end
688end
689
690-- Pseudo-opcodes to raise errors.
691map_coreop[".error_1"] = function(params)
692 if not params then return "message" end
693 werror(params[1])
694end
695
696map_coreop[".fatal_1"] = function(params)
697 if not params then return "message" end
698 wfatal(params[1])
699end
700
701-- Dump all user defined elements.
702local function dumpdef(out)
703 local lvl = g_opt.dumpdef
704 if lvl == 0 then return end
705 dumpsections(out, lvl)
706 dumpdefines(out, lvl)
707 if g_arch then g_arch.dumpdef(out, lvl) end
708 dumpmacros(out, lvl)
709 dumpcaptures(out, lvl)
710end
711
712------------------------------------------------------------------------------
713
714-- Helper for splitstmt.
715local splitlvl
716
717local function splitstmt_one(c)
718 if c == "(" then
719 splitlvl = ")"..splitlvl
720 elseif c == "[" then
721 splitlvl = "]"..splitlvl
722 elseif c == ")" or c == "]" then
723 if sub(splitlvl, 1, 1) ~= c then werror("unbalanced () or []") end
724 splitlvl = sub(splitlvl, 2)
725 elseif splitlvl == "" then
726 return " \0 "
727 end
728 return c
729end
730
731-- Split statement into (pseudo-)opcode and params.
732local function splitstmt(stmt)
733 -- Convert label with trailing-colon into .label statement.
734 local label = match(stmt, "^%s*(.+):%s*$")
735 if label then return ".label", {label} end
736
737 -- Split at commas and equal signs, but obey parentheses and brackets.
738 splitlvl = ""
739 stmt = gsub(stmt, "[,%(%)%[%]]", splitstmt_one)
740 if splitlvl ~= "" then werror("unbalanced () or []") end
741
742 -- Split off opcode.
743 local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$")
744 if not op then werror("bad statement syntax") end
745
746 -- Split parameters.
747 local params = {}
748 for p in gmatch(other, "%s*(%Z+)%z?") do
749 params[#params+1] = gsub(p, "%s+$", "")
750 end
751 if #params > 16 then werror("too many parameters") end
752
753 params.op = op
754 return op, params
755end
756
757-- Process a single statement.
758dostmt = function(stmt)
759 -- Ignore empty statements.
760 if match(stmt, "^%s*$") then return end
761
762 -- Capture macro defs before substitution.
763 if mac_capture then return mac_capture(stmt) end
764 stmt = definesubst(stmt)
765
766 -- Emit C code without parsing the line.
767 if sub(stmt, 1, 1) == "|" then
768 local tail = sub(stmt, 2)
769 wflush()
770 if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end
771 return
772 end
773
774 -- Split into (pseudo-)opcode and params.
775 local op, params = splitstmt(stmt)
776
777 -- Get opcode handler (matching # of parameters or generic handler).
778 local f = map_op[op.."_"..#params] or map_op[op.."_*"]
779 if not f then
780 if not g_arch then wfatal("first statement must be .arch") end
781 -- Improve error report.
782 for i=0,16 do
783 if map_op[op.."_"..i] then
784 werror("wrong number of parameters for `"..op.."'")
785 end
786 end
787 werror("unknown statement `"..op.."'")
788 end
789
790 -- Call opcode handler or special handler for template strings.
791 if type(f) == "string" then
792 map_op[".template__"](params, f)
793 else
794 f(params)
795 end
796end
797
798-- Process a single line.
799local function doline(line)
800 if g_opt.flushline then wflush() end
801
802 -- Assembler line?
803 local indent, aline = match(line, "^(%s*)%|(.*)$")
804 if not aline then
805 -- No, plain C code line, need to flush first.
806 wflush()
807 wsync()
808 wline(line, false)
809 return
810 end
811
812 g_indent = indent -- Remember current line indentation.
813
814 -- Emit C code (even from macros). Avoids echo and line parsing.
815 if sub(aline, 1, 1) == "|" then
816 if not mac_capture then
817 wsync()
818 elseif g_opt.comment then
819 wsync()
820 wcomment(aline)
821 end
822 dostmt(aline)
823 return
824 end
825
826 -- Echo assembler line as a comment.
827 if g_opt.comment then
828 wsync()
829 wcomment(aline)
830 end
831
832 -- Strip assembler comments.
833 aline = gsub(aline, "//.*$", "")
834
835 -- Split line into statements at semicolons.
836 if match(aline, ";") then
837 for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end
838 else
839 dostmt(aline)
840 end
841end
842
843------------------------------------------------------------------------------
844
845-- Write DynASM header.
846local function dasmhead(out)
847 out:write(format([[
848/*
849** This file has been pre-processed with DynASM.
850** %s
851** DynASM version %s, DynASM %s version %s
852** DO NOT EDIT! The original file is in "%s".
853*/
854
855#if DASM_VERSION != %d
856#error "Version mismatch between DynASM and included encoding engine"
857#endif
858
859]], _info.url,
860 _info.version, g_arch._info.arch, g_arch._info.version,
861 g_fname, _info.vernum))
862end
863
864-- Read input file.
865readfile = function(fin)
866 g_indent = ""
867 g_lineno = 0
868 g_synclineno = -1
869
870 -- Process all lines.
871 for line in fin:lines() do
872 g_lineno = g_lineno + 1
873 g_curline = line
874 local ok, err = pcall(doline, line)
875 if not ok and wprinterr(err, "\n") then return true end
876 end
877 wflush()
878
879 -- Close input file.
880 assert(fin == stdin or fin:close())
881end
882
883-- Write output file.
884local function writefile(outfile)
885 local fout
886
887 -- Open output file.
888 if outfile == nil or outfile == "-" then
889 fout = stdout
890 else
891 fout = assert(io.open(outfile, "w"))
892 end
893
894 -- Write all buffered lines
895 wdumplines(fout, g_wbuffer)
896
897 -- Close output file.
898 assert(fout == stdout or fout:close())
899
900 -- Optionally dump definitions.
901 dumpdef(fout == stdout and stderr or stdout)
902end
903
904-- Translate an input file to an output file.
905local function translate(infile, outfile)
906 g_wbuffer = {}
907 g_indent = ""
908 g_lineno = 0
909 g_synclineno = -1
910
911 -- Put header.
912 wline(dasmhead)
913
914 -- Read input file.
915 local fin
916 if infile == "-" then
917 g_fname = "(stdin)"
918 fin = stdin
919 else
920 g_fname = infile
921 fin = assert(io.open(infile, "r"))
922 end
923 readfile(fin)
924
925 -- Check for errors.
926 if not g_arch then
927 wprinterr(g_fname, ":*: error: missing .arch directive\n")
928 end
929 checkconds()
930 checkmacros()
931 checkcaptures()
932
933 if g_errcount ~= 0 then
934 stderr:write(g_fname, ":*: info: ", g_errcount, " error",
935 (type(g_errcount) == "number" and g_errcount > 1) and "s" or "",
936 " in input file -- no output file generated.\n")
937 dumpdef(stderr)
938 exit(1)
939 end
940
941 -- Write output file.
942 writefile(outfile)
943end
944
945------------------------------------------------------------------------------
946
947-- Print help text.
948function opt_map.help()
949 stdout:write("DynASM -- ", _info.description, ".\n")
950 stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n")
951 stdout:write[[
952
953Usage: dynasm [OPTION]... INFILE.dasc|-
954
955 -h, --help Display this help text.
956 -V, --version Display version and copyright information.
957
958 -o, --outfile FILE Output file name (default is stdout).
959 -I, --include DIR Add directory to the include search path.
960
961 -c, --ccomment Use /* */ comments for assembler lines.
962 -C, --cppcomment Use // comments for assembler lines (default).
963 -N, --nocomment Suppress assembler lines in output.
964 -M, --maccomment Show macro expansions as comments (default off).
965
966 -L, --nolineno Suppress CPP line number information in output.
967 -F, --flushline Flush action list for every line.
968
969 -D NAME[=SUBST] Define a substitution.
970 -U NAME Undefine a substitution.
971
972 -P, --dumpdef Dump defines, macros, etc. Repeat for more output.
973 -A, --dumparch ARCH Load architecture ARCH and dump description.
974]]
975 exit(0)
976end
977
978-- Print version information.
979function opt_map.version()
980 stdout:write(format("%s version %s, released %s\n%s\n\n%s",
981 _info.name, _info.version, _info.release, _info.url, _info.copyright))
982 exit(0)
983end
984
985-- Misc. options.
986function opt_map.outfile(args) g_opt.outfile = optparam(args) end
987function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end
988function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end
989function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end
990function opt_map.nocomment() g_opt.comment = false end
991function opt_map.maccomment() g_opt.maccomment = true end
992function opt_map.nolineno() g_opt.cpp = false end
993function opt_map.flushline() g_opt.flushline = true end
994function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end
995
996------------------------------------------------------------------------------
997
998-- Short aliases for long options.
999local opt_alias = {
1000 h = "help", ["?"] = "help", V = "version",
1001 o = "outfile", I = "include",
1002 c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment",
1003 L = "nolineno", F = "flushline",
1004 P = "dumpdef", A = "dumparch",
1005}
1006
1007-- Parse single option.
1008local function parseopt(opt, args)
1009 opt_current = #opt == 1 and "-"..opt or "--"..opt
1010 local f = opt_map[opt] or opt_map[opt_alias[opt]]
1011 if not f then
1012 opterror("unrecognized option `", opt_current, "'. Try `--help'.\n")
1013 end
1014 f(args)
1015end
1016
1017-- Parse arguments.
1018local function parseargs(args)
1019 -- Default options.
1020 g_opt.comment = "//|"
1021 g_opt.endcomment = ""
1022 g_opt.cpp = true
1023 g_opt.dumpdef = 0
1024 g_opt.include = { "" }
1025
1026 -- Process all option arguments.
1027 args.argn = 1
1028 repeat
1029 local a = args[args.argn]
1030 if not a then break end
1031 local lopt, opt = match(a, "^%-(%-?)(.+)")
1032 if not opt then break end
1033 args.argn = args.argn + 1
1034 if lopt == "" then
1035 -- Loop through short options.
1036 for o in gmatch(opt, ".") do parseopt(o, args) end
1037 else
1038 -- Long option.
1039 parseopt(opt, args)
1040 end
1041 until false
1042
1043 -- Check for proper number of arguments.
1044 local nargs = #args - args.argn + 1
1045 if nargs ~= 1 then
1046 if nargs == 0 then
1047 if g_opt.dumpdef > 0 then return dumpdef(stdout) end
1048 end
1049 opt_map.help()
1050 end
1051
1052 -- Translate a single input file to a single output file
1053 -- TODO: Handle multiple files?
1054 translate(args[args.argn], g_opt.outfile)
1055end
1056
1057------------------------------------------------------------------------------
1058
1059-- Add the directory dynasm.lua resides in to the Lua module search path.
1060local arg = arg
1061if arg and arg[0] then
1062 local prefix = match(arg[0], "^(.*/)")
1063 if prefix then package.path = prefix.."?.lua;"..package.path end
1064end
1065
1066-- Start DynASM.
1067parseargs{...}
1068
1069------------------------------------------------------------------------------
1070