Parcourir la source

Rework the preprocessor system using insanity.

master
Ben Kurtovic il y a 9 ans
Parent
révision
eebb90530e
6 fichiers modifiés avec 148 ajouts et 124 suppressions
  1. +17
    -11
      src/assembler/directives.h
  2. +9
    -11
      src/assembler/parse_util.c
  3. +8
    -4
      src/assembler/parse_util.h
  4. +110
    -93
      src/assembler/preprocessor.c
  5. +1
    -5
      src/assembler/state.c
  6. +3
    -0
      src/assembler/state.h

+ 17
- 11
src/assembler/directives.h Voir le fichier

@@ -5,17 +5,19 @@

#include <string.h>

#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_MARKER '.'
#define NUM_DIRECTIVES 10

#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))

@@ -26,3 +28,7 @@

#define DIRECTIVE_OFFSET(line, d) \
(DIRECTIVE_HAS_ARG(line, d) ? strlen(d) : 0)

#define DIRECTIVE_IS_AUTO(line, d) \
(line->length - (DIRECTIVE_OFFSET(line, d) + 1) == 4 && \
!strncmp(line->data + (DIRECTIVE_OFFSET(line, d) + 1), "auto", 4))

+ 9
- 11
src/assembler/parse_util.c Voir le fichier

@@ -10,10 +10,10 @@
/*
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.
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_bool(bool *result, const ASMLine *line, const char *directive)
{
size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
const char *arg = line->data + offset;
@@ -35,11 +35,9 @@ bool parse_bool(bool *result, const ASMLine *line, const char *directive, bool a
if (!strncmp(arg, "off", 3))
return (*result = false), true;
return false;
case 4: // true, auto
case 4: // true
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))
@@ -55,7 +53,7 @@ bool parse_bool(bool *result, const ASMLine *line, const char *directive, bool a
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_uint32_t(uint32_t *result, const ASMLine *line, const char *directive)
{
size_t offset = DIRECTIVE_OFFSET(line, directive) + 1;
const char *str = line->data + offset;
@@ -103,10 +101,10 @@ bool parse_uint32(uint32_t *result, const ASMLine *line, const char *directive)
Return true on success and false on failure; in the latter case, *result is
not modified.
*/
bool parse_uint16(uint16_t *result, const ASMLine *line, const char *directive)
bool parse_uint16_t(uint16_t *result, const ASMLine *line, const char *directive)
{
uint32_t value;
if (parse_uint32(&value, line, directive) && value <= UINT16_MAX)
if (parse_uint32_t(&value, line, directive) && value <= UINT16_MAX)
return (*result = value), true;
return false;
}
@@ -117,10 +115,10 @@ bool parse_uint16(uint16_t *result, const ASMLine *line, const char *directive)
Return true on success and false on failure; in the latter case, *result is
not modified.
*/
bool parse_uint8(uint8_t *result, const ASMLine *line, const char *directive)
bool parse_uint8_t(uint8_t *result, const ASMLine *line, const char *directive)
{
uint32_t value;
if (parse_uint32(&value, line, directive) && value <= UINT8_MAX)
if (parse_uint32_t(&value, line, directive) && value <= UINT8_MAX)
return (*result = value), true;
return false;
}

+ 8
- 4
src/assembler/parse_util.h Voir le fichier

@@ -8,7 +8,11 @@

#include "state.h"

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*);
#define parse__Bool parse_bool

/* Functions */

bool parse_bool(bool*, const ASMLine*, const char*);
bool parse_uint32_t(uint32_t*, const ASMLine*, const char*);
bool parse_uint16_t(uint16_t*, const ASMLine*, const char*);
bool parse_uint8_t(uint8_t*, const ASMLine*, const char*);

+ 110
- 93
src/assembler/preprocessor.c Voir le fichier

@@ -19,32 +19,60 @@

#define MAX_REGION_SIZE 32

/* Helper defines for preprocess() */
/* Helper macros for preprocess() */

#define SAVE_ARG(line, first, oldval, newval) \
if (first && oldval != newval) { \
ei = error_info_create(line, ET_PREPROC, ED_PP_DUPLICATE); \
error_info_append(ei, first); \
goto cleanup; \
} \
oldval = newval; \
first = line;

#define FAIL_ON_COND(cond, err_desc) \
if ((cond)) { \
#define FAIL(err_desc) \
{ \
ei = error_info_create(line, ET_PREPROC, err_desc); \
goto cleanup; \
}

#define REQUIRE_ARG(line, d) \
FAIL_ON_COND(!DIRECTIVE_HAS_ARG(line, d), ED_PP_NO_ARG)
#define FAIL_ON_COND(cond, err_desc) \
if ((cond)) FAIL(err_desc)

#define VALIDATE(retval) \
FAIL_ON_COND(!(retval), ED_PP_BAD_ARG)

#define RANGE_CHECK(arg, bound) \
#define CLAMP_RANGE(bound) \
FAIL_ON_COND(arg > bound, ED_PP_ARG_RANGE)

#define GEN_PARSER_CALL(arg_type) \
parse_##arg_type((arg_type*) &arg, line, directive)

#define USE_PARSER(arg_type) \
VALIDATE(GEN_PARSER_CALL(arg_type))

#define PARSER_BRANCH(arg_type, true_part, false_part) \
if (GEN_PARSER_CALL(arg_type)) {true_part} else {false_part}

#define BEGIN_DIRECTIVE_BLOCK \
ssize_t first_ctr = -1; \
if (0) {}

#define BEGIN_DIRECTIVE(d, arg_type, dest_loc, auto_val) \
else if (first_ctr++, IS_DIRECTIVE(line, d)) { \
directive = d; \
FAIL_ON_COND(!DIRECTIVE_HAS_ARG(line, directive), ED_PP_NO_ARG) \
arg_type arg; \
arg_type* dest = &(dest_loc); \
if (DIRECTIVE_IS_AUTO(line, directive)) { \
arg = auto_val; \
} else {

#define END_DIRECTIVE \
} \
if (firsts[first_ctr] && *dest != arg) { \
ei = error_info_create(line, ET_PREPROC, ED_PP_DUPLICATE); \
error_info_append(ei, firsts[first_ctr]); \
goto cleanup; \
} \
*dest = arg; \
firsts[first_ctr] = line; \
}

#define END_DIRECTIVE_BLOCK \
else FAIL(ED_PP_UNKNOWN)

/*
Preprocess a single source line (source, length) into a normalized ASMLine.

@@ -332,86 +360,74 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
&state->includes)))
return ei;

const ASMLine *firsts[NUM_DIRECTIVES];
for (size_t i = 0; i < NUM_DIRECTIVES; i++)
firsts[i] = NULL;

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

const ASMLine *first_optimizer = NULL, *first_offset = NULL,
*first_checksum = NULL, *first_product = NULL,
*first_version = NULL, *first_region = NULL;
const char *directive;

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

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

if (IS_DIRECTIVE(line, DIR_OPTIMIZER)) {
REQUIRE_ARG(line, DIR_OPTIMIZER)
bool arg;
VALIDATE(parse_bool(&arg, line, DIR_OPTIMIZER, false))
SAVE_ARG(line, first_optimizer, state->optimizer, arg)
}
else if (IS_DIRECTIVE(line, DIR_ROM_SIZE)) {
// TODO
// state->rom_size <-- value check
// auto
}
else if (IS_DIRECTIVE(line, DIR_ROM_HEADER)) {
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)) {
REQUIRE_ARG(line, DIR_ROM_CHECKSUM)
bool arg;
VALIDATE(parse_bool(&arg, line, DIR_ROM_CHECKSUM, true))
SAVE_ARG(line, first_checksum, state->header.checksum, arg)
}
else if (IS_DIRECTIVE(line, DIR_ROM_PRODUCT)) {
REQUIRE_ARG(line, DIR_ROM_PRODUCT)
uint32_t arg;
VALIDATE(parse_uint32(&arg, line, DIR_ROM_PRODUCT)) // auto
RANGE_CHECK(arg, 160000)
SAVE_ARG(line, first_product, state->header.product_code, arg)
}
else if (IS_DIRECTIVE(line, DIR_ROM_VERSION)) {
REQUIRE_ARG(line, DIR_ROM_VERSION)
uint8_t arg;
VALIDATE(parse_uint8(&arg, line, DIR_ROM_VERSION)) // auto
RANGE_CHECK(arg, 0x10)
SAVE_ARG(line, first_version, state->header.version, arg)
}
else if (IS_DIRECTIVE(line, DIR_ROM_REGION)) {
REQUIRE_ARG(line, DIR_ROM_REGION)
uint8_t arg;
if (parse_uint8(&arg, line, DIR_ROM_REGION)) { // auto
RANGE_CHECK(arg, 0x10)
VALIDATE(region_code_to_string(arg))
} else {
VALIDATE(parse_region_string(&arg, line))
}
SAVE_ARG(line, first_region, state->header.region, arg)
}
else if (IS_DIRECTIVE(line, DIR_ROM_DECLSIZE)) {
// TODO
// state->header.rom_size <-- value/range check
// auto
}
else {
ei = error_info_create(line, ET_PREPROC, ED_PP_UNKNOWN);
goto cleanup;
}

// Remove directive from lines, and schedule it for deletion:
line->next = condemned;
condemned = line;
prev->next = next;
line = prev;
}
if (line->data[0] != DIRECTIVE_MARKER)
continue;
if (IS_DIRECTIVE(line, DIR_ORIGIN))
continue; // Origins are handled by tokenizer

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

BEGIN_DIRECTIVE_BLOCK

BEGIN_DIRECTIVE(DIR_OPTIMIZER, bool, state->optimizer, false)
USE_PARSER(bool)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_SIZE, size_t, state->rom_size, 0)
// TODO: fixme
FAIL(ED_PP_UNKNOWN)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_HEADER, size_t, state->header.offset, DEFAULT_HEADER_OFFSET)
USE_PARSER(uint16_t)
VALIDATE(is_header_offset_valid(arg))
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_CHECKSUM, bool, state->header.checksum, true)
USE_PARSER(bool)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_PRODUCT, uint32_t, state->header.product_code, 0)
USE_PARSER(uint32_t)
CLAMP_RANGE(160000)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_VERSION, uint8_t, state->header.version, 0)
USE_PARSER(uint8_t)
CLAMP_RANGE(0x10)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_REGION, uint8_t, state->header.region, DEFAULT_REGION)
PARSER_BRANCH(uint8_t, {
CLAMP_RANGE(0x10)
VALIDATE(region_code_to_string(arg))
}, {
VALIDATE(parse_region_string(&arg, line))
})
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_DECLSIZE, uint8_t, state->header.rom_size, 0)
// TODO: fixme
FAIL(ED_PP_UNKNOWN)
END_DIRECTIVE

END_DIRECTIVE_BLOCK

// Remove directive from lines, and schedule it for deletion:
line->next = condemned;
condemned = line;
prev->next = next;
line = prev;
}

// TODO: if giving rom size, check header offset is in rom size range
@@ -419,6 +435,10 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)

state->rom_size = 8; // TODO

cleanup:
asm_lines_free(condemned);
state->lines = dummy.next; // Fix list head if first line was a directive

#ifdef DEBUG_MODE
DEBUG("Dumping ASMLines:")
const ASMLine *temp = state->lines;
@@ -429,8 +449,5 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)
}
#endif

cleanup:
asm_lines_free(condemned);
state->lines = dummy.next; // Fix list head if first line was a directive
return ei;
}

+ 1
- 5
src/assembler/state.c Voir le fichier

@@ -6,10 +6,6 @@
#include "state.h"
#include "io.h"
#include "../logging.h"
#include "../util.h"

#define DEFAULT_HEADER_OFFSET 0x7FF0
#define DEFAULT_REGION "GG Export"

/*
Initialize default values in an AssemblerState object.
@@ -20,7 +16,7 @@ void state_init(AssemblerState *state)
state->header.checksum = true;
state->header.product_code = 0;
state->header.version = 0;
state->header.region = region_string_to_code(DEFAULT_REGION);
state->header.region = DEFAULT_REGION;
state->header.rom_size = 0;
state->optimizer = false;
state->rom_size = 0;


+ 3
- 0
src/assembler/state.h Voir le fichier

@@ -9,6 +9,9 @@

#include "../assembler.h"

#define DEFAULT_HEADER_OFFSET 0x7FF0
#define DEFAULT_REGION 6 // GG Export

#define SYMBOL_TABLE_BUCKETS 128

/* Structs */


Chargement…
Annuler
Enregistrer