diff --git a/src/assembler/parse_util.c b/src/assembler/parse_util.c index cf256cd..855e9ac 100644 --- a/src/assembler/parse_util.c +++ b/src/assembler/parse_util.c @@ -8,12 +8,57 @@ #include "directives.h" /* - Read in an integer starting at str and ending the character before end. + Read in a boolean argument from the given line and store it in *result. - Store the value in *result and return true on success; else return false. + auto_val is used if the argument's value is "auto". Return true on success + and false on failure; in the latter case, *result is not modified. */ -static inline bool read_integer(uint32_t *result, const char *str, const char *end) +bool parse_bool(bool *result, const ASMLine *line, const char *directive, bool auto_val) +{ + const char *arg = line->data + (DIRECTIVE_OFFSET(line, directive) + 1); + ssize_t len = line->length - (DIRECTIVE_OFFSET(line, directive) + 1); + + if (len <= 0 || len > 5) + return false; + + switch (len) { + case 1: // 0, 1 + if (*arg == '0' || *arg == '1') + return (*result = *arg - '0'), true; + return false; + case 2: // on + if (!strncmp(arg, "on", 2)) + return (*result = true), true; + return false; + case 3: // off + if (!strncmp(arg, "off", 3)) + return (*result = false), true; + return false; + case 4: // true, auto + if (!strncmp(arg, "true", 4)) + return (*result = true), true; + if (!strncmp(arg, "auto", 4)) + return (*result = auto_val), true; + return false; + case 5: // false + if (!strncmp(arg, "false", 5)) + return (*result = false), true; + return false; + } + return false; +} + +/* + Read in a 32-bit int argument from the given line and store it in *result. + + Return true on success and false on failure; in the latter case, *result is + not modified. +*/ +bool parse_uint32(uint32_t *result, const ASMLine *line, const char *directive) { + const char *str = line->data + (DIRECTIVE_OFFSET(line, directive) + 1); + const char *end = str + (line->length - (DIRECTIVE_OFFSET(line, directive) + 1)); + if (end - str <= 0) return false; @@ -30,7 +75,7 @@ static inline bool read_integer(uint32_t *result, const char *str, const char *e value = (value * 0x10) + 0xA + (*str - 'a'); else return false; - if (value >= UINT32_MAX) + if (value > UINT32_MAX) return false; str++; } @@ -40,7 +85,7 @@ static inline bool read_integer(uint32_t *result, const char *str, const char *e if (*str < '0' || *str > '9') return false; value = (value * 10) + (*str - '0'); - if (value >= UINT32_MAX) + if (value > UINT32_MAX) return false; str++; } @@ -51,59 +96,29 @@ static inline bool read_integer(uint32_t *result, const char *str, const char *e } /* - Read in a boolean argument from the given line and store it in *result. + Read in a 16-bit int argument from the given line and store it in *result. - auto_val is used if the argument's value is "auto". Return true on success - and false on failure; in the latter case, *result is not modified. + Return true on success and false on failure; in the latter case, *result is + not modified. */ -bool parse_bool(bool *result, const ASMLine *line, const char *directive, bool auto_val) +bool parse_uint16(uint16_t *result, const ASMLine *line, const char *directive) { - const char *arg = line->data + (DIRECTIVE_OFFSET(line, directive) + 1); - ssize_t len = line->length - (DIRECTIVE_OFFSET(line, directive) + 1); - - if (len <= 0 || len > 5) - return false; - - switch (len) { - case 1: // 0, 1 - if (*arg == '0' || *arg == '1') - return (*result = *arg - '0'), true; - return false; - case 2: // on - if (!strncmp(arg, "on", 2)) - return (*result = true), true; - return false; - case 3: // off - if (!strncmp(arg, "off", 3)) - return (*result = false), true; - return false; - case 4: // true, auto - if (!strncmp(arg, "true", 4)) - return (*result = true), true; - if (!strncmp(arg, "auto", 4)) - return (*result = auto_val), true; - return false; - case 5: // false - if (!strncmp(arg, "false", 5)) - return (*result = false), true; - return false; - } + uint32_t value; + if (parse_uint32(&value, line, directive) && value <= UINT16_MAX) + return (*result = value), true; return false; } /* - Read in a 32-bit int argument from the given line and store it in *result. + Read in an 8-bit int argument from the given line and store it in *result. Return true on success and false on failure; in the latter case, *result is not modified. */ -bool parse_uint32(uint32_t *result, const ASMLine *line, const char *directive) +bool parse_uint8(uint8_t *result, const ASMLine *line, const char *directive) { - const char *arg = line->data + (DIRECTIVE_OFFSET(line, directive) + 1); - ssize_t len = line->length - (DIRECTIVE_OFFSET(line, directive) + 1); - uint32_t value; - if (read_integer(&value, arg, arg + len)) + if (parse_uint32(&value, line, directive) && value <= UINT8_MAX) return (*result = value), true; return false; } diff --git a/src/assembler/parse_util.h b/src/assembler/parse_util.h index 85247bc..db1212b 100644 --- a/src/assembler/parse_util.h +++ b/src/assembler/parse_util.h @@ -10,3 +10,5 @@ bool parse_bool(bool*, const ASMLine*, const char*, bool); bool parse_uint32(uint32_t*, const ASMLine*, const char*); +bool parse_uint16(uint16_t*, const ASMLine*, const char*); +bool parse_uint8(uint8_t*, const ASMLine*, const char*); diff --git a/src/assembler/preprocessor.c b/src/assembler/preprocessor.c index 04aa43c..68175fd 100644 --- a/src/assembler/preprocessor.c +++ b/src/assembler/preprocessor.c @@ -299,8 +299,9 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) ASMLine dummy = {.next = state->lines}; ASMLine *prev, *line = &dummy, *next = state->lines, *condemned = NULL; + const ASMLine *first_optimizer = NULL, *first_checksum = NULL, - *first_product = NULL; + *first_product = NULL, *first_version = NULL; while ((prev = line, line = next)) { next = line->next; @@ -338,8 +339,11 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) CATCH_DUPES(line, first_product, state->header.product_code, arg) } else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) { - // TODO - // state->header.version <-- range check + REQUIRE_ARG(line, DIR_ROM_VERSION) + uint8_t arg; + VALIDATE(parse_uint8(&arg, line, DIR_ROM_VERSION)) + RANGE_CHECK(arg, 0x10) + CATCH_DUPES(line, first_version, state->header.version, arg) } else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) { // TODO