1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
# 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
"""
|