Browse Source

Implement preprocessor for .optimizer.

master
Ben Kurtovic 9 years ago
parent
commit
f9276db105
2 changed files with 104 additions and 36 deletions
  1. +12
    -6
      src/asm_errors.h
  2. +92
    -30
      src/assembler.c

+ 12
- 6
src/asm_errors.h View File

@@ -11,11 +11,14 @@ typedef enum {
} ASMErrorType; } ASMErrorType;


typedef enum { typedef enum {
ED_BAD_ARG,
ED_RECURSION,
ED_FILE_READ_ERR,
ED_UNKNOWN_DIRECTIVE,
ED_MULTI_DIRECTIVE
ED_INC_BAD_ARG,
ED_INC_RECURSION,
ED_INC_FILE_READ,

ED_PP_UNKNOWN,
ED_PP_DUPLICATE,
ED_PP_NO_ARG,
ED_PP_BAD_ARG
} ASMErrorDesc; } ASMErrorDesc;


/* Strings */ /* Strings */
@@ -29,6 +32,9 @@ static const char *asm_error_descs[] = {
"missing or invalid argument", "missing or invalid argument",
"infinite recursion detected", "infinite recursion detected",
"couldn't read included file", "couldn't read included file",

"unknown directive", "unknown directive",
"multiple values for directive"
"multiple values for directive",
"missing argument for directive",
"invalid argument for directive"
}; };

+ 92
- 30
src/assembler.c View File

@@ -17,27 +17,26 @@
#define DEFAULT_REGION "GG Export" #define DEFAULT_REGION "GG Export"


#define DIRECTIVE_MARKER '.' #define DIRECTIVE_MARKER '.'
#define DIR_INCLUDE "include"
#define DIR_ORIGIN "org"
#define DIR_OPTIMIZER "optimizer"
#define DIR_ROM_SIZE "rom_size"
#define DIR_ROM_HEADER "rom_header"
#define DIR_ROM_CHECKSUM "rom_checksum"
#define DIR_ROM_PRODUCT "rom_product"
#define DIR_ROM_VERSION "rom_version"
#define DIR_ROM_REGION "rom_region"
#define DIR_ROM_DECLSIZE "rom_declsize"

#define DIRECTIVE(d) ("." d)
#define DIREC_LEN(d) (strlen(DIRECTIVE(d)))
#define DIR_INCLUDE ".include"
#define DIR_ORIGIN ".org"
#define DIR_OPTIMIZER ".optimizer"
#define DIR_ROM_SIZE ".rom_size"
#define DIR_ROM_HEADER ".rom_header"
#define DIR_ROM_CHECKSUM ".rom_checksum"
#define DIR_ROM_PRODUCT ".rom_product"
#define DIR_ROM_VERSION ".rom_version"
#define DIR_ROM_REGION ".rom_region"
#define DIR_ROM_DECLSIZE ".rom_declsize"

#define DIRECTIVE_HAS_ARG(line, d) ((line)->length > strlen(d))


#define IS_DIRECTIVE(line, d) \ #define IS_DIRECTIVE(line, d) \
(((line)->length >= DIREC_LEN(d)) && \
!strncmp((line)->data, DIRECTIVE(d), DIREC_LEN(d)) && \
((line)->length == DIREC_LEN(d) || (line)->data[DIREC_LEN(d)] == ' '))
(((line)->length >= strlen(d)) && \
!strncmp((line)->data, d, strlen(d)) && \
(!DIRECTIVE_HAS_ARG(line, d) || (line)->data[strlen(d)] == ' '))


#define DIRECTIVE_OFFSET(line, d) \ #define DIRECTIVE_OFFSET(line, d) \
((line)->length > strlen(DIRECTIVE(d)) ? strlen(DIRECTIVE(d)) : 0)
(DIRECTIVE_HAS_ARG(line, d) ? strlen(d) : 0)


#define ERROR_TYPE(err_info) (asm_error_types[err_info->type]) #define ERROR_TYPE(err_info) (asm_error_types[err_info->type])
#define ERROR_DESC(err_info) (asm_error_descs[err_info->desc]) #define ERROR_DESC(err_info) (asm_error_descs[err_info->desc])
@@ -589,14 +588,14 @@ static ErrorInfo* build_asm_lines(
ErrorInfo *ei; ErrorInfo *ei;
char *path = read_include_path(line); char *path = read_include_path(line);
if (!path) { if (!path) {
ei = create_error(line, ET_INCLUDE, ED_BAD_ARG);
ei = create_error(line, ET_INCLUDE, ED_INC_BAD_ARG);
free_asm_lines(line); free_asm_lines(line);
free_asm_lines(dummy.next); free_asm_lines(dummy.next);
return ei; return ei;
} }


if (path_has_been_loaded(path, root, *includes)) { if (path_has_been_loaded(path, root, *includes)) {
ei = create_error(line, ET_INCLUDE, ED_RECURSION);
ei = create_error(line, ET_INCLUDE, ED_INC_RECURSION);
free_asm_lines(line); free_asm_lines(line);
free_asm_lines(dummy.next); free_asm_lines(dummy.next);
free(path); free(path);
@@ -607,7 +606,7 @@ static ErrorInfo* build_asm_lines(
LineBuffer *incbuffer = read_source_file(path, false); LineBuffer *incbuffer = read_source_file(path, false);
free(path); free(path);
if (!incbuffer) { if (!incbuffer) {
ei = create_error(line, ET_INCLUDE, ED_FILE_READ_ERR);
ei = create_error(line, ET_INCLUDE, ED_INC_FILE_READ);
free_asm_lines(line); free_asm_lines(line);
free_asm_lines(dummy.next); free_asm_lines(dummy.next);
return ei; return ei;
@@ -647,6 +646,48 @@ static ErrorInfo* build_asm_lines(
} }


/* /*
Read in a boolean 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.
*/
static inline bool read_bool_argument(
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;
}

/*
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
@@ -669,14 +710,21 @@ static ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)


// if giving rom size, check header offset is in rom size range // if giving rom size, check header offset is in rom size range
// if giving reported and actual rom size, check reported is <= actual // if giving reported and actual rom size, check reported is <= actual
// ensure no duplicate explicit assignments


#define CATCH_DUPLICATES(line, first) \
if (first) { \
ei = create_error(line, ET_PREPROC, ED_MULTI_DIRECTIVE); \
#define CATCH_DUPES(line, first, oldval, newval) \
if (first && oldval != newval) { \
ei = create_error(line, ET_PREPROC, ED_PP_DUPLICATE); \
append_to_error(ei, first); \ append_to_error(ei, first); \
return ei; \ return ei; \
} // TODO: actually check values for dupes
}

#define REQUIRE_ARG(line, d) \
if (!DIRECTIVE_HAS_ARG(line, d)) \
return create_error(line, ET_PREPROC, ED_PP_NO_ARG);

#define VALIDATE(retval) \
if (!(retval)) \
return create_error(line, ET_PREPROC, ED_PP_BAD_ARG);


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


@@ -685,18 +733,24 @@ static ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
&state->includes))) &state->includes)))
return ei; return ei;


ASMLine dummy = {.next = state->lines};
ASMLine *prev, *line = &dummy, *next = state->lines;
const ASMLine *first_optimizer = NULL; const ASMLine *first_optimizer = NULL;


const ASMLine *line, *next = state->lines;
while ((line = next)) {
while ((prev = line, line = next)) {
next = line->next; next = line->next;
if (line->data[0] == DIRECTIVE_MARKER) { if (line->data[0] == DIRECTIVE_MARKER) {
if (IS_DIRECTIVE(line, DIR_ORIGIN)) if (IS_DIRECTIVE(line, DIR_ORIGIN))
continue; // Origins are handled by tokenizer continue; // Origins are handled by tokenizer


DEBUG("- handling directive: %.*s", (int) line->length, line->data) DEBUG("- handling directive: %.*s", (int) line->length, line->data)

if (IS_DIRECTIVE(line, DIR_OPTIMIZER)) { if (IS_DIRECTIVE(line, DIR_OPTIMIZER)) {
CATCH_DUPLICATES(line, first_optimizer)
REQUIRE_ARG(line, DIR_OPTIMIZER)
bool arg;
VALIDATE(read_bool_argument(&arg, line, DIR_OPTIMIZER, false))
CATCH_DUPES(line, first_optimizer, state->optimizer, arg)
state->optimizer = arg;
first_optimizer = line; first_optimizer = line;
} else if (IS_DIRECTIVE(line, DIR_ROM_SIZE)) { } else if (IS_DIRECTIVE(line, DIR_ROM_SIZE)) {
// TODO // TODO
@@ -713,8 +767,14 @@ static 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
} else { } else {
return create_error(line, ET_PREPROC, ED_UNKNOWN_DIRECTIVE);
return create_error(line, ET_PREPROC, ED_PP_UNKNOWN);
} }

// Remove the directive from the line list:
prev->next = next;
line->next = NULL;
free_asm_lines(line);
line = prev;
} }
} }


@@ -732,7 +792,9 @@ static ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)


return NULL; return NULL;


#undef CATCH_DUPLICATES
#undef VALIDATE
#undef REQUIRE_ARG
#undef CATCH_DUPES
} }


/* /*


Loading…
Cancel
Save