summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Phillips <david@sighup.nz>2019-07-29 22:07:00 +1200
committerDavid Phillips <david@sighup.nz>2019-08-03 12:44:12 +1200
commit5544ad5c06bee5f562dddd055c571818bc0d0119 (patch)
tree2c92b433d206b0fb4c99f70452872a983c96a864
parent5a22735d1c265a0a000c77ec9b5bd74688a87370 (diff)
downloadtoy-cpu-assembler-5544ad5c06bee5f562dddd055c571818bc0d0119.tar.xz
Add test for asm-disasm-asm, fix bug with labels
This adds a support script for future expansion of an asm->disasm->asm series of tests, which will at minimum ensure some parity between the assembler and disassembler. Lower level tests to ensure correct behaviour rather than just symmetrical behaviour belong in another set of tests. This patch also fixes the assembler's behaviour around numeric labels. Many other assemblers support entirely numeric labels, and the output of the disassembler includes them. The assembler has been adjusted to lex a probably-numeric as a label if it is at the start of the line. Otherwise, old label behavour and old numeric behaviour is left in place.
-rw-r--r--lex.c21
-rw-r--r--output.c2
-rw-r--r--test/Makefile2
-rw-r--r--test/full-pipeline/001-nop.test1
-rwxr-xr-xtest/full-pipeline/run-full-pipeline.sh75
5 files changed, 94 insertions, 7 deletions
diff --git a/lex.c b/lex.c
index 7294fbb..7384ca4 100644
--- a/lex.c
+++ b/lex.c
@@ -63,6 +63,13 @@ static int add_token(struct token t) {
return 0;
}
+static struct token last_token(void) {
+ if (tokens_count)
+ return tokens[tokens_count - 1];
+ else
+ return (struct token){ .type = TOKEN_EOL };
+}
+
static int lex_comma(struct token *t) {
if (expect(','))
return 1;
@@ -251,11 +258,6 @@ static int lex_misc(struct token *t) {
int i = 0;
int j = 0;
- if (!isalpha(buffer[column])) {
- emit("Error: '%c' cannot start an identifier\n", buffer[column]);
- return 1;
- }
-
for (i = column; isalnum(buffer[i]); i++) {
;
}
@@ -278,6 +280,12 @@ static int lex_misc(struct token *t) {
/* skip over colon, but don't have included it in the name */
if (t->type == TOKEN_LABEL) {
column++;
+ } else {
+ /* non-labels must start with an alpha */
+ if (!isalpha(t->s_val[0])) {
+ emit("Error: '%c' cannot start an identifier\n", t->s_val[0]);
+ return 1;
+ }
}
return 0;
}
@@ -356,7 +364,8 @@ int lex_line(void) {
break;
/* FIXME add support for expressions like `addi $0, $0, (1+2*3) */
default:
- if (isdigit(buffer[column])) {
+ /* allow numerical to start label only when at start of line */
+ if (isdigit(buffer[column]) && last_token().type != TOKEN_EOL) {
ret = lex_num(&tok);
} else {
ret = lex_misc(&tok);
diff --git a/output.c b/output.c
index 2afb5fe..047040a 100644
--- a/output.c
+++ b/output.c
@@ -165,7 +165,7 @@ int output_single(FILE *f, struct label *labels, size_t labels_count, struct ins
}
if (len == 2) {
-//#define RAW
+#define RAW
#ifdef RAW
fputc(0xFF & (i >> 24), f);
fputc(0xFF & (i >> 16), f);
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..c2407c7
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,2 @@
+test:
+ ./full-pipeline/run-full-pipeline.sh
diff --git a/test/full-pipeline/001-nop.test b/test/full-pipeline/001-nop.test
new file mode 100644
index 0000000..c27745a
--- /dev/null
+++ b/test/full-pipeline/001-nop.test
@@ -0,0 +1 @@
+nop
diff --git a/test/full-pipeline/run-full-pipeline.sh b/test/full-pipeline/run-full-pipeline.sh
new file mode 100755
index 0000000..34d4ff0
--- /dev/null
+++ b/test/full-pipeline/run-full-pipeline.sh
@@ -0,0 +1,75 @@
+#!/bin/bash -e
+
+#
+# Script for running all of the automated which will go from source to binary,
+# to source to binary, and compare the two binaries.
+# These tests won't find symmetrical errors (e.g. incorrectly translating 'add'
+# into the wrong opcode, and that same opcode back to 'add'), but provide some
+# level of confidence that the disassembler and assembler at least have parity.
+# Checking lower level things is the job of other tests.
+#
+
+fail() {
+ echo -e '[\e[1;31mFAIL\e[0m] '"$1:" "$2"
+}
+
+pass() {
+ echo -e '[\e[0;32mPASS\e[0m] '"$1"
+}
+
+clean() {
+ echo "Removing work dir $WORK"
+ rm -r "$WORK"
+}
+
+trap clean EXIT
+
+check_expected()
+{
+ [ -z "$1" ] && echo WARN: check_expected called with no argument
+ if [ -f "$1.expected" ] ; then
+ if ! diff "$1.expected" "$1.tmp" >/dev/null; then
+ fail "$1 didn't match expected"
+ fi
+ fi
+}
+
+WORK=$(mktemp -d)
+pushd $(dirname "$0") >/dev/null
+export ASM="$PWD/../../assembler"
+export DISASM="$PWD/../../disassembler"
+has_failure=0
+
+for first_stage_asm in *.test ; do
+ first_stage_bin="$WORK/first_stage.bin"
+ second_stage_asm="$WORK/second_stage.asm"
+ second_stage_bin="$WORK/second_stage.bin"
+
+ # Assemble test code
+ if ! "$ASM" "$first_stage_asm" "$first_stage_bin" ; then
+ fail "$first_stage_asm" "first stage assembly failed"
+ continue
+ fi
+
+ # Disassemble test code and re-assemble that disassembly
+ if ! "$DISASM" "$first_stage_bin" > "$second_stage_asm" ; then
+ fail "$first_stage_asm" "first stage disassembly failed"
+ continue
+ fi
+ if ! "$ASM" "$second_stage_asm" "$second_stage_bin" ; then
+ fail "$first_stage_asm" "second stage assembly failed"
+ continue
+ fi
+
+ # first stage bin and second stage identical for test pass
+ if diff "$first_stage_bin" "$second_stage_bin"; then
+ pass "$first_stage_asm"
+ else
+ fail "$first_stage_asm" "binary mismatch"
+ has_failure=1
+ fi
+
+done
+popd >/dev/null
+
+exit "$has_failure"