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