# bug #1513 import os, parseutils, strutils, ropes, macros var code {.compileTime.} = "" start {.compileTime.} = 0 line {.compileTime.} = 1 cpp {.compileTime.} = "" token {.compileTime.} = "" proc log(msg: string) {.compileTime.} = echo msg proc asmx64() {.compileTime} = #log "code = $1" % code const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {" const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} " const xp = "x." const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' } const symbol = { '0'..'9' } + symbolStart const eolComment = { ';' } const endOfLine = { '\l', '\r' } const leadingWhiteSpace = { ' ' } const end_or_comment = endOfLine + eolComment + { '\0' } const passthrough_start = { '{', '`' } const passthrough_end = { '}', '`', '\0' } const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start proc abortAsmParse(err:string) = discard let codeLen = code.len #let codeEnd = codeLen-1 cpp.add asmx64pre #log "{$1}\n" % [code] type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine var state:asmParseState = leading proc checkEnd(err:string) = let ch = code[start] if int(ch) == 0: abortAsmParse(err) proc get_passthrough() = inc start let prev_start = start let prev_token = token start += code.parseUntil(token, passthrough_end, start) checkEnd("Failed to find passthrough end delimiter from offset $1 for:$2\n$3" % [$prev_start, $(code[prev_start-prev_token.len..prev_start]), token[1..token.len-1]]) inc start cpp.add "`" cpp.add token cpp.add "`" var inparse = true proc checkCmdEnd() = if codeLen == start: state = endCmd inparse = false while inparse: checkCmdEnd() log("state=$1 start=$2" % [$state, $start]) case state: of leading: echo "b100 ", start start += code.skipWhile(leadingWhiteSpace, start) echo "b200 ", start let ch = code[start] if ch in endOfLine: inc(line) #echo "c100 ", start, ' ', code start += code.skipWhile(endOfline, start) #echo "c200 ", start, ' ', code continue elif ch in symbolStart: state = mnemonic elif ch in eolComment: state = skipToEndOfLine elif ch in passthrough_start: get_passthrough() echo "d100 ", start start += code.parseUntil(token, end_or_symbol_or_comment_or_passthrough, start) echo "d200 ", start cpp.add token state = mnemonic elif int(ch) == 0: break else: abortAsmParse("after '$3' illegal character at offset $1: $2" % [$start, $(int(ch)), token]) of mnemonic: echo "e100 ", start start += code.parseWhile(token, symbol, start) echo "e200 ", start cpp.add xp cpp.add token cpp.add "(" state = betweenArguments of betweenArguments: let tmp = start let rcode = code start += rcode.parseUntil(token, end_or_symbol_or_comment_or_passthrough, tmp) cpp.add token if codeLen <= start: state = endCmd continue let ch = code[start] if ch in passthrough_start: get_passthrough() continue if(ch in {'x', 'X'}) and('0' == code[start-1]): token = $(code[start]) cpp.add token inc start continue state = arguments of arguments: if code[start] in end_or_comment: state = endCmd continue start += code.parseWhile(token, symbol, start) cpp.add xp cpp.add token state = betweenArguments of endCmd: cpp.add ");\n" state = skipToEndOfLine of skipToEndOfLine: echo "a100 ", start start += code.skipUntil(endOfLine, start) echo "a200 ", start start += code.skipWhile(endOfline, start) echo "a300 ", start inc line state = leading cpp.add asmx64post echo($cpp) macro asmx64x(code_in:untyped) : typed = code = $code_in echo("code.len = $1, code = >>>$2<<<" % [$code.len, code]) asmx64() discard result asmx64x """ mov rax, {m} ret """