summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBobby Bingham <koorogi@koorogi.info>2017-01-18 19:40:18 -0600
committerBobby Bingham <koorogi@koorogi.info>2017-01-18 19:40:18 -0600
commit6c6b91f9a6bc5ae203e99ac7abb3a70215488a6f (patch)
treea60ee21b204363128001cf323e5914745a630afd
parent1e0d0202e614f398f491624c84ae9a8309fa2f96 (diff)
nqasm: support unary operators in immediate expressions
-rw-r--r--lexer.l6
-rw-r--r--nqasm.c19
-rw-r--r--nqasm.h16
-rw-r--r--parser.y10
4 files changed, 45 insertions, 6 deletions
diff --git a/lexer.l b/lexer.l
index 053ac4e..324c3da 100644
--- a/lexer.l
+++ b/lexer.l
@@ -76,7 +76,11 @@ HEX [0-9a-f]
<args>\. { return T_DOT; }
<args>@ { return T_DEREF; }
-<args>[-+]?{DEC}+ { return intlit(yytext, 10, &yylval.lval); }
+<args>\+ { return T_OPERATOR_ADD; }
+<args>- { return T_OPERATOR_SUB; }
+<args>! { return T_OPERATOR_NOT; }
+<args>~ { return T_OPERATOR_INV; }
+<args>{DEC}+ { return intlit(yytext, 10, &yylval.lval); }
<args>0x{HEX}+ { return intlit(yytext+2, 16, &yylval.lval); }
<args>{SP}*,{SP}* { return T_COMMA; }
diff --git a/nqasm.c b/nqasm.c
index ee3010a..49b4ec6 100644
--- a/nqasm.c
+++ b/nqasm.c
@@ -56,12 +56,27 @@ void add_instruction(const struct instruction *inst)
addr += 2;
}
+struct argument *argdup(const struct argument *arg)
+{
+ struct argument *ret = malloc(sizeof *ret);
+ if (!ret) {
+ fprintf(stderr, "unable to allocate argument\n");
+ exit(1);
+ }
+ *ret = *arg;
+ return ret;
+}
+
static long eval_argument(const struct argument *arg, uint16_t pc)
{
struct label *l;
switch (arg->type) {
- case ARG_INTEGER: return arg->value;
- case ARG_PC: return pc;
+ case ARG_INTEGER: return arg->value;
+ case ARG_PC: return pc;
+ case ARG_UNARY_ADD: return eval_argument(arg->children[0], pc);
+ case ARG_UNARY_SUB: return -eval_argument(arg->children[0], pc);
+ case ARG_UNARY_NOT: return !eval_argument(arg->children[0], pc);
+ case ARG_UNARY_INV: return ~eval_argument(arg->children[0], pc);
case ARG_LABEL:
l = vector_search(&labels->v, &(struct label) { .name = arg->label }, cmp_label);
diff --git a/nqasm.h b/nqasm.h
index 0bc51f7..e5a7452 100644
--- a/nqasm.h
+++ b/nqasm.h
@@ -1,15 +1,23 @@
#ifndef NQ_NQASM_H
#define NQ_NQASM_H
-#define ARG_INTEGER 0
-#define ARG_LABEL 1
-#define ARG_PC 2
+enum {
+ ARG_INTEGER,
+ ARG_LABEL,
+ ARG_PC,
+
+ ARG_UNARY_ADD,
+ ARG_UNARY_SUB,
+ ARG_UNARY_NOT,
+ ARG_UNARY_INV,
+};
struct argument {
int type;
union {
long value;
char *label;
+ const struct argument *children[1];
};
};
@@ -25,5 +33,7 @@ struct instruction {
void add_instruction(const struct instruction *);
void add_label(const char *);
+struct argument *argdup(const struct argument *);
+
#endif
diff --git a/parser.y b/parser.y
index 2ec2264..cb1343f 100644
--- a/parser.y
+++ b/parser.y
@@ -16,6 +16,7 @@ void yyerror(const char *msg)
#define MKARGVALUE(v) (struct argument) { .type = ARG_INTEGER, .value = (v) }
#define MKARGLABEL(l) (struct argument) { .type = ARG_LABEL, .label = (l) }
#define MKARGTYPE(t) (struct argument) { .type = (t) }
+#define MKARGEXPR(op,c) (struct argument) { .type = (op), .children = c }
%}
@@ -84,6 +85,11 @@ void yyerror(const char *msg)
%token T_DOT "."
%token T_DEREF "@"
+%token T_OPERATOR_ADD "+"
+%token T_OPERATOR_SUB "-"
+%token T_OPERATOR_NOT "!"
+%token T_OPERATOR_INV "~"
+
%type <inst> inst
%type <arg> reg
%type <arg> regp
@@ -181,6 +187,10 @@ expr:
intlit { $$ = MKARGVALUE($1); }
| T_LABEL { $$ = MKARGLABEL($1); }
| "." { $$ = MKARGTYPE(ARG_PC); }
+ | "+" expr { $$ = MKARGEXPR(ARG_UNARY_ADD, { argdup(&$2) }); }
+ | "-" expr { $$ = MKARGEXPR(ARG_UNARY_SUB, { argdup(&$2) }); }
+ | "!" expr { $$ = MKARGEXPR(ARG_UNARY_NOT, { argdup(&$2) }); }
+ | "~" expr { $$ = MKARGEXPR(ARG_UNARY_INV, { argdup(&$2) }); }
;
intlit: T_INT