An emulator, assembler, and disassembler for the Sega Game Gear
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

209 строки
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)
  177. return (*result = code), true;
  178. return false;
  179. }