An emulator, assembler, and disassembler for the Sega Game Gear
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.
 
 
 
 
 

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