Browse Source

Refactor directive macros to hide 'arg'; misc tweaks.

master
Ben Kurtovic 9 years ago
parent
commit
971af841cf
3 changed files with 83 additions and 72 deletions
  1. +49
    -0
      src/assembler/parse_util.c
  2. +3
    -0
      src/assembler/parse_util.h
  3. +31
    -72
      src/assembler/preprocessor.c

+ 49
- 0
src/assembler/parse_util.c View File

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

#include "parse_util.h"
#include "directives.h"
#include "../util.h"

#define MAX_REGION_SIZE 32

/*
Read in a boolean argument from the given line and store it in *result.
@@ -122,3 +125,49 @@ bool parse_uint8_t(uint8_t *result, const ASMLine *line, const char *directive)
return (*result = value), true;
return false;
}

/*
Parse the region code string in an ASMLine and store it in *result.

Return true on success and false on failure; in the latter case, *result is
not modified.
*/
bool parse_region_string(uint8_t *result, const ASMLine *line)
{
char buffer[MAX_REGION_SIZE];

size_t offset = DIRECTIVE_OFFSET(line, DIR_ROM_REGION) + 1;
const char *arg = line->data + offset;
ssize_t len = line->length - offset;

if (len <= 2 || len >= MAX_REGION_SIZE + 2) // Account for double quotes
return false;
if (arg[0] != '"' || arg[len - 1] != '"')
return false;

strncpy(buffer, arg + 1, len - 2);
buffer[len - 2] = '\0';

uint8_t code = region_string_to_code(buffer);
if (code)
return (*result = code), true;
return false;
}

/*
Parse the size code in an ASMLine and store it in *result.

Return true on success and false on failure; in the latter case, *result is
not modified.
*/
bool parse_size_code(uint8_t *result, const ASMLine *line)
{
uint32_t bytes;
if (!parse_uint32_t(&bytes, line, DIR_ROM_DECLSIZE))
return false;

uint8_t code = size_bytes_to_code(bytes);
if (code)
return (*result = code), true;
return false;
}

+ 3
- 0
src/assembler/parse_util.h View File

@@ -16,3 +16,6 @@ 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*);

bool parse_region_string(uint8_t*, const ASMLine*);
bool parse_size_code(uint8_t*, const ASMLine*);

+ 31
- 72
src/assembler/preprocessor.c View File

@@ -17,33 +17,37 @@
#include "../logging.h"
#include "../util.h"

#define MAX_REGION_SIZE 32

/* Helper macros for preprocess() */

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

#define FAIL_ON_COND(cond, err_desc) \
if ((cond)) FAIL(err_desc)
#define CALL_GENERIC_PARSER_(arg_type) \
parse_##arg_type((arg_type*) &arg, line, directive)

#define VALIDATE(retval) \
FAIL_ON_COND(!(retval), ED_PP_BAD_ARG)
#define CALL_SPECIFIC_PARSER_(arg_type, parser) \
parse_##parser((arg_type*) &arg, line)

#define CLAMP_RANGE(bound) \
FAIL_ON_COND(arg > bound, ED_PP_ARG_RANGE)
#define DISPATCH_(first, second, target, ...) target

#define GEN_PARSER_CALL(arg_type) \
parse_##arg_type((arg_type*) &arg, line, directive)
#define CALL_PARSER_(...) \
DISPATCH_(__VA_ARGS__, CALL_SPECIFIC_PARSER_, CALL_GENERIC_PARSER_, \
__VA_ARGS__)(__VA_ARGS__)

#define USE_PARSER(arg_type) \
VALIDATE(GEN_PARSER_CALL(arg_type))
#define VALIDATE(func) \
FAIL_ON_COND_(!(func(arg)), ED_PP_BAD_ARG)

#define CHECK_RANGE(bound) \
FAIL_ON_COND_(arg > bound, ED_PP_ARG_RANGE)

#define USE_PARSER(...) \
FAIL_ON_COND_(!CALL_PARSER_(__VA_ARGS__), ED_PP_BAD_ARG)

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

#define BEGIN_DIRECTIVE_BLOCK \
ssize_t first_ctr = -1; \
@@ -52,7 +56,7 @@
#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) \
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)) { \
@@ -71,7 +75,7 @@
}

#define END_DIRECTIVE_BLOCK \
else FAIL(ED_PP_UNKNOWN)
else FAIL_ON_COND_(true, ED_PP_UNKNOWN)

/*
Preprocess a single source line (source, length) into a normalized ASMLine.
@@ -314,51 +318,6 @@ static inline bool is_header_offset_valid(uint16_t offset)
}

/*
Parse the region code string in an ASMLine and store it in *result.

Return true on success and false on failure; in the latter case, *result is
not modified.
*/
static bool parse_region_string(uint8_t *result, const ASMLine *line)
{
char buffer[MAX_REGION_SIZE];

size_t offset = DIRECTIVE_OFFSET(line, DIR_ROM_REGION) + 1;
const char *arg = line->data + offset;
ssize_t len = line->length - offset;

if (len <= 2 || len >= MAX_REGION_SIZE + 2) // Account for double quotes
return false;
if (arg[0] != '"' || arg[len - 1] != '"')
return false;

strncpy(buffer, arg + 1, len - 2);
buffer[len - 2] = '\0';

uint8_t code = region_string_to_code(buffer);
if (code)
return (*result = code), true;
return false;
}

/*
Parse the size code in an ASMLine and store it in *result.

Return true on success and false on failure.
*/
static bool parse_size_code(uint8_t *result, const ASMLine *line)
{
uint32_t bytes;
if (!parse_uint32_t(&bytes, line, DIR_ROM_DECLSIZE))
return false;

uint8_t code = size_bytes_to_code(bytes);
if (code)
return (*result = code), true;
return false;
}

/*
Preprocess the LineBuffer into ASMLines. Change some state along the way.

This function processes include directives, so read_source_file() may be
@@ -402,12 +361,12 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)

BEGIN_DIRECTIVE(DIR_ROM_SIZE, size_t, state->rom_size, 0)
// TODO: fixme
FAIL(ED_PP_UNKNOWN)
FAIL_ON_COND_(1, 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))
VALIDATE(is_header_offset_valid)
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_CHECKSUM, bool, state->header.checksum, true)
@@ -416,29 +375,29 @@ ErrorInfo* preprocess(AssemblerState *state, const LineBuffer *source)

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

BEGIN_DIRECTIVE(DIR_ROM_VERSION, uint8_t, state->header.version, 0)
USE_PARSER(uint8_t)
CLAMP_RANGE(0x10)
CHECK_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))
CHECK_RANGE(0x10)
VALIDATE(region_code_to_string)
}, {
VALIDATE(parse_region_string(&arg, line))
USE_PARSER(uint8_t, region_string)
})
END_DIRECTIVE

BEGIN_DIRECTIVE(DIR_ROM_DECLSIZE, uint8_t, state->header.rom_size, 0)
PARSER_BRANCH(uint8_t, {
CLAMP_RANGE(0x10)
VALIDATE(size_code_to_bytes(arg))
CHECK_RANGE(0x10)
VALIDATE(size_code_to_bytes)
}, {
VALIDATE(parse_size_code(&arg, line))
USE_PARSER(uint8_t, size_code)
})
END_DIRECTIVE



Loading…
Cancel
Save