Browse Source

Parse condition codes.

master
Ben Kurtovic 9 years ago
parent
commit
8bbca15e47
6 changed files with 93 additions and 16 deletions
  1. +1
    -0
      src/assembler/errors.c
  2. +1
    -0
      src/assembler/errors.h
  3. +44
    -10
      src/assembler/instructions.c
  4. +40
    -5
      src/assembler/parse_util.c
  5. +2
    -0
      src/assembler/parse_util.h
  6. +5
    -1
      src/assembler/tokenizer.c

+ 1
- 0
src/assembler/errors.c View File

@@ -43,6 +43,7 @@ static const char *error_descs[] = {
[ED_SYM_DUPE_LABELS] = "duplicate definitions for label",
[ED_SYM_NO_LABEL] = "undefined reference to label",
[ED_SYM_IS_REGISTER] = "labels cannot share names with registers",
[ED_SYM_IS_CONDITION] = "labels cannot share names with condition codes",

[ED_PS_OP_TOO_LONG] = "opcode mnemonic is too long (2-4 characters)",
[ED_PS_OP_TOO_SHORT] = "opcode mnemonic is too short (2-4 characters)",


+ 1
- 0
src/assembler/errors.h View File

@@ -42,6 +42,7 @@ typedef enum {
ED_SYM_DUPE_LABELS,
ED_SYM_NO_LABEL,
ED_SYM_IS_REGISTER,
ED_SYM_IS_CONDITION,

ED_PS_OP_TOO_LONG,
ED_PS_OP_TOO_SHORT,


+ 44
- 10
src/assembler/instructions.c View File

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

#include "instructions.h"
#include "inst_args.h"
#include "parse_util.h"
#include "../logging.h"

/*
@@ -81,7 +82,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \
if (!arg) \
INST_ERROR(TOO_FEW_ARGS) \
ASMInstArg args[3]; \
size_t nargs; \
size_t nargs = 0; \
ASMErrorDesc err = parse_args(args, &nargs, arg, size); \
if (err) \
return err; \
@@ -90,14 +91,13 @@ static ASMErrorDesc parse_inst_##mnemonic( \
if (nargs > hi) \
INST_ERROR(TOO_MANY_ARGS)

#define INST_ARG(n) (args[n])
#define INST_TYPE(n) INST_ARG(n).type
#define INST_REG(n) INST_ARG(n).data.reg
#define INST_IMM(n) INST_ARG(n).data.imm
#define INST_INDIRECT(n) INST_ARG(n).data.indirect
#define INST_INDEX(n) INST_ARG(n).data.index
#define INST_LABEL(n) INST_ARG(n).data.label
#define INST_COND(n) INST_ARG(n).data.cond
#define INST_TYPE(n) args[n].type
#define INST_REG(n) args[n].data.reg
#define INST_IMM(n) args[n].data.imm
#define INST_INDIRECT(n) args[n].data.indirect
#define INST_INDEX(n) args[n].data.index
#define INST_LABEL(n) args[n].data.label
#define INST_COND(n) args[n].data.cond

#define INST_REG_PREFIX(n) INST_PREFIX_(INST_REG(n))
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg)
@@ -148,7 +148,33 @@ static ASMErrorDesc parse_arg(
ASMInstArg *arg, const char *str, size_t size, char **symbol)
{
// TODO
DEBUG("parse_arg(): -->%.*s<--", (int) size, str)

// AT_REGISTER
// AT_IMMEDIATE
// AT_INDIRECT
// AT_INDEXED
// AT_LABEL
// AT_CONDITION

// ASMArgRegister reg;
// ASMArgImmediate imm;
// ASMArgIndirect indirect;
// ASMArgIndexed index;
// ASMArgLabel label;
// ASMArgCondition cond;

DEBUG("parse_arg(): -->%.*s<-- %zu", (int) size, str, size)

if (parse_register(&arg->data.reg, str, size)) {
arg->type = AT_REGISTER;
return ED_NONE;
}

if (parse_condition(&arg->data.cond, str, size)) {
arg->type = AT_CONDITION;
return ED_NONE;
}

return ED_PS_ARG_SYNTAX;
}

@@ -190,6 +216,7 @@ static ASMErrorDesc parse_args(
if (i > start) {
if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol)))
return err;
(*nargs)++;
}
return ED_NONE;
}
@@ -254,6 +281,12 @@ INST_FUNC(adc)
}
*/

INST_FUNC(retn)
{
INST_TAKES_NO_ARGS
INST_RETURN(2, 0xED, 0x45)
}

/*
Return the relevant ASMInstParser function for a given mnemonic.

@@ -271,6 +304,7 @@ ASMInstParser get_inst_parser(char mstr[MAX_MNEMONIC_SIZE])
HANDLE(inc)
// HANDLE(add)
// HANDLE(adc)
HANDLE(retn)

return NULL;
}

+ 40
- 5
src/assembler/parse_util.c View File

@@ -12,6 +12,8 @@

#define MAX_REGION_SIZE 32

#define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c)

#define DIRECTIVE_PARSE_FUNC(name, type) \
bool dparse_##name(type *result, const ASMLine *line, const char *directive)

@@ -180,14 +182,12 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size)
if (size < 1 || size > 3)
return false;

#define LCASE(c) ((c >= 'A' && c <= 'Z') ? (c + 'a' - 'A') : c)
char buf[3] = {'\0'};
switch (size) {
case 3: buf[2] = LCASE(arg[2]);
case 2: buf[1] = LCASE(arg[1]);
case 1: buf[0] = LCASE(arg[0]);
}
#undef LCASE

switch (size) {
case 1:
@@ -209,7 +209,7 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size)
case 0x6166: return (*result = REG_AF), true;
case 0x6263: return (*result = REG_BC), true;
case 0x6465: return (*result = REG_DE), true;
case 0x686c: return (*result = REG_HL), true;
case 0x686C: return (*result = REG_HL), true;
case 0x6978: return (*result = REG_IX), true;
case 0x6979: return (*result = REG_IY), true;
case 0x7063: return (*result = REG_PC), true;
@@ -220,9 +220,44 @@ bool parse_register(ASMArgRegister *result, const char *arg, ssize_t size)
switch ((buf[0] << 16) + (buf[1] << 8) + buf[2]) {
case 0x616627: return (*result = REG_AF_), true;
case 0x697868: return (*result = REG_IXH), true;
case 0x69786c: return (*result = REG_IXL), true;
case 0x69786C: return (*result = REG_IXL), true;
case 0x697968: return (*result = REG_IYH), true;
case 0x69796c: return (*result = REG_IYL), true;
case 0x69796C: return (*result = REG_IYL), true;
}
return false;
}
return false;
}

/*
Read in a register argument and store it in *result.
*/
bool parse_condition(ASMArgCondition *result, const char *arg, ssize_t size)
{
if (size < 1 || size > 2)
return false;

char buf[2] = {'\0'};
switch (size) {
case 2: buf[1] = LCASE(arg[1]);
case 1: buf[0] = LCASE(arg[0]);
}

switch (size) {
case 1:
switch (buf[0]) {
case 'n': return (*result = COND_N), true;
case 'c': return (*result = COND_C), true;
case 'p': return (*result = COND_P), true;
case 'm': return (*result = COND_M), true;
}
return false;
case 2:
switch ((buf[0] << 8) + buf[1]) {
case 0x6E7A: return (*result = COND_NZ), true;
case 0x6E63: return (*result = COND_NC), true;
case 0x706F: return (*result = COND_PO), true;
case 0x7065: return (*result = COND_PE), true;
}
return false;
}


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

@@ -17,7 +17,9 @@ bool parse_bool(bool*, const char*, ssize_t);
bool parse_uint32_t(uint32_t*, const char*, ssize_t);
bool parse_string(char**, size_t*, const char*, ssize_t);
bool parse_bytes(uint8_t**, size_t*, const char*, ssize_t);

bool parse_register(ASMArgRegister*, const char*, ssize_t);
bool parse_condition(ASMArgCondition*, const char*, ssize_t);

bool dparse_bool(bool*, const ASMLine*, const char*);
bool dparse_uint32_t(uint32_t*, const ASMLine*, const char*);


+ 5
- 1
src/assembler/tokenizer.c View File

@@ -57,7 +57,7 @@ static inline int8_t default_bank_slot(uint8_t bank)
Add a given line, representing a label, to the symbol table.

Return NULL on success and an ErrorInfo object on failure (e.g. in the case
of duplicate labels).
of duplicate labels, or labels sharing names with registers/conditions).
*/
static ErrorInfo* add_label_to_table(
ASMSymbolTable *symtable, const ASMLine *line, size_t offset, int8_t slot)
@@ -66,6 +66,10 @@ static ErrorInfo* add_label_to_table(
if (parse_register(&reg, line->data, line->length - 1))
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_REGISTER);

ASMArgCondition cond;
if (parse_condition(&cond, line->data, line->length - 1))
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_CONDITION);

char *symbol = strndup(line->data, line->length - 1);
if (!symbol)
OUT_OF_MEMORY()


Loading…
Cancel
Save