Browse Source

Finish implementing .define/.undef directives.

master
Ben Kurtovic 9 years ago
parent
commit
1c35adf276
5 changed files with 140 additions and 45 deletions
  1. +45
    -33
      src/assembler/parse_util.c
  2. +1
    -10
      src/assembler/preprocessor.c
  3. +83
    -2
      src/assembler/tokenizer.c
  4. +9
    -0
      src/util.c
  5. +2
    -0
      src/util.h

+ 45
- 33
src/assembler/parse_util.c View File

@@ -56,6 +56,34 @@ static bool adjust_for_indirection(ASMArgParseInfo *ap_info)
} }


/* /*
Calculate the mask field for an ASMArgImmediate based on its uval/sval.
*/
static void calculate_immediate_mask(ASMArgImmediate *imm)
{
imm->mask = 0;
if (imm->sval < 0) {
if (imm->sval >= INT8_MIN)
imm->mask |= IMM_S8;
if (imm->sval >= INT8_MIN + 2)
imm->mask |= IMM_REL;
} else {
imm->mask = IMM_U16;
if (imm->uval <= UINT8_MAX)
imm->mask |= IMM_U8;
if (imm->uval <= INT8_MAX)
imm->mask |= IMM_S8;
if (imm->uval <= INT8_MAX + 2)
imm->mask |= IMM_REL;
if (imm->uval <= 7)
imm->mask |= IMM_BIT;
if (!(imm->uval & ~0x38))
imm->mask |= IMM_RST;
if (imm->uval <= 2)
imm->mask |= IMM_IM;
}
}

/*
Read in a boolean value and store it in *result. Read in a boolean value and store it in *result.
*/ */
bool parse_bool(bool *result, const char *arg, ssize_t size) bool parse_bool(bool *result, const char *arg, ssize_t size)
@@ -303,12 +331,6 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
if (ai.size <= 0) if (ai.size <= 0)
return false; return false;


const ASMDefine *define = asm_deftable_find(ai.deftable, ai.arg, ai.size);
if (define) {
*result = define->value;
return true;
}

bool negative = false; bool negative = false;
ssize_t i = 0; ssize_t i = 0;


@@ -318,9 +340,23 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
if (++i >= ai.size) if (++i >= ai.size)
return false; return false;
} }
ai.arg += i;
ai.size -= i;

const ASMDefine *define = asm_deftable_find(ai.deftable, ai.arg, ai.size);
if (define) {
if (negative) {
result->uval = define->value.uval;
result->sval = -define->value.sval;
calculate_immediate_mask(result);
} else {
*result = define->value;
}
return true;
}


uint32_t uval; uint32_t uval;
if (!parse_uint32_t(&uval, ai.arg + i, ai.size - i) || uval > UINT16_MAX)
if (!parse_uint32_t(&uval, ai.arg, ai.size) || uval > UINT16_MAX)
return false; return false;


int32_t sval = negative ? -uval : uval; int32_t sval = negative ? -uval : uval;
@@ -329,28 +365,7 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)


result->uval = uval; result->uval = uval;
result->sval = sval; result->sval = sval;
result->mask = 0;

if (sval < 0) {
if (sval >= INT8_MIN)
result->mask |= IMM_S8;
if (sval >= INT8_MIN + 2)
result->mask |= IMM_REL;
} else {
result->mask = IMM_U16;
if (uval <= UINT8_MAX)
result->mask |= IMM_U8;
if (uval <= INT8_MAX)
result->mask |= IMM_S8;
if (uval <= INT8_MAX + 2)
result->mask |= IMM_REL;
if (uval <= 7)
result->mask |= IMM_BIT;
if (!(uval & ~0x38))
result->mask |= IMM_RST;
if (uval <= 2)
result->mask |= IMM_IM;
}
calculate_immediate_mask(result);
return true; return true;
} }


@@ -425,11 +440,8 @@ bool argparse_label(ASMArgLabel *result, ASMArgParseInfo ai)
if (ai.size <= 0 || ai.size >= MAX_SYMBOL_SIZE) if (ai.size <= 0 || ai.size >= MAX_SYMBOL_SIZE)
return false; return false;


// Validate the label characters:
for (const char *i = ai.arg; i < ai.arg + ai.size; i++) { for (const char *i = ai.arg; i < ai.arg + ai.size; i++) {
char c = *i;
if (!((c >= 'a' && c <= 'z') || c == '_' || c == '.' ||
(i != ai.arg && c >= '0' && c <= '9')))
if (!is_valid_symbol_char(*i, i == ai.arg))
return false; return false;
} }




+ 1
- 10
src/assembler/preprocessor.c View File

@@ -85,15 +85,6 @@
else FAIL_ON_COND_(true, ED_PP_UNKNOWN) else FAIL_ON_COND_(true, ED_PP_UNKNOWN)


/* /*
Return whether the given character is a valid label character.
*/
static inline bool is_valid_label_char(char c, bool first)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(!first && c >= '0' && c <= '9') || c == '_' || c == '.';
}

/*
Functions similar memcpy, but lowercases the characters along the way. Functions similar memcpy, but lowercases the characters along the way.
*/ */
static void memcpy_lc(char *restrict dst, const char *restrict src, size_t n) static void memcpy_lc(char *restrict dst, const char *restrict src, size_t n)
@@ -121,7 +112,7 @@ static size_t read_labels(
start++; start++;


i = start; i = start;
while (i < length && is_valid_label_char(source[i], i == start))
while (i < length && is_valid_symbol_char(source[i], i == start))
i++; i++;


if (i == start || i == length || source[i] != ':') { if (i == start || i == length || source[i] != ':') {


+ 83
- 2
src/assembler/tokenizer.c View File

@@ -12,6 +12,7 @@
#include "../logging.h" #include "../logging.h"
#include "../mmu.h" #include "../mmu.h"
#include "../rom.h" #include "../rom.h"
#include "../util.h"


/* Internal structs */ /* Internal structs */


@@ -128,6 +129,84 @@ static ErrorInfo* add_label_to_table(
} }


/* /*
Handle a define directive by adding an entry to the define table.

Return NULL on success and an ErrorInfo object on failure.
*/
static ErrorInfo* handle_define_directive(
const ASMLine *line, ASMDefineTable *deftab)
{
if (!DIRECTIVE_HAS_ARG(line, DIR_DEFINE))
return error_info_create(line, ET_PREPROC, ED_PP_NO_ARG);

size_t start = DIRECTIVE_OFFSET(line, DIR_DEFINE) + 1, i;
for (i = start; i < line->length; i++) {
if (!is_valid_symbol_char(line->data[i], i == start)) {
if (line->data[i] == ' ' && i > start) {
i++;
break;
}
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG);
}
}

if (i >= line->length) // Missing value for define
return error_info_create(line, ET_PREPROC, ED_PP_NO_ARG);

const char *key = line->data + start;
size_t keylen = i - start - 1;

const ASMDefine *current = asm_deftable_find(deftab, key, keylen);
if (current) {
ErrorInfo *ei = error_info_create(line, ET_PREPROC, ED_PP_DUPLICATE);
error_info_append(ei, current->line);
return ei;
}

ASMArgImmediate imm;
ASMArgParseInfo info = {
.arg = line->data + i, .size = line->length - i, .deftable = deftab};
if (!argparse_immediate(&imm, info))
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG);

ASMDefine *define = malloc(sizeof(ASMDefine));
if (!define)
OUT_OF_MEMORY()

if (!(define->name = strndup(key, keylen)))
OUT_OF_MEMORY()

define->value = imm;
define->line = line;
asm_deftable_insert(deftab, define);
return NULL;
}

/*
Handle an undefine directive by remove an entry in the define table.

Return NULL on success and an ErrorInfo object on failure.
*/
static ErrorInfo* handle_undef_directive(
const ASMLine *line, ASMDefineTable *deftab)
{
if (!DIRECTIVE_HAS_ARG(line, DIR_UNDEF))
return error_info_create(line, ET_PREPROC, ED_PP_NO_ARG);

size_t offset = DIRECTIVE_OFFSET(line, DIR_UNDEF) + 1;
const char *arg = line->data + offset;
size_t size = line->length - offset, i;

for (i = 0; i < size; i++) {
if (!is_valid_symbol_char(arg[i], i == 0))
return error_info_create(line, ET_PREPROC, ED_PP_BAD_ARG);
}

asm_deftable_remove(deftab, arg, size);
return NULL;
}

/*
Handle an origin directive by updating the offset. Handle an origin directive by updating the offset.


Return NULL on success and an ErrorInfo object on failure. Return NULL on success and an ErrorInfo object on failure.
@@ -410,10 +489,12 @@ ErrorInfo* tokenize(AssemblerState *state)
} }
else if (IS_LOCAL_DIRECTIVE(line)) { else if (IS_LOCAL_DIRECTIVE(line)) {
if (IS_DIRECTIVE(line, DIR_DEFINE)) { if (IS_DIRECTIVE(line, DIR_DEFINE)) {
// TODO
if ((ei = handle_define_directive(line, deftab)))
goto cleanup;
} }
else if (IS_DIRECTIVE(line, DIR_UNDEF)) { else if (IS_DIRECTIVE(line, DIR_UNDEF)) {
// TODO
if ((ei = handle_undef_directive(line, deftab)))
goto cleanup;
} }
else if (IS_DIRECTIVE(line, DIR_ORIGIN)) { else if (IS_DIRECTIVE(line, DIR_ORIGIN)) {
if ((ei = handle_origin_directive(line, &offset))) if ((ei = handle_origin_directive(line, &offset)))


+ 9
- 0
src/util.c View File

@@ -54,6 +54,15 @@ uint64_t get_time_ns()
} }


/* /*
Return whether the given character is valid in a symbol (label, define).
*/
bool is_valid_symbol_char(char c, bool first)
{
return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
(!first && c >= '0' && c <= '9') || c == '_' || c == '.';
}

/*
Return the name of the region encoded by the given region code. Return the name of the region encoded by the given region code.


The given code should not be larger than one nibble. NULL is returned if The given code should not be larger than one nibble. NULL is returned if


+ 2
- 0
src/util.h View File

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


#pragma once #pragma once


#include <stdbool.h>
#include <stdint.h> #include <stdint.h>


#define INVALID_SIZE_CODE 0x8 #define INVALID_SIZE_CODE 0x8
@@ -12,6 +13,7 @@
uint8_t bcd_encode(uint8_t); uint8_t bcd_encode(uint8_t);
uint8_t bcd_decode(uint8_t); uint8_t bcd_decode(uint8_t);
uint64_t get_time_ns(); uint64_t get_time_ns();
bool is_valid_symbol_char(char, bool);
const char* region_code_to_string(uint8_t); const char* region_code_to_string(uint8_t);
uint8_t region_string_to_code(const char*); uint8_t region_string_to_code(const char*);
size_t size_code_to_bytes(uint8_t); size_t size_code_to_bytes(uint8_t);


Loading…
Cancel
Save