diff --git a/.gitignore b/.gitignore index ab4e333..1f076b1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,9 @@ -cache -vgcore.* -libnoja.a +cache/ +report/ + noja -*.gcov \ No newline at end of file +!noja/ + +vgcore.* +*.gcov +lib*.a \ No newline at end of file diff --git a/coverage.sh b/coverage.sh deleted file mode 100755 index c649d9e..0000000 --- a/coverage.sh +++ /dev/null @@ -1,8 +0,0 @@ -./build.sh --coverage -mkdir temp -export LLVM_PROFILE_FILE="temp/noja.profraw" -./build/noja run examples/json.noja -llvm-profdata merge -sparse temp/noja.profraw -o temp/noja.profdata -llvm-cov show ./build/noja -instr-profile=temp/noja.profdata >> build/coverage.txt -llvm-cov export ./build/noja -instr-profile=temp/noja.profdata >> build/coverage.json -rm -rf temp \ No newline at end of file diff --git a/examples/bubble_sort.njbc b/examples/bubble_sort.njbc index f0009e8..2317ae9 100644 --- a/examples/bubble_sort.njbc +++ b/examples/bubble_sort.njbc @@ -12,12 +12,14 @@ copy: PUSHINT 0; ASS "i"; POP 1; + +loop_start: PUSHVAR "i"; PUSHVAR "L"; PUSHVAR "count"; CALL 1, 1; LSS; - JUMPIFNOTANDPOP 31; + JUMPIFNOTANDPOP loop_end; PUSHVAR "L"; PUSHVAR "i"; SELECT; @@ -30,7 +32,8 @@ copy: ADD; ASS "i"; POP 1; - JUMP 12; + JUMP loop_start; +loop_end: PUSHVAR "L2"; RETURN 1; RETURN 0; @@ -50,7 +53,7 @@ bubble_sort: PUSHNNE; EQL; JUMPIFNOTANDPOP default_less_cb_end; - PUSHFUN 50, 2; + PUSHFUN default_less_cb, 2; ASS "less"; POP 1; JUMP default_less_cb_end; diff --git a/makefile b/makefile index 70a377a..153e8b3 100644 --- a/makefile +++ b/makefile @@ -18,14 +18,22 @@ SRCDIR = src # when doing `make clean`. OBJDIR = cache +# Temporary directory where execution coverage +# reports are stored. If this directory doesn't +# exist, it will be created. This folder is +# deleted by `make clean`. +REPORTDIR = report + # Source directory for each program to be build # They are relative to the SRCDIR folder. -LIB_SUBDIR = noja +LIB_SUBDIR = lib CLI_SUBDIR = cli +TST_SUBDIR = test # Resulting file names LIB_FNAME = libnoja.a CLI_FNAME = noja +TST_FNAME = test # Where the build programs will be moved when # installation occurres. @@ -92,12 +100,14 @@ endif # Absolute path of each program's source tree LIB_SRCDIR = $(SRCDIR)/$(LIB_SUBDIR) CLI_SRCDIR = $(SRCDIR)/$(CLI_SUBDIR) +TST_SRCDIR = $(SRCDIR)/$(TST_SUBDIR) # Each program that is being build uses as object # cache a subfolder of OBJDIR called like the it's # source tree base folder in SRCDIR. LIB_OBJDIR = $(OBJDIR)/$(LIB_SUBDIR) CLI_OBJDIR = $(OBJDIR)/$(CLI_SUBDIR) +TST_OBJDIR = $(OBJDIR)/$(TST_SUBDIR) LIB_CFILES = $(call rwildcard, $(LIB_SRCDIR), *.c) LIB_HFILES = $(call rwildcard, $(LIB_SRCDIR), *.h) @@ -107,15 +117,24 @@ CLI_CFILES = $(call rwildcard, $(CLI_SRCDIR), *.c) CLI_HFILES = $(call rwildcard, $(CLI_SRCDIR), *.h) CLI_OFILES = $(patsubst $(CLI_SRCDIR)/%.c, $(CLI_OBJDIR)/%.o, $(CLI_CFILES)) +TST_CFILES = $(call rwildcard, $(TST_SRCDIR), *.c) +TST_HFILES = $(call rwildcard, $(TST_SRCDIR), *.h) +TST_OFILES = $(patsubst $(TST_SRCDIR)/%.c, $(TST_OBJDIR)/%.o, $(TST_CFILES)) + +ALL_CFILES = $(call rwildcard, $(SRCDIR), *.c) + # Useful abbreviations LIB = $(OUTDIR)/$(LIB_FNAME) CLI = $(OUTDIR)/$(CLI_FNAME) +TST = $(OUTDIR)/$(TST_FNAME) # ===================== # # === Rules =========== # # ===================== # -all: $(LIB) $(CLI) +.PHONY: report install clean all + +all: $(LIB) $(CLI) $(TST) $(OBJDIR)/%.o: $(SRCDIR)/%.c @ mkdir -p $(@D) @@ -128,11 +147,29 @@ $(LIB): $(LIB_OFILES) $(CLI): $(CLI_OFILES) $(LIB) $(CC) $^ -o $@ $(LFLAGS) +$(TST): $(TST_OFILES) $(LIB) + gcc $^ -o $@ $(LFLAGS) + +#$(REPORTDIR)/%.gcov: src/%.c +# @ mkdir -p $(@D) +# gcov --stdout $(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.c, $^) > $@ +# +#report: $(patsubst $(SRCDIR)/%.c, $(REPORTDIR)/%.gcov, $(ALL_CFILES)) +# lcov --capture --directory $(OBJDIR) --output-file coverage.info +# genhtml coverage.info --output-directory . +# + +report: + lcov --capture --directory $(OBJDIR) --output-file $(OBJDIR)/coverage.info + @ mkdir -p report + genhtml $(OBJDIR)/coverage.info --output-directory report + install: $(LIB) $(CLI) sudo cp $(LIB) $(LIB_INSTALLDIR) sudo cp $(CLI) $(CLI_INSTALLDIR) clean: rm -rf $(OBJDIR) + rm -rf $(REPORTDIR) rm -f $(LIB) - rm -f $(CLI) + rm -f $(CLI) \ No newline at end of file diff --git a/report_test_suite_coverage.sh b/report_test_suite_coverage.sh new file mode 100755 index 0000000..8331060 --- /dev/null +++ b/report_test_suite_coverage.sh @@ -0,0 +1,4 @@ +make -B BUILD_MODE=COVERAGE CC=gcc +./test tests/suite +make report +firefox report/index.html \ No newline at end of file diff --git a/src/cli/main.c b/src/cli/main.c index b76f92c..e3385fc 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -32,7 +32,7 @@ #include #include #include -#include "../noja/noja.h" +#include "../lib/noja.h" static const char usage[] = "Usage patterns:\n" diff --git a/src/noja/README.md b/src/lib/README.md similarity index 100% rename from src/noja/README.md rename to src/lib/README.md diff --git a/src/lib/assembler/assemble.c b/src/lib/assembler/assemble.c new file mode 100644 index 0000000..2a787c3 --- /dev/null +++ b/src/lib/assembler/assemble.c @@ -0,0 +1,393 @@ +#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 + // + //