summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lexer.l1
-rw-r--r--nqasm.c60
-rw-r--r--nqasm.h7
-rw-r--r--parser.y64
-rw-r--r--vector.c10
-rw-r--r--vector.h2
6 files changed, 100 insertions, 44 deletions
diff --git a/lexer.l b/lexer.l
index 28aa7fe..7d44adf 100644
--- a/lexer.l
+++ b/lexer.l
@@ -79,6 +79,7 @@ HEX [0-9a-f]
<args>[-+]?{DEC}+ { return intlit(yytext, 10, &yylval.lval); }
<args>0x{HEX}+ { return intlit(yytext+2, 16, &yylval.lval); }
<args>{SP}*,{SP}* { return T_COMMA; }
+<args>{LABEL} { SETSTR(yytext); return T_LABEL; }
{SP}*{COMMENT}?\n { BEGIN(INITIAL); return T_EOL; }
{SP}*{COMMENT} { BEGIN(INITIAL); return T_EOL; }
diff --git a/nqasm.c b/nqasm.c
index 738f815..0b0bbd8 100644
--- a/nqasm.c
+++ b/nqasm.c
@@ -1,3 +1,4 @@
+#include <assert.h>
#include <stdint.h>
#include <stdio.h>
@@ -15,6 +16,12 @@ struct label {
uint16_t addr;
+static int cmp_label(const void *a, const void *b)
+{
+ const struct label *la = a, *lb = b;
+ return strcmp(la->name, lb->name);
+}
+
#define DEFINE_VECTOR(name, arraytype, arrayname, initsize) \
static struct name { \
struct vector v; \
@@ -49,7 +56,25 @@ void add_instruction(const struct instruction *inst)
addr += 2;
}
-static void assemble_instruction(const struct instruction *inst)
+static long eval_argument(const struct argument *arg)
+{
+ struct label *l;
+ switch (arg->type) {
+ case ARG_INTEGER:
+ return arg->value;
+
+ case ARG_LABEL:
+ l = vector_search(&labels->v, &(struct label) { .name = arg->label }, cmp_label);
+ if (l) return l->addr;
+ fprintf(stderr, "unknown label '%s'\n", arg->label);
+ exit(1);
+
+ default:
+ assert(0);
+ }
+}
+
+static void assemble_instruction(const struct instruction *inst, uint16_t pc)
{
const struct mnemonic *mnem = &mnemonics[inst->mnem];
uint16_t bits = mnem->bits;
@@ -57,7 +82,34 @@ static void assemble_instruction(const struct instruction *inst)
const struct operand *ops = mnem->operands;
const struct argument *args = inst->args.args;
for (int i = 0; i < 3 && ops[i].type; i++) {
- bits |= args[i].value << ops[i].shift;
+ long value = eval_argument(args + i);
+
+ switch (ops[i].type) {
+ case REG:
+ case REGPTR:
+ if (0 > value || value >= 8) {
+ fprintf(stderr, "invalid register\n");
+ exit(1);
+ }
+ break;
+ case IMM:
+ if (-0x80 > value || value > 0xff) {
+ fprintf(stderr, "immediate operand out of range\n");
+ exit(1);
+ }
+ break;
+ case PCOFF:
+ value -= pc;
+ if (-0x80 > value || value > 0x7f) {
+ fprintf(stderr, "pc offset operand out of range\n");
+ exit(1);
+ }
+ break;
+ default:
+ assert(0);
+ }
+
+ bits |= (value & 255) << ops[i].shift;
}
printf("%04x\n", bits);
@@ -84,8 +136,10 @@ int main(int argc, char **argv)
yyparse();
+ vector_sort(&labels->v, cmp_label);
+
for (size_t i = 0; i < instrs->v.count; i++) {
- assemble_instruction(instrs->i + i);
+ assemble_instruction(instrs->i + i, 2 * i);
}
return 0;
diff --git a/nqasm.h b/nqasm.h
index 232c41b..f2e036d 100644
--- a/nqasm.h
+++ b/nqasm.h
@@ -1,9 +1,14 @@
#ifndef NQ_NQASM_H
#define NQ_NQASM_H
+#define ARG_INTEGER 0
+#define ARG_LABEL 1
+
struct argument {
+ int type;
union {
- int value;
+ long value;
+ char *label;
};
};
diff --git a/parser.y b/parser.y
index 1f4f5bd..e6cb0b1 100644
--- a/parser.y
+++ b/parser.y
@@ -13,7 +13,8 @@ void yyerror(const char *msg)
#define INSTRUCTION_ARGS(m,a) (struct instruction) { MNEM_ ## m, a }
#define INSTRUCTION(m) (struct instruction) { MNEM_ ## m }
#define MKARGS(...) (struct arguments) { { __VA_ARGS__ } }
-#define MKARGVALUE(v) (struct argument) { .value = (v) }
+#define MKARGVALUE(v) (struct argument) { .type = ARG_INTEGER, .value = (v) }
+#define MKARGLABEL(l) (struct argument) { .type = ARG_LABEL, .label = (l) }
%}
@@ -84,16 +85,14 @@ void yyerror(const char *msg)
%token T_COLON ":"
%type <inst> inst
-%type <arg> imm
-%type <arg> pcoff
+%type <arg> expr
%type <args> a_reg2
%type <args> a_reg3
%type <args> a_regp
%type <args> a_regp_reg
%type <args> a_reg_regp
-%type <args> a_reg_imm
-%type <args> a_reg_pcoff
-%type <args> a_pcoff
+%type <args> a_reg_expr
+%type <args> a_expr
%type <lval> intlit
%%
@@ -136,17 +135,17 @@ inst:
| T_LD_BL a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BL, $2); }
| T_LD_BH a_reg_regp { $$ = INSTRUCTION_ARGS(LD_BH, $2); }
| T_LD_W a_reg_regp { $$ = INSTRUCTION_ARGS(LD_W, $2); }
- | T_LDI_BL a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BL, $2); }
- | T_LDI_BH a_reg_imm { $$ = INSTRUCTION_ARGS(LDI_BH, $2); }
- | T_BEQ a_pcoff { $$ = INSTRUCTION_ARGS(BEQ, $2); }
- | T_BNE a_pcoff { $$ = INSTRUCTION_ARGS(BNE, $2); }
- | T_BGT a_pcoff { $$ = INSTRUCTION_ARGS(BGT, $2); }
- | T_BGE a_pcoff { $$ = INSTRUCTION_ARGS(BGE, $2); }
- | T_BLT a_pcoff { $$ = INSTRUCTION_ARGS(BLT, $2); }
- | T_BLE a_pcoff { $$ = INSTRUCTION_ARGS(BLE, $2); }
- | T_BRA a_pcoff { $$ = INSTRUCTION_ARGS(BRA, $2); }
+ | T_LDI_BL a_reg_expr { $$ = INSTRUCTION_ARGS(LDI_BL, $2); }
+ | T_LDI_BH a_reg_expr { $$ = INSTRUCTION_ARGS(LDI_BH, $2); }
+ | T_BEQ a_expr { $$ = INSTRUCTION_ARGS(BEQ, $2); }
+ | T_BNE a_expr { $$ = INSTRUCTION_ARGS(BNE, $2); }
+ | T_BGT a_expr { $$ = INSTRUCTION_ARGS(BGT, $2); }
+ | T_BGE a_expr { $$ = INSTRUCTION_ARGS(BGE, $2); }
+ | T_BLT a_expr { $$ = INSTRUCTION_ARGS(BLT, $2); }
+ | T_BLE a_expr { $$ = INSTRUCTION_ARGS(BLE, $2); }
+ | T_BRA a_expr { $$ = INSTRUCTION_ARGS(BRA, $2); }
| T_JMP a_regp { $$ = INSTRUCTION_ARGS(JMP, $2); }
- | T_ADDPC a_reg_pcoff { $$ = INSTRUCTION_ARGS(ADDPC, $2); }
+ | T_ADDPC a_reg_expr { $$ = INSTRUCTION_ARGS(ADDPC, $2); }
| T_NOP { $$ = INSTRUCTION(NOP); }
;
@@ -160,30 +159,15 @@ a_regp_reg:
T_SPACE T_REGPTR "," T_REG { $$ = MKARGS($2, $4); }
a_reg_regp:
T_SPACE T_REG "," T_REGPTR { $$ = MKARGS($2, $4); }
-a_reg_imm:
- T_SPACE T_REG "," imm { $$ = MKARGS($2, $4); }
-a_reg_pcoff:
- T_SPACE T_REG "," pcoff { $$ = MKARGS($2, $4); }
-a_pcoff:
- T_SPACE pcoff { $$ = MKARGS($2); }
-
-pcoff: intlit {
- if (-0x80 > $1 || $1 > 0x7f) {
- yyerror("pc offset operand out of range");
- YYERROR;
- } else {
- $$ = MKARGVALUE((uint8_t) $1);
- }
- }
-
-imm: intlit {
- if (-0x80 > $1 || $1 > 0xff) {
- yyerror("immediate operand out of range");
- YYERROR;
- } else {
- $$ = MKARGVALUE((uint8_t) $1);
- }
- }
+a_reg_expr:
+ T_SPACE T_REG "," expr { $$ = MKARGS($2, $4); }
+a_expr:
+ T_SPACE expr { $$ = MKARGS($2); }
+
+expr:
+ intlit { $$ = MKARGVALUE($1); }
+ | T_LABEL { $$ = MKARGLABEL($1); }
+ ;
intlit: T_INT
| T_BADINT {
diff --git a/vector.c b/vector.c
index 57f62d7..8ff637c 100644
--- a/vector.c
+++ b/vector.c
@@ -35,3 +35,13 @@ void *vector_append(struct vector **vp)
return (char*)v + v->arrayoff + v->count++ * v->elemsize;
}
+void vector_sort(struct vector *v, int (*cmp)(const void *, const void *))
+{
+ qsort((char*)v + v->arrayoff, v->count, v->elemsize, cmp);
+}
+
+void *vector_search(struct vector *v, const void *key, int (*cmp)(const void *, const void *))
+{
+ return bsearch(key, (char*)v + v->arrayoff, v->count, v->elemsize, cmp);
+}
+
diff --git a/vector.h b/vector.h
index fb32da7..6fba081 100644
--- a/vector.h
+++ b/vector.h
@@ -9,5 +9,7 @@ struct vector {
void *vector_init(size_t alloc, size_t elemsize, size_t arrayoff);
void *vector_append(struct vector **vp);
+void vector_sort(struct vector *v, int (*cmp)(const void *, const void *));
+void *vector_search(struct vector *v, const void *key, int (*cmp)(const void *, const void *));
#endif