summaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c68
1 files changed, 54 insertions, 14 deletions
diff --git a/main.c b/main.c
index 2471e96..5277aad 100644
--- a/main.c
+++ b/main.c
@@ -69,6 +69,8 @@
#define OK 1
#define CONTINUE 2
+#define BCC_S_MAX_BACKWARDS 126
+
enum token_type {
TT_NONE = 0,
TT_NEWLINE,
@@ -412,8 +414,8 @@ struct instruction {
struct directive {
enum directive_type type;
- size_t name_token; /// Directive self first token
- size_t first_token, num_tokens; /// Directive arguments tokens span
+ size_t name_token; ///< Directive self first token
+ size_t first_token, num_tokens; ///< Directive arguments tokens span
};
struct stmt {
@@ -425,6 +427,7 @@ struct stmt {
size_t label_token;
size_t first_token, num_tokens; // Statement tokens span, may be NULL
size_t comment_token;
+ uint32_t addr;
};
struct symbol {
@@ -462,15 +465,15 @@ struct token_recognition {
struct {
enum reg_type reg;
uint8_t reg_num;
- }; // For RTT_REG
- int32_t number; // For TT_ID
- size_t symbol_id; // For TT_ID and TT_DOT_ID, see (struct pars).symtab
+ }; ///< For RTT_REG
+ int32_t number; ///< For TT_ID
+ size_t symbol_id; ///< For TT_ID and TT_DOT_ID, see (struct pars).symtab
};
};
struct sym {
size_t stmt_id;
- size_t addr;
+ uint32_t addr;
};
struct pars {
@@ -478,7 +481,10 @@ struct pars {
// State
size_t cur_tok_id;
enum pars_error error;
- bool in_sat; ///< Indicates whether inside .def ... .endef block or not
+ /*!
+ * SAT stands for Symbol Attribute Table
+ */
+ bool in_sat; ///< Indicates whether inside `.def ... .endef` block or not
// Statement table
FILE *stmttab_stream;
struct stmt *stmttab;
@@ -1713,7 +1719,7 @@ static size_t get_instruction_size(const struct instruction *const instr)
}
static void pars_put_stmt(
- struct pars *const self, const struct stmt *const stmt)
+ struct pars *const self, struct stmt *const stmt)
{
if (stmt->label_token) {
// fflush is necessary to update stmttab_size variable
@@ -1727,6 +1733,7 @@ static void pars_put_stmt(
(void) res;
}
if (stmt->type == ST_INSTRUCTION) {
+ stmt->addr = self->addr_cursor;
self->addr_cursor += get_instruction_size(&stmt->instruction);
}
fwrite_stmt(stmt, self->stmttab_stream);
@@ -2084,7 +2091,7 @@ static int pars_finish_directive(
return ret;
}
const size_t first_token = label_id ? label_id : directive.name_token;
- const struct stmt stmt = {
+ struct stmt stmt = {
.type = ST_DIRECTIVE,
.directive = directive,
.label_token = label_id,
@@ -2734,7 +2741,7 @@ static int pars_yield_instruction(
break;
}
const size_t first_token_id = label_id ? label_id : mnemonic_id;
- const struct stmt stmt = {
+ struct stmt stmt = {
.type = ST_INSTRUCTION,
.instruction = {
.mnemonic = mnemonic,
@@ -3164,10 +3171,43 @@ static enum opsize assem_resolve_bcc(
const size_t stmt_number)
{
const struct pars *const pars = self->pars;
- (void) pars;
- (void) stmt_number;
- // TODO impl real resolving
- return OPSIZE_S;
+ const struct stmt *const stmt = pars->stmttab + stmt_number;
+ const struct instruction *const instr = &stmt->instruction;
+ const struct arg *const arg = &instr->arg1;
+ // XXX I'm not sure what else it can be, so let's catch it with an assert
+ assert(arg->type == ARG_ADDR_UNSPEC);
+ // Usually it is just a label - a single token
+ // TODO Impl support of expressions for real
+ assert(arg->expr.num_tokens);
+ const struct token *const target_token = pars->lex->tokbuf + arg->expr.first_token;
+ assert(target_token->type == TT_DOT_ID || target_token->type == TT_ID);
+ bool found = false;
+ uint32_t found_addr = 0;
+ for (size_t i = 0; i < pars->symtab_size; i++) {
+ const struct sym *const sym = pars->symtab + i;
+ if (sym->addr >= stmt->addr) {
+ // Current Bcc statement address reached or surpassed. And we are
+ // not interested in it if it is located either somewhere after
+ // current Bcc statement or in another translation unit.
+ break;
+ }
+ const struct stmt *const target = pars->stmttab + sym->stmt_id;
+ const struct token *const label_token = pars->lex->tokbuf + target->label_token;
+ const bool matches = 0 == memcmp(
+ pars->lex->input + label_token->offset,
+ pars->lex->input + target_token->offset,
+ target_token->length);
+ if (matches) {
+ found = true;
+ found_addr = sym->addr;
+ }
+ }
+ if (found && ((stmt->addr + 2 - found_addr) <= BCC_S_MAX_BACKWARDS)) {
+ return OPSIZE_S;
+ }
+ // Label is not found, therefore current Bcc size must be as wide as
+ // possible (word). This is original behavior of Sierra's ASM68.EXE.
+ return OPSIZE_W;
}
static struct res { uint32_t value; bool ok; } assem_find_symbol(