Browse Source

Implement product code directive.

master
Ben Kurtovic 9 years ago
parent
commit
e65bb69a52
2 changed files with 87 additions and 13 deletions
  1. +4
    -2
      src/assembler/errors.h
  2. +83
    -11
      src/assembler/preprocessor.c

+ 4
- 2
src/assembler/errors.h View File

@@ -22,7 +22,8 @@ typedef enum {
ED_PP_UNKNOWN, ED_PP_UNKNOWN,
ED_PP_DUPLICATE, ED_PP_DUPLICATE,
ED_PP_NO_ARG, ED_PP_NO_ARG,
ED_PP_BAD_ARG
ED_PP_BAD_ARG,
ED_PP_ARG_RANGE
} ASMErrorDesc; } ASMErrorDesc;


/* Strings */ /* Strings */
@@ -40,7 +41,8 @@ static const char *asm_error_descs[] = {
"unknown directive", "unknown directive",
"multiple values for directive", "multiple values for directive",
"missing argument for directive", "missing argument for directive",
"invalid argument for directive"
"invalid argument for directive",
"directive argument out of range"
}; };


/* Structs */ /* Structs */


+ 83
- 11
src/assembler/preprocessor.c View File

@@ -3,6 +3,7 @@


#include <libgen.h> #include <libgen.h>
#include <limits.h> #include <limits.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -309,6 +310,68 @@ static inline bool read_bool_argument(
} }


/* /*
Read in an integer starting at str and ending the character before end.

Store the value in *result and return true on success; else return false.
*/
static inline bool read_integer(
uint32_t *result, const char *str, const char *end)
{
if (end - str <= 0)
return false;

uint64_t value = 0;
if (*str == '$') {
str++;
if (str == end)
return false;

while (str < end) {
if (*str >= '0' && *str <= '9')
value = value * 16 + (*str - '0');
else if (*str >= 'a' && *str <= 'f')
value = (value * 0x10) + 0xA + (*str - 'a');
else
return false;
if (value >= UINT32_MAX)
return false;
str++;
}
}
else {
while (str < end) {
if (*str < '0' || *str > '9')
return false;
value = (value * 10) + (*str - '0');
if (value >= UINT32_MAX)
return false;
str++;
}
}

*result = value;
return true;
}

/*
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.
*/
static inline bool read_uint32_argument(
uint32_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))
return (*result = value), true;
return false;
}

/*
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
@@ -320,15 +383,8 @@ static inline bool read_bool_argument(
*/ */
ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source) ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
{ {
// state->header.offset <-- check in list of acceptable values
// state->header.product_code <-- range check
// state->header.version <-- range check
// state->header.region <-- string conversion, check
// state->header.rom_size <-- value/range check
// state->rom_size <-- value check

// if giving rom size, check header offset is in rom size range
// if giving reported and actual rom size, check reported is <= actual
// TODO: if giving rom size, check header offset is in rom size range
// TODO: if giving reported and actual rom size, check reported is <= actual


#define CATCH_DUPES(line, first, oldval, newval) \ #define CATCH_DUPES(line, first, oldval, newval) \
if (first && oldval != newval) { \ if (first && oldval != newval) { \
@@ -352,6 +408,12 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); \ return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG); \
} }


#define RANGE_CHECK(arg, bound) \
if (arg > bound) { \
asm_lines_free(condemned); \
return error_info_create(line, ET_PREPROC, ED_PP_ARG_RANGE); \
}

DEBUG("Running preprocessor:") DEBUG("Running preprocessor:")


ErrorInfo* ei; ErrorInfo* ei;
@@ -361,7 +423,8 @@ 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;
const ASMLine *first_optimizer = NULL, *first_checksum = NULL,
*first_product = NULL;


while ((prev = line, line = next)) { while ((prev = line, line = next)) {
next = line->next; next = line->next;
@@ -379,9 +442,11 @@ 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
} }
else if (IS_DIRECTIVE(line, DIR_ROM_HEADER)) { else if (IS_DIRECTIVE(line, DIR_ROM_HEADER)) {
// TODO // TODO
// state->header.offset <-- check in list of acceptable values
} }
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)
@@ -390,16 +455,23 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
CATCH_DUPES(line, first_checksum, state->header.checksum, arg) CATCH_DUPES(line, first_checksum, state->header.checksum, arg)
} }
else if (IS_DIRECTIVE(line, DIR_ROM_PRODUCT)) { else if (IS_DIRECTIVE(line, DIR_ROM_PRODUCT)) {
// TODO
REQUIRE_ARG(line, DIR_ROM_PRODUCT)
uint32_t arg;
VALIDATE(read_uint32_argument(&arg, line, DIR_ROM_PRODUCT))
RANGE_CHECK(arg, 160000)
CATCH_DUPES(line, first_product, state->header.product_code, arg)
} }
else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) { else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) {
// TODO // TODO
// state->header.version <-- range check
} }
else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) { else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) {
// TODO // TODO
// state->header.region <-- string conversion, check
} }
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
} }
else { else {
asm_lines_free(condemned); asm_lines_free(condemned);


Loading…
Cancel
Save