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.
*/
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)
return false;

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

bool negative = false;
ssize_t i = 0;

@@ -318,9 +340,23 @@ bool argparse_immediate(ASMArgImmediate *result, ASMArgParseInfo ai)
if (++i >= ai.size)
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;
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;

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

result->uval = uval;
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;
}

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

// Validate the label characters:
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;
}



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

@@ -85,15 +85,6 @@
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.
*/
static void memcpy_lc(char *restrict dst, const char *restrict src, size_t n)
@@ -121,7 +112,7 @@ static size_t read_labels(
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++;

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


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

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

/* 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.

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

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

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

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


Loading…
Cancel
Save