diff options
-rw-r--r-- | asm/lexer.c | 7 | ||||
-rw-r--r-- | asm/lexer.h | 1 | ||||
-rw-r--r-- | asm/parser.c | 115 | ||||
-rw-r--r-- | asm/parser.h | 15 |
4 files changed, 102 insertions, 36 deletions
diff --git a/asm/lexer.c b/asm/lexer.c index 525deb2..7f37ce7 100644 --- a/asm/lexer.c +++ b/asm/lexer.c @@ -24,6 +24,8 @@ const char *token_type_as_cstr(token_type_t type) { switch (type) { + case TOKEN_GLOBAL: + return "GLOBAL"; case TOKEN_STAR: return "STAR"; case TOKEN_LITERAL_NUMBER: @@ -331,6 +333,11 @@ token_t tokenise_symbol(buffer_t *buffer, size_t *column) offset = 3; type = TOKEN_RET; } + else if (sym_size == 6 && strncmp(opcode, "GLOBAL", 6) == 0) + { + offset = 6; + type = TOKEN_GLOBAL; + } else is_opcode = false; diff --git a/asm/lexer.h b/asm/lexer.h index cdddb6a..0ced4ca 100644 --- a/asm/lexer.h +++ b/asm/lexer.h @@ -17,6 +17,7 @@ typedef enum TokenType { + TOKEN_GLOBAL, TOKEN_STAR, TOKEN_LITERAL_NUMBER, TOKEN_LITERAL_CHAR, diff --git a/asm/parser.c b/asm/parser.c index 4843429..196c09c 100644 --- a/asm/parser.c +++ b/asm/parser.c @@ -35,6 +35,8 @@ const char *perr_as_cstr(perr_t perr) return "EXPECTED_UTYPE"; case PERR_EXPECTED_SYMBOL: return "EXPECTED_SYMBOL"; + case PERR_EXPECTED_LABEL: + return "EXPECTED_LABEL"; case PERR_EXPECTED_OPERAND: return "EXPECTED_OPERAND"; case PERR_UNKNOWN_LABEL: @@ -141,7 +143,7 @@ perr_t parse_word_label_or_relative(token_stream_t *stream, presult_t *res) res->type = PRES_RELATIVE_ADDRESS; ++stream->used; return parse_sword(TOKEN_STREAM_AT(stream->data, stream->used), - &res->relative_address); + &res->address); } return PERR_EXPECTED_OPERAND; } @@ -271,6 +273,18 @@ perr_t parse_next(token_stream_t *stream, presult_t *ret) case TOKEN_LITERAL_NUMBER: case TOKEN_LITERAL_CHAR: return PERR_EXPECTED_SYMBOL; + case TOKEN_GLOBAL: { + if (stream->used + 1 >= stream->available || + TOKEN_STREAM_AT(stream->data, stream->used + 1).type != TOKEN_SYMBOL) + return PERR_EXPECTED_LABEL; + ++stream->used; + token_t label = TOKEN_STREAM_AT(stream->data, stream->used); + *ret = (presult_t){.type = PRES_GLOBAL_LABEL, + .label = malloc(label.str_size + 1)}; + memcpy(ret->label, label.str, label.str_size); + ret->label[label.str_size] = '\0'; + return PERR_OK; + } case TOKEN_NOOP: *ret = (presult_t){.instruction = INST_NOOP, .type = PRES_COMPLETE_RESULT}; break; @@ -448,12 +462,19 @@ perr_t parse_next(token_stream_t *stream, presult_t *ret) return perr; } -struct LabelPair +label_t search_labels(label_t *labels, size_t n, char *name) { - char *label; - size_t label_size; - word addr; -}; + size_t name_size = strlen(name); + for (size_t i = 0; i < n; ++i) + { + label_t label = labels[i]; + if (label.name_size == name_size && + strncmp(label.name, name, name_size) == 0) + return label; + } + + return (label_t){0}; +} perr_t process_presults(presult_t *results, size_t res_count, inst_t **instructions, size_t *inst_count) @@ -474,10 +495,13 @@ perr_t process_presults(presult_t *results, size_t res_count, printf("\n"); break; case PRES_RELATIVE_ADDRESS: - printf("\tRELATIVE_CALL: addr=%lu, inst=", pres.relative_address); + printf("\tRELATIVE_CALL: addr=%ld, inst=", pres.address); inst_print(pres.instruction, stdout); printf("\n"); break; + case PRES_GLOBAL_LABEL: + printf("\tSET_GLOBAL_START: name=%s\n", pres.label); + break; case PRES_COMPLETE_RESULT: printf("\tCOMPLETE: inst="); inst_print(pres.instruction, stdout); @@ -486,8 +510,11 @@ perr_t process_presults(presult_t *results, size_t res_count, } } #endif - darr_t label_pairs = {0}; - darr_init(&label_pairs, sizeof(struct LabelPair)); + bool global_start_defined = false; + char *start_label = NULL; + + darr_t label_registry = {0}; + darr_init(&label_registry, sizeof(label_t)); *inst_count = 0; for (size_t i = 0; i < res_count; ++i) { @@ -495,35 +522,55 @@ perr_t process_presults(presult_t *results, size_t res_count, switch (res.type) { case PRES_LABEL: { - struct LabelPair pair = {0}; - pair.label = res.label; - pair.addr = (*inst_count); - pair.label_size = strlen(res.label); - darr_append_bytes(&label_pairs, (byte *)&pair, sizeof(pair)); + label_t label = {.name = res.label, + .name_size = strlen(res.label), + .addr = (*inst_count) + 1}; + darr_append_bytes(&label_registry, (byte *)&label, sizeof(label)); break; } case PRES_RELATIVE_ADDRESS: { - s_word offset = res.relative_address; + s_word offset = res.address; if (offset < 0 && ((word)(-offset)) > *inst_count) { - free(label_pairs.data); + free(label_registry.data); return PERR_INVALID_RELATIVE_ADDRESS; } results[i].instruction.operand.as_word = ((s_word)*inst_count) + offset; (*inst_count)++; break; } + case PRES_GLOBAL_LABEL: { + global_start_defined = true; + start_label = res.label; + break; + } case PRES_LABEL_ADDRESS: case PRES_COMPLETE_RESULT: - default: { + default: (*inst_count)++; break; } - } } darr_t instr_darr = {0}; darr_init(&instr_darr, sizeof(**instructions)); + + if (global_start_defined) + { + label_t label = + search_labels((label_t *)label_registry.data, + label_registry.used / sizeof(label_t), start_label); + if (!label.name) + { + free(instr_darr.data); + free(label_registry.data); + return PERR_UNKNOWN_LABEL; + } + inst_t initial_jump = INST_JUMP_ABS(label.addr); + darr_append_bytes(&instr_darr, (byte *)&initial_jump, sizeof(initial_jump)); + (*inst_count)++; + } + for (size_t i = 0; i < res_count; ++i) { presult_t res = results[i]; @@ -531,36 +578,34 @@ perr_t process_presults(presult_t *results, size_t res_count, { case PRES_LABEL_ADDRESS: { inst_t inst = {0}; - for (size_t j = 0; j < (label_pairs.used / sizeof(struct LabelPair)); ++j) - { - struct LabelPair pair = ((struct LabelPair *)label_pairs.data)[j]; - if (pair.label_size == strlen(res.label) && - strncmp(pair.label, res.label, pair.label_size) == 0) - { - inst = res.instruction; - inst.operand = DWORD(pair.addr); - } - } + label_t label = + search_labels((label_t *)label_registry.data, + label_registry.used / sizeof(label_t), res.label); - if (inst.opcode == OP_NOOP) + if (!label.name) { free(instr_darr.data); - free(label_pairs.data); + free(label_registry.data); return PERR_UNKNOWN_LABEL; } + + inst.opcode = res.instruction.opcode; + inst.operand = DWORD(label.addr); darr_append_bytes(&instr_darr, (byte *)&inst, sizeof(inst)); break; } case PRES_RELATIVE_ADDRESS: - case PRES_COMPLETE_RESULT: + case PRES_COMPLETE_RESULT: { darr_append_bytes(&instr_darr, (byte *)&res.instruction, sizeof(res.instruction)); + } + case PRES_GLOBAL_LABEL: case PRES_LABEL: break; } } - free(label_pairs.data); + free(label_registry.data); *instructions = (inst_t *)instr_darr.data; return PERR_OK; } @@ -578,7 +623,8 @@ perr_t parse_stream(token_stream_t *stream, inst_t **ret, size_t *size) for (size_t i = 0; i < (presults.used / sizeof(presult_t)); ++i) { presult_t res = ((presult_t *)presults.data)[i]; - if (res.type == PRES_LABEL_ADDRESS || res.type == PRES_LABEL) + if (res.type == PRES_LABEL_ADDRESS || res.type == PRES_LABEL || + res.type == PRES_GLOBAL_LABEL) free(res.label); } free(presults.data); @@ -593,7 +639,8 @@ perr_t parse_stream(token_stream_t *stream, inst_t **ret, size_t *size) for (size_t i = 0; i < (presults.used / sizeof(presult_t)); ++i) { presult_t res = ((presult_t *)presults.data)[i]; - if (res.type == PRES_LABEL_ADDRESS || res.type == PRES_LABEL) + if (res.type == PRES_LABEL_ADDRESS || res.type == PRES_LABEL || + res.type == PRES_GLOBAL_LABEL) free(res.label); } free(presults.data); diff --git a/asm/parser.h b/asm/parser.h index 0a65310..b0091d2 100644 --- a/asm/parser.h +++ b/asm/parser.h @@ -25,9 +25,10 @@ typedef enum PERR_EXPECTED_UTYPE, PERR_EXPECTED_TYPE, PERR_EXPECTED_SYMBOL, + PERR_EXPECTED_LABEL, PERR_EXPECTED_OPERAND, - PERR_UNKNOWN_OPERATOR, PERR_INVALID_RELATIVE_ADDRESS, + PERR_UNKNOWN_OPERATOR, PERR_UNKNOWN_LABEL, } perr_t; @@ -37,16 +38,26 @@ typedef struct { inst_t instruction; char *label; - s_word relative_address; + s_word address; enum PResult_Type { PRES_LABEL = 0, PRES_LABEL_ADDRESS, + PRES_GLOBAL_LABEL, PRES_RELATIVE_ADDRESS, PRES_COMPLETE_RESULT, } type; } presult_t; +typedef struct +{ + char *name; + size_t name_size; + word addr; +} label_t; + +label_t search_labels(label_t *, size_t, char *); + perr_t parse_next(token_stream_t *, presult_t *); perr_t process_presults(presult_t *, size_t, inst_t **, size_t *); perr_t parse_stream(token_stream_t *, inst_t **, size_t *); |