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.
 
 
 
 
 

163 lines
5.0 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 <stdlib.h>
  4. #include "errors.h"
  5. #include "state.h"
  6. #include "../assembler.h"
  7. #include "../util.h"
  8. /* Error strings */
  9. static const char *error_types[] = {
  10. [ET_INCLUDE] = "include directive",
  11. [ET_PREPROC] = "preprocessor",
  12. [ET_LAYOUT] = "memory layout",
  13. [ET_SYMBOL] = "symbol table",
  14. [ET_PARSER] = "instruction parser"
  15. };
  16. static const char *error_descs[] = {
  17. [ED_NONE] = "undefined error",
  18. [ED_INC_BAD_ARG] = "missing or invalid argument",
  19. [ED_INC_DEPTH] = "maximum include depth exceeded",
  20. [ED_INC_FILE_READ] = "couldn't read included file",
  21. [ED_PP_UNKNOWN] = "unknown directive",
  22. [ED_PP_DUPLICATE] = "multiple values for directive",
  23. [ED_PP_NO_ARG] = "missing argument for directive",
  24. [ED_PP_BAD_ARG] = "invalid argument for directive",
  25. [ED_PP_ARG_RANGE] = "directive argument out of range",
  26. [ED_LYT_HEADER_RANGE] = "header offset exceeds given ROM size",
  27. [ED_LYT_DECL_RANGE] = "declared ROM size in header exceeds actual size",
  28. [ED_LYT_BOUNDS] = "location is out of bounds for the ROM size",
  29. [ED_LYT_BLOCK0] = "block zero cannot be mapped into a nonzero slot",
  30. [ED_LYT_SLOTS] = "multiple slot declarations for block directive",
  31. [ED_LYT_BLOCK_CROSS] = "instruction or data extends past block boundary",
  32. [ED_LYT_OVERLAP] = "multiple instructions/data occupy same location",
  33. [ED_LYT_OVERLAP_HEAD] = "location overlaps with ROM header",
  34. [ED_SYM_DUPE_LABELS] = "duplicate definitions for label",
  35. [ED_SYM_NO_LABEL] = "undefined reference to label",
  36. [ED_SYM_TOO_LONG] = "label name is too long",
  37. [ED_SYM_IS_REGISTER] = "labels cannot share names with registers",
  38. [ED_SYM_IS_CONDITION] = "labels cannot share names with condition codes",
  39. [ED_PS_OP_TOO_LONG] = "opcode mnemonic is too long (2-4 characters)",
  40. [ED_PS_OP_TOO_SHORT] = "opcode mnemonic is too short (2-4 characters)",
  41. [ED_PS_OP_INVALID] = "invalid characters in opcode mnemonic",
  42. [ED_PS_OP_UNKNOWN] = "unknown opcode mnemonic",
  43. [ED_PS_TOO_FEW_ARGS] = "too few arguments for opcode",
  44. [ED_PS_TOO_MANY_ARGS] = "too many arguments for opcode",
  45. [ED_PS_ARG_SYNTAX] = "invalid syntax in argument(s)",
  46. [ED_PS_ARG_TYPE] = "invalid argument type",
  47. [ED_PS_ARG_VALUE] = "invalid value for argument"
  48. };
  49. /* Internal structs */
  50. struct ASMErrorLine {
  51. char *data;
  52. size_t length;
  53. size_t lineno;
  54. char *filename;
  55. struct ASMErrorLine *next;
  56. };
  57. typedef struct ASMErrorLine ASMErrorLine;
  58. struct ErrorInfo {
  59. ASMErrorType type;
  60. ASMErrorDesc desc;
  61. ASMErrorLine *line;
  62. };
  63. /*
  64. Create an ASMErrorLine object from an ASMLine.
  65. */
  66. static ASMErrorLine* create_error_line(const ASMLine *line)
  67. {
  68. ASMErrorLine *el = cr_malloc(sizeof(ASMErrorLine));
  69. const char *source = line->original->data;
  70. size_t length = line->original->length;
  71. // Ignore spaces at beginning:
  72. while (length > 0 && (*source == ' ' || *source == '\t'))
  73. source++, length--;
  74. el->data = cr_malloc(sizeof(char) * length);
  75. memcpy(el->data, source, length);
  76. el->length = length;
  77. el->lineno = line->original->lineno;
  78. el->filename = cr_strdup(line->filename);
  79. el->next = NULL;
  80. return el;
  81. }
  82. /*
  83. Create an ErrorInfo object describing a particular error.
  84. The ErrorInfo object can be printed with error_info_print(), and must be
  85. freed when done with error_info_destroy().
  86. This function never fails (OOM triggers an exit()); the caller can be
  87. confident the returned object is valid.
  88. */
  89. ErrorInfo* error_info_create(
  90. const ASMLine *line, ASMErrorType err_type, ASMErrorDesc err_desc)
  91. {
  92. ErrorInfo *einfo = cr_malloc(sizeof(ErrorInfo));
  93. einfo->type = err_type;
  94. einfo->desc = err_desc;
  95. einfo->line = line ? create_error_line(line) : NULL;
  96. return einfo;
  97. }
  98. /*
  99. Add an ASMLine to an ErrorInfo object, as part of a file trace.
  100. */
  101. void error_info_append(ErrorInfo *einfo, const ASMLine *line)
  102. {
  103. ASMErrorLine* el = create_error_line(line);
  104. el->next = einfo->line;
  105. einfo->line = el;
  106. }
  107. /*
  108. Print an ErrorInfo object returned by assemble() to the given stream.
  109. */
  110. void error_info_print(const ErrorInfo *einfo, FILE *file)
  111. {
  112. ASMErrorLine *line = einfo->line;
  113. fprintf(file, "error: %s: %s\n", error_types[einfo->type],
  114. error_descs[einfo->desc]);
  115. while (line) {
  116. fprintf(file, "%s:%zu:\n", line->filename, line->lineno);
  117. fprintf(file, " %.*s\n", (int) line->length, line->data);
  118. line = line->next;
  119. }
  120. }
  121. /*
  122. Destroy an ErrorInfo object created by assemble().
  123. */
  124. void error_info_destroy(ErrorInfo *error_info)
  125. {
  126. if (!error_info)
  127. return;
  128. ASMErrorLine *line = error_info->line, *temp;
  129. while (line) {
  130. temp = line->next;
  131. free(line->data);
  132. free(line->filename);
  133. free(line);
  134. line = temp;
  135. }
  136. free(error_info);
  137. }