An emulator, assembler, and disassembler for the Sega Game Gear
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

301 lignes
7.5 KiB

  1. /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <limits.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "parse_util.h"
  7. #include "directives.h"
  8. #include "../logging.h"
  9. #include "../util.h"
  10. #define MAX_REGION_SIZE 32
  11. #define DIRECTIVE_PARSE_FUNC(name, type) \
  12. bool dparse_##name(type *result, const ASMLine *line, const char *directive)
  13. /*
  14. All public functions in this file follow the same return conventions:
  15. - Return true on success and false on failure.
  16. - *result is only modified on success.
  17. */
  18. /*
  19. Read in a boolean value and store it in *result.
  20. */
  21. bool parse_bool(bool *result, const char *arg, ssize_t size)
  22. {
  23. if (size <= 0 || size > 5)
  24. return false;
  25. switch (size) {
  26. case 1: // 0, 1
  27. if (*arg == '0' || *arg == '1')
  28. return (*result = *arg - '0'), true;
  29. return false;
  30. case 2: // on
  31. if (!strncmp(arg, "on", 2))
  32. return (*result = true), true;
  33. return false;
  34. case 3: // off
  35. if (!strncmp(arg, "off", 3))
  36. return (*result = false), true;
  37. return false;
  38. case 4: // true
  39. if (!strncmp(arg, "true", 4))
  40. return (*result = true), true;
  41. return false;
  42. case 5: // false
  43. if (!strncmp(arg, "false", 5))
  44. return (*result = false), true;
  45. return false;
  46. }
  47. return false;
  48. }
  49. /*
  50. Read in a 32-bit integer and store it in *result.
  51. */
  52. bool parse_uint32_t(uint32_t *result, const char *arg, ssize_t size)
  53. {
  54. if (size <= 0)
  55. return false;
  56. const char *end = arg + size;
  57. uint64_t value = 0;
  58. if (*arg == '$') {
  59. arg++;
  60. if (arg == end)
  61. return false;
  62. while (arg < end) {
  63. if (*arg >= '0' && *arg <= '9')
  64. value = (value * 0x10) + (*arg - '0');
  65. else if (*arg >= 'a' && *arg <= 'f')
  66. value = (value * 0x10) + 0xA + (*arg - 'a');
  67. else
  68. return false;
  69. if (value > UINT32_MAX)
  70. return false;
  71. arg++;
  72. }
  73. }
  74. else {
  75. while (arg < end) {
  76. if (*arg < '0' || *arg > '9')
  77. return false;
  78. value = (value * 10) + (*arg - '0');
  79. if (value > UINT32_MAX)
  80. return false;
  81. arg++;
  82. }
  83. }
  84. *result = value;
  85. return true;
  86. }
  87. /*
  88. Read in a string, possibly with escape sequences, and store it in *result.
  89. *length is also updated to the size of the string, which is *not*
  90. null-terminated. *result must be free()'d when finished.
  91. */
  92. bool parse_string(char **result, size_t *length, const char *arg, ssize_t size)
  93. {
  94. if (size < 2 || arg[0] != '"' || arg[size - 1] != '"')
  95. return false;
  96. ssize_t i, slashes = 0;
  97. for (i = 1; i < size; i++) {
  98. if (arg[i] == '"' && (slashes % 2) == 0)
  99. break;
  100. // TODO: parse escape codes here
  101. if (arg[i] == '\\')
  102. slashes++;
  103. else
  104. slashes = 0;
  105. }
  106. if (i != size - 1) // Junk present after closing quote
  107. return false;
  108. *length = size - 2;
  109. *result = malloc(sizeof(char) * (*length));
  110. if (!*result)
  111. OUT_OF_MEMORY()
  112. memcpy(*result, arg + 1, *length);
  113. return true;
  114. }
  115. /*
  116. Read in a space-separated sequence of bytes and store it in *result.
  117. *length is also updated to the number of bytes in the array. *result must
  118. be free()'d when finished.
  119. */
  120. bool parse_bytes(uint8_t **result, size_t *length, const char *arg, ssize_t size)
  121. {
  122. if (size <= 0)
  123. return false;
  124. const char *end = arg + size;
  125. uint8_t *bytes = NULL;
  126. size_t nbytes = 0;
  127. while (arg < end) {
  128. const char *start = arg;
  129. while (arg != end && *arg != ' ' && *arg != ',')
  130. arg++;
  131. uint32_t temp;
  132. if (!parse_uint32_t(&temp, start, arg - start) || temp > UINT8_MAX) {
  133. free(bytes);
  134. return false;
  135. }
  136. nbytes++;
  137. bytes = realloc(bytes, sizeof(uint8_t) * nbytes);
  138. if (!bytes)
  139. OUT_OF_MEMORY()
  140. bytes[nbytes - 1] = temp;
  141. if (arg < end - 1 && *arg == ',' && *(arg + 1) == ' ')
  142. arg += 2;
  143. else if (arg++ >= end)
  144. break;
  145. }
  146. *result = bytes;
  147. *length = nbytes;
  148. return true;
  149. }
  150. /*
  151. Read in a boolean argument from the given line and store it in *result.
  152. */
  153. DIRECTIVE_PARSE_FUNC(bool, bool)
  154. {
  155. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  156. return parse_bool(result, line->data + offset, line->length - offset);
  157. }
  158. /*
  159. Read in a 32-bit int argument from the given line and store it in *result.
  160. */
  161. DIRECTIVE_PARSE_FUNC(uint32_t, uint32_t)
  162. {
  163. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  164. return parse_uint32_t(result, line->data + offset, line->length - offset);
  165. }
  166. /*
  167. Read in a 16-bit int argument from the given line and store it in *result.
  168. */
  169. DIRECTIVE_PARSE_FUNC(uint16_t, uint16_t)
  170. {
  171. uint32_t value;
  172. if (dparse_uint32_t(&value, line, directive) && value <= UINT16_MAX)
  173. return (*result = value), true;
  174. return false;
  175. }
  176. /*
  177. Read in an 8-bit int argument from the given line and store it in *result.
  178. */
  179. DIRECTIVE_PARSE_FUNC(uint8_t, uint8_t)
  180. {
  181. uint32_t value;
  182. if (dparse_uint32_t(&value, line, directive) && value <= UINT8_MAX)
  183. return (*result = value), true;
  184. return false;
  185. }
  186. /*
  187. Parse a ROM size string in an ASMLine and store it in *result.
  188. */
  189. DIRECTIVE_PARSE_FUNC(rom_size, uint32_t)
  190. {
  191. const char *arg = line->data + DIRECTIVE_OFFSET(line, directive) + 1;
  192. const char *end = line->data + line->length - 1;
  193. if (end - arg < 5)
  194. return false;
  195. if (*(arg++) != '"' || *(end--) != '"')
  196. return false;
  197. if (*end != 'B' && *end != 'b')
  198. return false;
  199. end--;
  200. uint32_t factor;
  201. if (*end == 'K' || *end == 'k')
  202. factor = 1 << 10;
  203. else if (*end == 'M' || *end == 'm')
  204. factor = 1 << 20;
  205. else
  206. return false;
  207. end--;
  208. if (*end != ' ')
  209. return false;
  210. uint32_t value = 0;
  211. while (arg < end) {
  212. if (*arg < '0' || *arg > '9')
  213. return false;
  214. value = (value * 10) + (*arg - '0');
  215. if (value > UINT16_MAX)
  216. return false;
  217. arg++;
  218. }
  219. *result = value * factor;
  220. return true;
  221. }
  222. /*
  223. Parse a region code string in an ASMLine and store it in *result.
  224. */
  225. DIRECTIVE_PARSE_FUNC(region_string, uint8_t)
  226. {
  227. char buffer[MAX_REGION_SIZE];
  228. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  229. const char *arg = line->data + offset;
  230. ssize_t len = line->length - offset;
  231. if (len <= 2 || len >= MAX_REGION_SIZE + 2) // Account for double quotes
  232. return false;
  233. if (arg[0] != '"' || arg[len - 1] != '"')
  234. return false;
  235. strncpy(buffer, arg + 1, len - 2);
  236. buffer[len - 2] = '\0';
  237. uint8_t code = region_string_to_code(buffer);
  238. if (code)
  239. return (*result = code), true;
  240. return false;
  241. }
  242. /*
  243. Parse a size code in an ASMLine and store it in *result.
  244. */
  245. DIRECTIVE_PARSE_FUNC(size_code, uint8_t)
  246. {
  247. uint32_t bytes;
  248. if (!dparse_uint32_t(&bytes, line, directive)) {
  249. if (!dparse_rom_size(&bytes, line, directive))
  250. return false;
  251. }
  252. uint8_t code = size_bytes_to_code(bytes);
  253. if (code != INVALID_SIZE_CODE)
  254. return (*result = code), true;
  255. return false;
  256. }