| @@ -3,6 +3,7 @@ | |||||
| #include <libgen.h> | #include <libgen.h> | ||||
| #include <limits.h> | #include <limits.h> | ||||
| #include <stdbool.h> | |||||
| #include <stdint.h> | #include <stdint.h> | ||||
| #include <stdio.h> | #include <stdio.h> | ||||
| #include <stdlib.h> | #include <stdlib.h> | ||||
| @@ -24,16 +25,15 @@ | |||||
| if (first && oldval != newval) { \ | if (first && oldval != newval) { \ | ||||
| ei = error_info_create(line, ET_PREPROC, ED_PP_DUPLICATE); \ | ei = error_info_create(line, ET_PREPROC, ED_PP_DUPLICATE); \ | ||||
| error_info_append(ei, first); \ | error_info_append(ei, first); \ | ||||
| asm_lines_free(condemned); \ | |||||
| return ei; \ | |||||
| goto cleanup; \ | |||||
| } \ | } \ | ||||
| oldval = newval; \ | oldval = newval; \ | ||||
| first = line; | first = line; | ||||
| #define FAIL_ON_COND(cond, err_desc) \ | #define FAIL_ON_COND(cond, err_desc) \ | ||||
| if ((cond)) { \ | if ((cond)) { \ | ||||
| asm_lines_free(condemned); \ | |||||
| return error_info_create(line, ET_PREPROC, err_desc); \ | |||||
| ei = error_info_create(line, ET_PREPROC, err_desc); \ | |||||
| goto cleanup; \ | |||||
| } | } | ||||
| #define REQUIRE_ARG(line, d) \ | #define REQUIRE_ARG(line, d) \ | ||||
| @@ -306,6 +306,14 @@ static bool parse_region_string(uint8_t *result, const ASMLine *line) | |||||
| } | } | ||||
| /* | /* | ||||
| Return whether the given header offset is a valid location. | |||||
| */ | |||||
| static inline bool is_header_offset_valid(uint16_t offset) | |||||
| { | |||||
| return offset == 0x7FF0 || offset == 0x3FF0 || offset == 0x1FF0; | |||||
| } | |||||
| /* | |||||
| Preprocess the LineBuffer into ASMLines. Change some state along the way. | Preprocess the LineBuffer into ASMLines. Change some state along the way. | ||||
| This function processes include directives, so read_source_file() may be | This function processes include directives, so read_source_file() may be | ||||
| @@ -317,9 +325,9 @@ static bool parse_region_string(uint8_t *result, const ASMLine *line) | |||||
| */ | */ | ||||
| ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | ||||
| { | { | ||||
| ErrorInfo* ei = NULL; | |||||
| DEBUG("Running preprocessor:") | DEBUG("Running preprocessor:") | ||||
| ErrorInfo* ei; | |||||
| if ((ei = build_asm_lines(source, source, &state->lines, NULL, | if ((ei = build_asm_lines(source, source, &state->lines, NULL, | ||||
| &state->includes))) | &state->includes))) | ||||
| return ei; | return ei; | ||||
| @@ -327,9 +335,9 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| ASMLine dummy = {.next = state->lines}; | ASMLine dummy = {.next = state->lines}; | ||||
| ASMLine *prev, *line = &dummy, *next = state->lines, *condemned = NULL; | ASMLine *prev, *line = &dummy, *next = state->lines, *condemned = NULL; | ||||
| const ASMLine *first_optimizer = NULL, *first_checksum = NULL, | |||||
| *first_product = NULL, *first_version = NULL, | |||||
| *first_region = NULL; | |||||
| const ASMLine *first_optimizer = NULL, *first_offset = NULL, | |||||
| *first_checksum = NULL, *first_product = NULL, | |||||
| *first_version = NULL, *first_region = NULL; | |||||
| while ((prev = line, line = next)) { | while ((prev = line, line = next)) { | ||||
| next = line->next; | next = line->next; | ||||
| @@ -348,10 +356,14 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| else if (IS_DIRECTIVE(line, DIR_ROM_SIZE)) { | else if (IS_DIRECTIVE(line, DIR_ROM_SIZE)) { | ||||
| // TODO | // TODO | ||||
| // state->rom_size <-- value check | // state->rom_size <-- value check | ||||
| // auto | |||||
| } | } | ||||
| else if (IS_DIRECTIVE(line, DIR_ROM_HEADER)) { | else if (IS_DIRECTIVE(line, DIR_ROM_HEADER)) { | ||||
| // TODO | |||||
| // state->header.offset <-- check in list of acceptable values | |||||
| REQUIRE_ARG(line, DIR_ROM_HEADER) | |||||
| uint16_t arg; | |||||
| VALIDATE(parse_uint16(&arg, line, DIR_ROM_HEADER)) // auto | |||||
| VALIDATE(is_header_offset_valid(arg)) | |||||
| SAVE_ARG(line, first_offset, state->header.offset, arg) | |||||
| } | } | ||||
| else if (IS_DIRECTIVE(line, DIR_ROM_CHECKSUM)) { | else if (IS_DIRECTIVE(line, DIR_ROM_CHECKSUM)) { | ||||
| REQUIRE_ARG(line, DIR_ROM_CHECKSUM) | REQUIRE_ARG(line, DIR_ROM_CHECKSUM) | ||||
| @@ -362,21 +374,21 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| else if (IS_DIRECTIVE(line, DIR_ROM_PRODUCT)) { | else if (IS_DIRECTIVE(line, DIR_ROM_PRODUCT)) { | ||||
| REQUIRE_ARG(line, DIR_ROM_PRODUCT) | REQUIRE_ARG(line, DIR_ROM_PRODUCT) | ||||
| uint32_t arg; | uint32_t arg; | ||||
| VALIDATE(parse_uint32(&arg, line, DIR_ROM_PRODUCT)) | |||||
| VALIDATE(parse_uint32(&arg, line, DIR_ROM_PRODUCT)) // auto | |||||
| RANGE_CHECK(arg, 160000) | RANGE_CHECK(arg, 160000) | ||||
| SAVE_ARG(line, first_product, state->header.product_code, arg) | SAVE_ARG(line, first_product, state->header.product_code, arg) | ||||
| } | } | ||||
| else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) { | else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) { | ||||
| REQUIRE_ARG(line, DIR_ROM_VERSION) | REQUIRE_ARG(line, DIR_ROM_VERSION) | ||||
| uint8_t arg; | uint8_t arg; | ||||
| VALIDATE(parse_uint8(&arg, line, DIR_ROM_VERSION)) | |||||
| VALIDATE(parse_uint8(&arg, line, DIR_ROM_VERSION)) // auto | |||||
| RANGE_CHECK(arg, 0x10) | RANGE_CHECK(arg, 0x10) | ||||
| SAVE_ARG(line, first_version, state->header.version, arg) | SAVE_ARG(line, first_version, state->header.version, arg) | ||||
| } | } | ||||
| else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) { | else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) { | ||||
| REQUIRE_ARG(line, DIR_ROM_REGION) | REQUIRE_ARG(line, DIR_ROM_REGION) | ||||
| uint8_t arg; | uint8_t arg; | ||||
| if (parse_uint8(&arg, line, DIR_ROM_REGION)) { | |||||
| if (parse_uint8(&arg, line, DIR_ROM_REGION)) { // auto | |||||
| RANGE_CHECK(arg, 0x10) | RANGE_CHECK(arg, 0x10) | ||||
| VALIDATE(region_code_to_string(arg)) | VALIDATE(region_code_to_string(arg)) | ||||
| } else { | } else { | ||||
| @@ -387,10 +399,11 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| else if (IS_DIRECTIVE(line, DIR_ROM_DECLSIZE)) { | else if (IS_DIRECTIVE(line, DIR_ROM_DECLSIZE)) { | ||||
| // TODO | // TODO | ||||
| // state->header.rom_size <-- value/range check | // state->header.rom_size <-- value/range check | ||||
| // auto | |||||
| } | } | ||||
| else { | else { | ||||
| asm_lines_free(condemned); | |||||
| return error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN); | |||||
| ei = error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN); | |||||
| goto cleanup; | |||||
| } | } | ||||
| // Remove directive from lines, and schedule it for deletion: | // Remove directive from lines, and schedule it for deletion: | ||||
| @@ -406,9 +419,6 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| state->rom_size = 8; // TODO | state->rom_size = 8; // TODO | ||||
| asm_lines_free(condemned); | |||||
| state->lines = dummy.next; // Fix list head if first line was a directive | |||||
| #ifdef DEBUG_MODE | #ifdef DEBUG_MODE | ||||
| DEBUG("Dumping ASMLines:") | DEBUG("Dumping ASMLines:") | ||||
| const ASMLine *temp = state->lines; | const ASMLine *temp = state->lines; | ||||
| @@ -419,5 +429,8 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) | |||||
| } | } | ||||
| #endif | #endif | ||||
| return NULL; | |||||
| cleanup: | |||||
| asm_lines_free(condemned); | |||||
| state->lines = dummy.next; // Fix list head if first line was a directive | |||||
| return ei; | |||||
| } | } | ||||