diff options
author | David Phillips <david@sighup.nz> | 2019-07-29 22:07:00 +1200 |
---|---|---|
committer | David Phillips <david@sighup.nz> | 2019-08-03 12:44:12 +1200 |
commit | 5544ad5c06bee5f562dddd055c571818bc0d0119 (patch) | |
tree | 2c92b433d206b0fb4c99f70452872a983c96a864 | |
parent | 5a22735d1c265a0a000c77ec9b5bd74688a87370 (diff) | |
download | toy-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.c | 21 | ||||
-rw-r--r-- | output.c | 2 | ||||
-rw-r--r-- | test/Makefile | 2 | ||||
-rw-r--r-- | test/full-pipeline/001-nop.test | 1 | ||||
-rwxr-xr-x | test/full-pipeline/run-full-pipeline.sh | 75 |
5 files changed, 94 insertions, 7 deletions
@@ -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); @@ -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" |