summary refs log tree commit diff stats
path: root/tests/vm/tasmparser.nim
blob: d70c629b641562c881781a8ad9a3b515372cd100 (plain) (blame)
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
"""