diff --git a/.gitignore b/.gitignore index ed93eb3..ab4e333 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ cache vgcore.* libnoja.a -noja \ No newline at end of file +noja +*.gcov \ No newline at end of file diff --git a/build_tests.sh b/build_tests.sh index 7e83d90..ae0ef57 100755 --- a/build_tests.sh +++ b/build_tests.sh @@ -1,13 +1,12 @@ FILES="tests/assembler_test.c \ - src/assembler/assembler.c \ - src/common/executable.c \ - src/utils/error.c \ - src/utils/source.c \ - src/utils/bpalloc.c \ - src/utils/promise.c \ - src/utils/labellist.c \ - src/utils/bucketlist.c" - -gcc $FILES -o build/assembler_test_cov -Wall -Wextra -g --coverage -gcc $FILES -o build/assembler_test -Wall -Wextra -g + src/noja/assembler/assembler.c \ + src/noja/common/executable.c \ + src/noja/utils/error.c \ + src/noja/utils/source.c \ + src/noja/utils/bpalloc.c \ + src/noja/utils/promise.c \ + src/noja/utils/labellist.c \ + src/noja/utils/bucketlist.c" +gcc $FILES -o assembler_test_cov -Wall -Wextra -g --coverage +gcc $FILES -o assembler_test -Wall -Wextra -g diff --git a/examples/bubble_sort.njbc b/examples/bubble_sort.njbc new file mode 100644 index 0000000..f0009e8 --- /dev/null +++ b/examples/bubble_sort.njbc @@ -0,0 +1,171 @@ + PUSHFUN copy, 1; + ASS "copy"; + POP 1; + JUMP copy_end; + +copy: + ASS "L"; + POP 1; + PUSHLST 0; + ASS "L2"; + POP 1; + PUSHINT 0; + ASS "i"; + POP 1; + PUSHVAR "i"; + PUSHVAR "L"; + PUSHVAR "count"; + CALL 1, 1; + LSS; + JUMPIFNOTANDPOP 31; + PUSHVAR "L"; + PUSHVAR "i"; + SELECT; + PUSHVAR "L2"; + PUSHVAR "i"; + INSERT2; + POP 1; + PUSHVAR "i"; + PUSHINT 1; + ADD; + ASS "i"; + POP 1; + JUMP 12; + PUSHVAR "L2"; + RETURN 1; + RETURN 0; + +copy_end: + PUSHFUN bubble_sort, 2; + ASS "bubble_sort"; + POP 1; + JUMP bubble_sort_end; + +bubble_sort: + ASS "less"; + POP 1; + ASS "L"; + POP 1; + PUSHVAR "less"; + PUSHNNE; + EQL; + JUMPIFNOTANDPOP default_less_cb_end; + PUSHFUN 50, 2; + ASS "less"; + POP 1; + JUMP default_less_cb_end; + +default_less_cb: + ASS "b"; + POP 1; + ASS "a"; + POP 1; + PUSHVAR "a"; + PUSHVAR "b"; + LSS; + RETURN 1; + RETURN 0; + +default_less_cb_end: + PUSHVAR "L"; + PUSHVAR "copy"; + CALL 1, 1; + ASS "L"; + POP 1; + +outer_loop_start: + PUSHFLS; + ASS "swapped"; + POP 1; + PUSHINT 0; + ASS "i"; + POP 1; + +inner_loop_start: + PUSHVAR "i"; + PUSHVAR "L"; + PUSHVAR "count"; + CALL 1, 1; + PUSHINT 1; + SUB; + LSS; + PUSHVAR "swapped"; + NOT; + AND; + JUMPIFNOTANDPOP outer_loop_end; + PUSHVAR "L"; + PUSHVAR "i"; + SELECT; + PUSHVAR "L"; + PUSHVAR "i"; + PUSHINT 1; + ADD; + SELECT; + PUSHVAR "less"; + CALL 2, 1; + JUMPIFNOTANDPOP if_branch_end; + PUSHTRU; + ASS "swapped"; + POP 1; + PUSHVAR "L"; + PUSHVAR "i"; + PUSHINT 1; + ADD; + SELECT; + ASS "tmp"; + POP 1; + PUSHVAR "L"; + PUSHVAR "i"; + SELECT; + PUSHVAR "L"; + PUSHVAR "i"; + PUSHINT 1; + ADD; + INSERT2; + POP 1; + PUSHVAR "tmp"; + PUSHVAR "L"; + PUSHVAR "i"; + INSERT2; + POP 1; + +if_branch_end: + PUSHVAR "i"; + PUSHINT 1; + ADD; + ASS "i"; + POP 1; + JUMP inner_loop_start; + +outer_loop_end: + PUSHVAR "swapped"; + JUMPIFANDPOP outer_loop_start; + PUSHVAR "L"; + RETURN 1; + RETURN 0; + +bubble_sort_end: + PUSHLST 5; + PUSHINT 0; + PUSHINT 3; + INSERT; + PUSHINT 1; + PUSHINT 2; + INSERT; + PUSHINT 2; + PUSHINT 1; + INSERT; + PUSHINT 3; + PUSHINT 6; + INSERT; + PUSHINT 4; + PUSHINT 0; + PUSHINT 2; + SUB; + INSERT; + PUSHVAR "bubble_sort"; + CALL 1, 1; + PUSHVAR "print"; + CALL 1, 1; + POP 1; + RETURN 0; diff --git a/examples/hello-world.njbc b/examples/hello-world.njbc new file mode 100644 index 0000000..f37fe92 --- /dev/null +++ b/examples/hello-world.njbc @@ -0,0 +1,5 @@ +PUSHSTR "Hello, world!\n"; +PUSHVAR "print"; +CALL 1, 1; +POP 1; +RETURN 0; diff --git a/makefile b/makefile index dfd7447..70a377a 100644 --- a/makefile +++ b/makefile @@ -57,8 +57,8 @@ LFLAGS_DEBUG = CFLAGS_RELEASE = -DNDEBUG -O3 LFLAGS_RELEASE = -CFLAGS_COVERAGE_GCC = -LFLAGS_COVERAGE_GCC = --coverage +CFLAGS_COVERAGE_GCC = -fprofile-arcs -ftest-coverage +LFLAGS_COVERAGE_GCC = -lgcov CFLAGS_COVERAGE_CLANG = -fprofile-instr-generate -fcoverage-mapping LFLAGS_COVERAGE_CLANG = # NOTE: To support BUILD_MODE=COVERAGE for a new compiler, @@ -135,4 +135,4 @@ install: $(LIB) $(CLI) clean: rm -rf $(OBJDIR) rm -f $(LIB) - rm -f $(CLI) \ No newline at end of file + rm -f $(CLI) diff --git a/src/cli/main.c b/src/cli/main.c index 42bb96b..b76f92c 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -39,7 +39,9 @@ static const char usage[] = " $ noja run file.noja\n" " $ noja run inline \"print('some noja code');\"\n" " $ noja dis file.noja\n" - " $ noja dis inline \"print('some noja code');\"\n"; + " $ noja dis inline \"print('some noja code');\"\n" + " $ noja asm file.noja\n" + " $ noja asm inline \"PUSHINT 5; PUSHFLT 1.0; ADD; POP 1;\"\n"; int main(int argc, char **argv) { @@ -76,6 +78,30 @@ int main(int argc, char **argv) r = NOJA_runFile(argv[2]); return r ? 0 : -1; } + + if(!strcmp(argv[1], "asm")) + { + if(argc == 2) + { + fprintf(stderr, "Error: Missing source file.\n"); + return -1; + } + + _Bool r; + + if(!strcmp(argv[2], "inline")) + { + if(argc == 3) + { + fprintf(stderr, "Error: Missing source string.\n"); + return -1; + } + r = NOJA_runAssemblyString(argv[3]); + } + else + r = NOJA_runAssemblyFile(argv[2]); + return r ? 0 : -1; + } if(!strcmp(argv[1], "dis")) { @@ -111,4 +137,4 @@ int main(int argc, char **argv) fprintf(stderr, "Error: Incorrect usage.\n\n"); fprintf(stderr, usage); return -1; -} \ No newline at end of file +} diff --git a/src/noja/assembler/assembler.c b/src/noja/assembler/assembler.c deleted file mode 100644 index f833e86..0000000 --- a/src/noja/assembler/assembler.c +++ /dev/null @@ -1,389 +0,0 @@ -#include -#include -#include -#include -#include "../utils/error.h" -#include "../utils/source.h" -#include "../utils/labellist.h" -#include "../common/executable.h" - -typedef struct { - const char *str; - size_t len; - size_t cur; -} Context; - -static void skipIdentifier(Context *ctx) -{ - while(ctx->cur < ctx->len && (isalpha(ctx->str[ctx->cur]) || isdigit(ctx->str[ctx->cur]) || ctx->str[ctx->cur] == '_')) - ctx->cur += 1; -} - -static void skipSpaces(Context *ctx) -{ - while(ctx->cur < ctx->len && isspace(ctx->str[ctx->cur])) - ctx->cur += 1; -} - -typedef struct { - size_t offset; - size_t length; -} Slice; - -static bool parseLabelAndOpcode(Context *ctx, bool *no_label, - Slice *label, Slice *opcode, - Error *error) -{ - assert(ctx != NULL && no_label != NULL - && label != NULL && opcode != NULL); - - // NOTE: This function must start at - // the first byte of the label or - // opcode. All whitespace must be - // consumed by the caller. - - // Now we expect either a label and an - // opcode, or just an opcode - // - //