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_DUPE_LABELS] = "duplicate definitions for label",
[ED_SYM_NO_LABEL] = "undefined reference to label", [ED_SYM_NO_LABEL] = "undefined reference to label",
[ED_SYM_IS_REGISTER] = "labels cannot share names with registers", [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_LONG] = "opcode mnemonic is too long (2-4 characters)",
[ED_PS_OP_TOO_SHORT] = "opcode mnemonic is too short (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_DUPE_LABELS,
ED_SYM_NO_LABEL, ED_SYM_NO_LABEL,
ED_SYM_IS_REGISTER, ED_SYM_IS_REGISTER,
ED_SYM_IS_CONDITION,


ED_PS_OP_TOO_LONG, ED_PS_OP_TOO_LONG,
ED_PS_OP_TOO_SHORT, ED_PS_OP_TOO_SHORT,


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

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


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


/* /*
@@ -81,7 +82,7 @@ static ASMErrorDesc parse_inst_##mnemonic( \
if (!arg) \ if (!arg) \
INST_ERROR(TOO_FEW_ARGS) \ INST_ERROR(TOO_FEW_ARGS) \
ASMInstArg args[3]; \ ASMInstArg args[3]; \
size_t nargs; \
size_t nargs = 0; \
ASMErrorDesc err = parse_args(args, &nargs, arg, size); \ ASMErrorDesc err = parse_args(args, &nargs, arg, size); \
if (err) \ if (err) \
return err; \ return err; \
@@ -90,14 +91,13 @@ static ASMErrorDesc parse_inst_##mnemonic( \
if (nargs > hi) \ if (nargs > hi) \
INST_ERROR(TOO_MANY_ARGS) 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_REG_PREFIX(n) INST_PREFIX_(INST_REG(n))
#define INST_INDEX_PREFIX(n) INST_PREFIX_(INST_INDEX(n).reg) #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) ASMInstArg *arg, const char *str, size_t size, char **symbol)
{ {
// TODO // 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; return ED_PS_ARG_SYNTAX;
} }


@@ -190,6 +216,7 @@ static ASMErrorDesc parse_args(
if (i > start) { if (i > start) {
if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol))) if ((err = parse_arg(&args[*nargs], str + start, i - start, &symbol)))
return err; return err;
(*nargs)++;
} }
return ED_NONE; 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. 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(inc)
// HANDLE(add) // HANDLE(add)
// HANDLE(adc) // HANDLE(adc)
HANDLE(retn)


return NULL; return NULL;
} }

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

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


#define MAX_REGION_SIZE 32 #define MAX_REGION_SIZE 32


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

#define DIRECTIVE_PARSE_FUNC(name, type) \ #define DIRECTIVE_PARSE_FUNC(name, type) \
bool dparse_##name(type *result, const ASMLine *line, const char *directive) 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) if (size < 1 || size > 3)
return false; return false;


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


switch (size) { switch (size) {
case 1: 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 0x6166: return (*result = REG_AF), true;
case 0x6263: return (*result = REG_BC), true; case 0x6263: return (*result = REG_BC), true;
case 0x6465: return (*result = REG_DE), 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 0x6978: return (*result = REG_IX), true;
case 0x6979: return (*result = REG_IY), true; case 0x6979: return (*result = REG_IY), true;
case 0x7063: return (*result = REG_PC), 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]) { switch ((buf[0] << 16) + (buf[1] << 8) + buf[2]) {
case 0x616627: return (*result = REG_AF_), true; case 0x616627: return (*result = REG_AF_), true;
case 0x697868: return (*result = REG_IXH), 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 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; 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_uint32_t(uint32_t*, const char*, ssize_t);
bool parse_string(char**, size_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_bytes(uint8_t**, size_t*, const char*, ssize_t);

bool parse_register(ASMArgRegister*, 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_bool(bool*, const ASMLine*, const char*);
bool dparse_uint32_t(uint32_t*, 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. 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 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( static ErrorInfo* add_label_to_table(
ASMSymbolTable *symtable, const ASMLine *line, size_t offset, int8_t slot) 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)) if (parse_register(&reg, line->data, line->length - 1))
return error_info_create(line, ET_SYMBOL, ED_SYM_IS_REGISTER); 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); char *symbol = strndup(line->data, line->length - 1);
if (!symbol) if (!symbol)
OUT_OF_MEMORY() OUT_OF_MEMORY()


Loading…
Cancel
Save