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.
 
 
 
 
 

209 lignes
5.2 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 <string.h>
  5. #include "parse_util.h"
  6. #include "directives.h"
  7. #include "../util.h"
  8. #define MAX_REGION_SIZE 32
  9. #define PARSE_FUNC_HEADER(name, type) \
  10. bool parse_##name(type *result, const ASMLine *line, const char *directive)
  11. /*
  12. All public functions in this file follow the same return conventions:
  13. - Return true on success and false on failure.
  14. - *result is only modified on success.
  15. */
  16. /*
  17. Read in a boolean argument from the given line and store it in *result.
  18. */
  19. PARSE_FUNC_HEADER(bool, bool)
  20. {
  21. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  22. const char *arg = line->data + offset;
  23. ssize_t len = line->length - offset;
  24. if (len <= 0 || len > 5)
  25. return false;
  26. switch (len) {
  27. case 1: // 0, 1
  28. if (*arg == '0' || *arg == '1')
  29. return (*result = *arg - '0'), true;
  30. return false;
  31. case 2: // on
  32. if (!strncmp(arg, "on", 2))
  33. return (*result = true), true;
  34. return false;
  35. case 3: // off
  36. if (!strncmp(arg, "off", 3))
  37. return (*result = false), true;
  38. return false;
  39. case 4: // true
  40. if (!strncmp(arg, "true", 4))
  41. return (*result = true), true;
  42. return false;
  43. case 5: // false
  44. if (!strncmp(arg, "false", 5))
  45. return (*result = false), true;
  46. return false;
  47. }
  48. return false;
  49. }
  50. /*
  51. Read in a 32-bit int argument from the given line and store it in *result.
  52. */
  53. PARSE_FUNC_HEADER(uint32_t, uint32_t)
  54. {
  55. const char *str = line->data + DIRECTIVE_OFFSET(line, directive) + 1;
  56. const char *end = line->data + line->length;
  57. if (end - str <= 0)
  58. return false;
  59. uint64_t value = 0;
  60. if (*str == '$') {
  61. str++;
  62. if (str == end)
  63. return false;
  64. while (str < end) {
  65. if (*str >= '0' && *str <= '9')
  66. value = value * 16 + (*str - '0');
  67. else if (*str >= 'a' && *str <= 'f')
  68. value = (value * 0x10) + 0xA + (*str - 'a');
  69. else
  70. return false;
  71. if (value > UINT32_MAX)
  72. return false;
  73. str++;
  74. }
  75. }
  76. else {
  77. while (str < end) {
  78. if (*str < '0' || *str > '9')
  79. return false;
  80. value = (value * 10) + (*str - '0');
  81. if (value > UINT32_MAX)
  82. return false;
  83. str++;
  84. }
  85. }
  86. *result = value;
  87. return true;
  88. }
  89. /*
  90. Read in a 16-bit int argument from the given line and store it in *result.
  91. */
  92. PARSE_FUNC_HEADER(uint16_t, uint16_t)
  93. {
  94. uint32_t value;
  95. if (parse_uint32_t(&value, line, directive) && value <= UINT16_MAX)
  96. return (*result = value), true;
  97. return false;
  98. }
  99. /*
  100. Read in an 8-bit int argument from the given line and store it in *result.
  101. */
  102. PARSE_FUNC_HEADER(uint8_t, uint8_t)
  103. {
  104. uint32_t value;
  105. if (parse_uint32_t(&value, line, directive) && value <= UINT8_MAX)
  106. return (*result = value), true;
  107. return false;
  108. }
  109. /*
  110. Parse a ROM size string in an ASMLine and store it in *result.
  111. */
  112. PARSE_FUNC_HEADER(rom_size, uint32_t)
  113. {
  114. const char *arg = line->data + DIRECTIVE_OFFSET(line, directive) + 1;
  115. const char *end = line->data + line->length - 1;
  116. if (end - arg < 5)
  117. return false;
  118. if (*(arg++) != '"' || *(end--) != '"')
  119. return false;
  120. if (*end != 'B' && *end != 'b')
  121. return false;
  122. end--;
  123. uint32_t factor;
  124. if (*end == 'K' || *end == 'k')
  125. factor = 1 << 10;
  126. else if (*end == 'M' || *end == 'm')
  127. factor = 1 << 20;
  128. else
  129. return false;
  130. end--;
  131. if (*end != ' ')
  132. return false;
  133. uint32_t value = 0;
  134. while (arg < end) {
  135. if (*arg < '0' || *arg > '9')
  136. return false;
  137. value = (value * 10) + (*arg - '0');
  138. if (value > UINT16_MAX)
  139. return false;
  140. arg++;
  141. }
  142. *result = value * factor;
  143. return true;
  144. }
  145. /*
  146. Parse a region code string in an ASMLine and store it in *result.
  147. */
  148. PARSE_FUNC_HEADER(region_string, uint8_t)
  149. {
  150. char buffer[MAX_REGION_SIZE];
  151. size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
  152. const char *arg = line->data + offset;
  153. ssize_t len = line->length - offset;
  154. if (len <= 2 || len >= MAX_REGION_SIZE + 2) // Account for double quotes
  155. return false;
  156. if (arg[0] != '"' || arg[len - 1] != '"')
  157. return false;
  158. strncpy(buffer, arg + 1, len - 2);
  159. buffer[len - 2] = '\0';
  160. uint8_t code = region_string_to_code(buffer);
  161. if (code)
  162. return (*result = code), true;
  163. return false;
  164. }
  165. /*
  166. Parse a size code in an ASMLine and store it in *result.
  167. */
  168. PARSE_FUNC_HEADER(size_code, uint8_t)
  169. {
  170. uint32_t bytes;
  171. if (!parse_uint32_t(&bytes, line, directive)) {
  172. if (!parse_rom_size(&bytes, line, directive))
  173. return false;
  174. }
  175. uint8_t code = size_bytes_to_code(bytes);
  176. if (code != INVALID_SIZE_CODE)
  177. return (*result = code), true;
  178. return false;
  179. }