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.
 
 
 
 
 

161 rivejä
4.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 <stdlib.h>
  4. #include "errors.h"
  5. #include "state.h"
  6. #include "../assembler.h"
  7. #include "../logging.h"
  8. #define ERROR_TYPE(err_info) (asm_error_types[err_info->type])
  9. #define ERROR_DESC(err_info) (asm_error_descs[err_info->desc])
  10. /* Error strings */
  11. static const char *asm_error_types[] = {
  12. [ET_INCLUDE] = "include directive",
  13. [ET_PREPROC] = "preprocessor",
  14. [ET_LAYOUT] = "memory layout",
  15. [ET_SYMBOL] = "symbol table",
  16. [ET_PARSER] = "instruction parser"
  17. };
  18. static const char *asm_error_descs[] = {
  19. [ED_INC_BAD_ARG] = "missing or invalid argument",
  20. [ED_INC_RECURSION] = "infinite recursion detected",
  21. [ED_INC_FILE_READ] = "couldn't read included file",
  22. [ED_PP_UNKNOWN] = "unknown directive",
  23. [ED_PP_DUPLICATE] = "multiple values for directive",
  24. [ED_PP_NO_ARG] = "missing argument for directive",
  25. [ED_PP_BAD_ARG] = "invalid argument for directive",
  26. [ED_PP_ARG_RANGE] = "directive argument out of range",
  27. [ED_LYT_HEADER_RANGE] = "header offset exceeds given ROM size",
  28. [ED_LYT_DECL_RANGE] = "declared ROM size in header exceeds actual size",
  29. [ED_LYT_BOUNDS] = "location is out of bounds for the ROM size",
  30. [ED_LYT_BLOCK0] = "block zero cannot be mapped into a nonzero slot",
  31. [ED_LYT_SLOTS] = "multiple slot declarations for block directive",
  32. [ED_LYT_OVERLAP] = "location overlaps with instruction or data",
  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_PARSE_SYNTAX] = "syntax error"
  37. };
  38. /* Internal structs */
  39. struct ASMErrorLine {
  40. char *data;
  41. size_t length;
  42. size_t lineno;
  43. char *filename;
  44. struct ASMErrorLine *next;
  45. };
  46. typedef struct ASMErrorLine ASMErrorLine;
  47. struct ErrorInfo {
  48. ASMErrorType type;
  49. ASMErrorDesc desc;
  50. ASMErrorLine *line;
  51. };
  52. /*
  53. Create an ASMErrorLine object from an ASMLine.
  54. */
  55. static ASMErrorLine* create_error_line(const ASMLine *line)
  56. {
  57. ASMErrorLine *el = malloc(sizeof(ASMErrorLine));
  58. if (!el)
  59. OUT_OF_MEMORY()
  60. const char *source = line->original->data;
  61. size_t length = line->original->length;
  62. if (!(el->data = malloc(sizeof(char) * length)))
  63. OUT_OF_MEMORY()
  64. // Ignore spaces at beginning:
  65. while (length > 0 && (*source == ' ' || *source == '\t'))
  66. source++, length--;
  67. memcpy(el->data, source, length);
  68. el->length = length;
  69. el->lineno = line->original->lineno;
  70. el->filename = strdup(line->filename);
  71. if (!el->filename)
  72. OUT_OF_MEMORY()
  73. el->next = NULL;
  74. return el;
  75. }
  76. /*
  77. Create an ErrorInfo object describing a particular error.
  78. The ErrorInfo object can be printed with error_info_print(), and must be
  79. freed when done with error_info_destroy().
  80. This function never fails (OOM triggers an exit()); the caller can be
  81. confident the returned object is valid.
  82. */
  83. ErrorInfo* error_info_create(
  84. const ASMLine *line, ASMErrorType err_type, ASMErrorDesc err_desc)
  85. {
  86. ErrorInfo *einfo = malloc(sizeof(ErrorInfo));
  87. if (!einfo)
  88. OUT_OF_MEMORY()
  89. einfo->type = err_type;
  90. einfo->desc = err_desc;
  91. einfo->line = line ? create_error_line(line) : NULL;
  92. return einfo;
  93. }
  94. /*
  95. Add an ASMLine to an ErrorInfo object, as part of a file trace.
  96. */
  97. void error_info_append(ErrorInfo *einfo, const ASMLine *line)
  98. {
  99. ASMErrorLine* el = create_error_line(line);
  100. el->next = einfo->line;
  101. einfo->line = el;
  102. }
  103. /*
  104. Print an ErrorInfo object returned by assemble() to the given stream.
  105. */
  106. void error_info_print(const ErrorInfo *einfo, FILE *file)
  107. {
  108. ASMErrorLine *line = einfo->line;
  109. fprintf(file, "error: %s: %s\n", ERROR_TYPE(einfo), ERROR_DESC(einfo));
  110. while (line) {
  111. fprintf(file, "%s:%zu:\n", line->filename, line->lineno);
  112. fprintf(file, " %.*s\n", (int) line->length, line->data);
  113. line = line->next;
  114. }
  115. }
  116. /*
  117. Destroy an ErrorInfo object created by assemble().
  118. */
  119. void error_info_destroy(ErrorInfo *error_info)
  120. {
  121. if (!error_info)
  122. return;
  123. ASMErrorLine *line = error_info->line, *temp;
  124. while (line) {
  125. temp = line->next;
  126. free(line->data);
  127. free(line->filename);
  128. free(line);
  129. line = temp;
  130. }
  131. free(error_info);
  132. }