lol its in c
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

289 lines
8.8 KiB

  1. import sys
  2. import re
  3. ## Need to convert asxxxx syntax to rgbds syntax
  4. module = sys.argv[1]
  5. class Token:
  6. def __init__(self, kind, value, line_nr):
  7. self.kind = kind
  8. self.value = value
  9. self.line_nr = line_nr
  10. def isA(self, kind, value=None):
  11. return self.kind == kind and (value is None or value == self.value)
  12. def __repr__(self):
  13. return "[%s:%s:%d]" % (self.kind, self.value, self.line_nr)
  14. class Tokenizer:
  15. TOKEN_REGEX = re.compile(
  16. "|".join(
  17. "(?P<%s>%s)" % pair
  18. for pair in [
  19. ("HEX", r"0x[0-9A-Fa-f]+"),
  20. ("ASSIGN", r"="),
  21. ("ALABEL", r"\d+\$"),
  22. ("NUMBER", r"\d+(\.\d*)?"),
  23. ("COMMENT", r";[^\n]*"),
  24. ("LABEL", r":+"),
  25. ("EXPR", r"#"),
  26. ("STRING", '"[^"]*"'),
  27. ("DIRECTIVE", r"\.[A-Za-z_][A-Za-z0-9_\.]*"),
  28. ("ID", r"[A-Za-z_][A-Za-z0-9_\.]*"),
  29. ("OP", r"[+\-*/,\(\)<>]"),
  30. ("NEWLINE", r"\n"),
  31. ("SKIP", r"[ \t]+"),
  32. ("MISMATCH", r"."),
  33. ]
  34. )
  35. )
  36. def __init__(self, code):
  37. self.__tokens = []
  38. line_num = 1
  39. for mo in self.TOKEN_REGEX.finditer(code):
  40. kind = mo.lastgroup
  41. value = mo.group()
  42. if kind == "MISMATCH":
  43. print("ERR:", code.split("\n")[line_num - 1])
  44. raise RuntimeError("Syntax error on line: %d: %s\n%s", line_num, value)
  45. elif kind == "SKIP":
  46. pass
  47. else:
  48. if kind == "HEX":
  49. value = "$" + value[2:]
  50. if kind == "ALABEL":
  51. value = "._ANNO_" + value[:-1]
  52. kind = "ID"
  53. self.__tokens.append(Token(kind, value, line_num))
  54. if kind == "NEWLINE":
  55. line_num += 1
  56. self.__tokens.append(Token("NEWLINE", "\n", line_num))
  57. def peek(self):
  58. return self.__tokens[0]
  59. def pop(self):
  60. return self.__tokens.pop(0)
  61. def expect(self, kind, value=None):
  62. pop = self.pop()
  63. if not pop.isA(kind, value):
  64. if value is not None:
  65. raise SyntaxError("%s != %s:%s" % (pop, kind, value))
  66. raise SyntaxError("%s != %s" % (pop, kind))
  67. def __bool__(self):
  68. return bool(self.__tokens)
  69. tok = Tokenizer(sys.stdin.read())
  70. global_names = set()
  71. def processExpression():
  72. while True:
  73. t = tok.peek()
  74. if t.isA("EXPR"):
  75. tok.pop()
  76. t = tok.peek()
  77. if t.isA("OP", "<"):
  78. sys.stdout.write("LOW")
  79. tok.pop()
  80. t = tok.peek()
  81. if t.isA("OP", ">"):
  82. sys.stdout.write("HIGH")
  83. tok.pop()
  84. t = tok.peek()
  85. if t.isA("OP", "("):
  86. tok.pop()
  87. sys.stdout.write("(")
  88. processExpression()
  89. t = tok.pop()
  90. assert t.isA("OP", ")")
  91. sys.stdout.write(")")
  92. if t.isA("ID") and t.value.startswith("b_"):
  93. t.value = "BANK(%s)" % (t.value[1:])
  94. if t.isA("NEWLINE") or t.isA("OP", ")") or t.isA("OP", ","):
  95. break
  96. sys.stdout.write(t.value)
  97. tok.pop()
  98. def processParameter():
  99. t = tok.pop()
  100. if t.isA("EXPR"):
  101. processExpression()
  102. elif t.isA("NEWLINE"):
  103. return
  104. elif t.isA("ID") or t.isA("NUMBER") or t.isA("HEX"):
  105. sys.stdout.write(t.value)
  106. elif t.isA("OP", "("):
  107. sys.stdout.write("[")
  108. processExpression()
  109. t = tok.pop()
  110. while not t.isA("OP", ")"):
  111. sys.stdout.write(t.value)
  112. t = tok.pop()
  113. assert t.isA("OP", ")"), t
  114. sys.stdout.write("]")
  115. else:
  116. raise Exception(t)
  117. class AnyStr:
  118. def __eq__(self, other) -> bool:
  119. return isinstance(other, str)
  120. BYTE_ADDR_PATTERN = [
  121. "(",
  122. AnyStr(),
  123. "+",
  124. "0",
  125. ")",
  126. ",",
  127. "(",
  128. "(",
  129. AnyStr(),
  130. "+",
  131. "0",
  132. ")",
  133. ">",
  134. ">",
  135. "8",
  136. ")",
  137. "\n",
  138. ]
  139. ID_PATTERN_IDX1 = 1
  140. ID_PATTERN_IDX2 = 8
  141. def processByteAddr():
  142. tokens = [tok.pop().value for _ in range(17)]
  143. assert tokens == BYTE_ADDR_PATTERN
  144. assert tokens[ID_PATTERN_IDX1] == tokens[ID_PATTERN_IDX2]
  145. addr = tokens[ID_PATTERN_IDX1]
  146. sys.stdout.write(f"LOW({addr}), HIGH({addr})")
  147. while tok:
  148. start = tok.pop()
  149. if start.isA("NEWLINE"):
  150. pass
  151. elif start.isA("COMMENT"):
  152. print(start.value)
  153. elif start.isA("DIRECTIVE"):
  154. if start.value in {".module", ".optsdcc"}:
  155. while not tok.pop().isA("NEWLINE"):
  156. pass
  157. elif start.value == ".globl":
  158. global_name = tok.pop().value
  159. global_names.add(global_name)
  160. assert tok.pop().isA("NEWLINE")
  161. elif start.value == ".area":
  162. area_name = tok.pop().value
  163. if area_name == "_DATA":
  164. print('SECTION "%s_%s", WRAM0' % (module, area_name))
  165. elif area_name == "_DABS":
  166. print('SECTION "%s_%s", SRAM' % (module, area_name))
  167. elif area_name == "_HOME":
  168. print('SECTION FRAGMENT "%s_%s", ROM0' % (module, area_name))
  169. elif area_name == "_CODE":
  170. print('SECTION FRAGMENT "%s_%s", ROM0' % (module, area_name))
  171. elif area_name.startswith("_CODE_"):
  172. print(
  173. 'SECTION FRAGMENT "%s_%s", ROMX, BANK[%d]'
  174. % (module, area_name, int(area_name[6:]))
  175. )
  176. elif area_name == "_CABS":
  177. print('SECTION FRAGMENT "%s_%s", ROM0' % (module, area_name))
  178. elif area_name == "_GSINIT":
  179. print('SECTION FRAGMENT "GSINIT", ROMX, BANK[1]')
  180. elif area_name == "_GSFINAL":
  181. print('SECTION FRAGMENT "GSFINAL", ROMX, BANK[1]')
  182. elif area_name == "_auto":
  183. print('SECTION FRAGMENT "code_%s", ROMX' % (module))
  184. else:
  185. raise Exception(area_name)
  186. while not tok.pop().isA("NEWLINE"):
  187. pass
  188. elif start.value == ".ds":
  189. sys.stdout.write("ds ")
  190. processExpression()
  191. sys.stdout.write("\n")
  192. elif start.value == ".ascii":
  193. sys.stdout.write("db ")
  194. sys.stdout.write(tok.pop().value)
  195. sys.stdout.write("\n")
  196. elif start.value == ".db":
  197. sys.stdout.write("db ")
  198. processParameter()
  199. while tok.peek().isA("OP", ","):
  200. sys.stdout.write(",")
  201. tok.pop()
  202. processParameter()
  203. sys.stdout.write("\n")
  204. elif start.value == ".byte":
  205. sys.stdout.write("db ")
  206. processByteAddr()
  207. sys.stdout.write("\n")
  208. elif start.value == ".dw":
  209. sys.stdout.write("dw ")
  210. processParameter()
  211. while tok.peek().isA("OP", ","):
  212. sys.stdout.write(",")
  213. tok.pop()
  214. processParameter()
  215. sys.stdout.write("\n")
  216. elif start.value == ".incbin":
  217. sys.stdout.write("incbin ")
  218. while not tok.peek().isA("NEWLINE"):
  219. sys.stdout.write(tok.pop().value)
  220. sys.stdout.write("\n")
  221. tok.pop()
  222. else:
  223. sys.stderr.write(f"{module}: error: could not parse\n")
  224. raise Exception(start, tok.peek())
  225. elif start.isA("ID"):
  226. if tok.peek().isA("ASSIGN"):
  227. tok.pop()
  228. sys.stdout.write("%s = " % (start.value))
  229. processExpression()
  230. sys.stdout.write("\n")
  231. elif tok.peek().isA("LABEL"):
  232. label_suffix = tok.pop().value
  233. if label_suffix == ":" and start.value in global_names:
  234. label_suffix = "::"
  235. print("%s%s" % (start.value, label_suffix))
  236. elif start.isA("ID", "ldhl"):
  237. tok.expect("ID", "sp")
  238. tok.expect("OP", ",")
  239. sys.stdout.write("ld hl, sp + ")
  240. processParameter()
  241. sys.stdout.write("\n")
  242. elif start.isA("ID", "lda"):
  243. tok.expect("ID", "hl")
  244. tok.expect("OP", ",")
  245. t = tok.pop()
  246. assert t.isA("NUMBER") or t.isA("HEX")
  247. tok.expect("OP", "(")
  248. tok.expect("ID", "sp")
  249. tok.expect("OP", ")")
  250. sys.stdout.write("ld hl, sp + %s\n" % (t.value))
  251. else:
  252. sys.stdout.write("%s " % (start.value))
  253. if not tok.peek().isA("NEWLINE"):
  254. processParameter()
  255. if tok.peek().isA("OP", ","):
  256. tok.pop()
  257. sys.stdout.write(", ")
  258. processParameter()
  259. sys.stdout.write("\n")
  260. tok.expect("NEWLINE")
  261. else:
  262. raise Exception(start)