tasmparser.nim 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. # bug #1513
  2. import os, parseutils, strutils, ropes, macros
  3. var
  4. code {.compileTime.} = ""
  5. start {.compileTime.} = 0
  6. line {.compileTime.} = 1
  7. cpp {.compileTime.} = ""
  8. token {.compileTime.} = ""
  9. proc log(msg: string) {.compileTime.} =
  10. echo msg
  11. proc asmx64() {.compileTime} =
  12. #log "code = $1" % code
  13. const asmx64pre = "{.emit: \"\"\"{x64asm& x= *x64asm_ptr(`asm0`); try {"
  14. const asmx64post = "} catch (Xbyak::Error e) { printf (\"asmx64 error: %s\\n\", e.what ()); }}\"\"\".} "
  15. const xp = "x."
  16. const symbolStart = { '_', 'a'..'z', 'A' .. 'Z' }
  17. const symbol = { '0'..'9' } + symbolStart
  18. const eolComment = { ';' }
  19. const endOfLine = { '\l', '\r' }
  20. const leadingWhiteSpace = { ' ' }
  21. const end_or_comment = endOfLine + eolComment + { '\0' }
  22. const passthrough_start = { '{', '`' }
  23. const passthrough_end = { '}', '`', '\0' }
  24. const end_or_symbol_or_comment_or_passthrough = symbolStart + end_or_comment + passthrough_start
  25. proc abortAsmParse(err:string) =
  26. discard
  27. let codeLen = code.len
  28. #let codeEnd = codeLen-1
  29. cpp.add asmx64pre
  30. #log "{$1}\n" % [code]
  31. type asmParseState = enum leading, mnemonic, betweenArguments, arguments, endCmd, skipToEndOfLine
  32. var state:asmParseState = leading
  33. proc checkEnd(err:string) =
  34. let ch = code[start]
  35. if int(ch) == 0:
  36. abortAsmParse(err)
  37. proc get_passthrough() =
  38. inc start
  39. let prev_start = start
  40. let prev_token = token
  41. start += code.parseUntil(token, passthrough_end, start)
  42. 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]])
  43. inc start
  44. cpp.add "`"
  45. cpp.add token
  46. cpp.add "`"
  47. var inparse = true
  48. proc checkCmdEnd() =
  49. if codeLen == start:
  50. state = endCmd
  51. inparse = false
  52. while inparse:
  53. checkCmdEnd()
  54. log("state=$1 start=$2" % [$state, $start])
  55. case state:
  56. of leading:
  57. echo "b100 ", start
  58. start += code.skipWhile(leadingWhiteSpace, start)
  59. echo "b200 ", start
  60. let ch = code[start]
  61. if ch in endOfLine:
  62. inc(line)
  63. #echo "c100 ", start, ' ', code
  64. start += code.skipWhile(endOfline, start)
  65. #echo "c200 ", start, ' ', code
  66. continue
  67. elif ch in symbolStart:
  68. state = mnemonic
  69. elif ch in eolComment:
  70. state = skipToEndOfLine
  71. elif ch in passthrough_start:
  72. get_passthrough()
  73. echo "d100 ", start
  74. start += code.parseUntil(token, end_or_symbol_or_comment_or_passthrough, start)
  75. echo "d200 ", start
  76. cpp.add token
  77. state = mnemonic
  78. elif int(ch) == 0:
  79. break
  80. else:
  81. abortAsmParse("after '$3' illegal character at offset $1: $2" % [$start, $(int(ch)), token])
  82. of mnemonic:
  83. echo "e100 ", start
  84. start += code.parseWhile(token, symbol, start)
  85. echo "e200 ", start
  86. cpp.add xp
  87. cpp.add token
  88. cpp.add "("
  89. state = betweenArguments
  90. of betweenArguments:
  91. let tmp = start
  92. let rcode = code
  93. start += rcode.parseUntil(token, end_or_symbol_or_comment_or_passthrough, tmp)
  94. cpp.add token
  95. if codeLen <= start:
  96. state = endCmd
  97. continue
  98. let ch = code[start]
  99. if ch in passthrough_start:
  100. get_passthrough()
  101. continue
  102. if(ch in {'x', 'X'}) and('0' == code[start-1]):
  103. token = $(code[start])
  104. cpp.add token
  105. inc start
  106. continue
  107. state = arguments
  108. of arguments:
  109. if code[start] in end_or_comment:
  110. state = endCmd
  111. continue
  112. start += code.parseWhile(token, symbol, start)
  113. cpp.add xp
  114. cpp.add token
  115. state = betweenArguments
  116. of endCmd:
  117. cpp.add ");\n"
  118. state = skipToEndOfLine
  119. of skipToEndOfLine:
  120. echo "a100 ", start
  121. start += code.skipUntil(endOfLine, start)
  122. echo "a200 ", start
  123. start += code.skipWhile(endOfline, start)
  124. echo "a300 ", start
  125. inc line
  126. state = leading
  127. cpp.add asmx64post
  128. echo($cpp)
  129. macro asmx64x(code_in:untyped) : typed =
  130. code = $code_in
  131. echo("code.len = $1, code = >>>$2<<<" % [$code.len, code])
  132. asmx64()
  133. discard result
  134. asmx64x """
  135. mov rax, {m}
  136. ret
  137. """