+++ /dev/null
-source 'https://rubygems.org'\r
-gem 'rake', '>= 0'\r
-gem 'rscons', '>= 0'\r
-gem 'rspec', '>= 0'\r
+++ /dev/null
-GEM
- remote: https://rubygems.org/
- specs:
- diff-lcs (1.2.5)
- json (1.8.1)
- rake (10.3.2)
- rscons (1.8.1)
- json (~> 1.0)
- rspec (3.1.0)
- rspec-core (~> 3.1.0)
- rspec-expectations (~> 3.1.0)
- rspec-mocks (~> 3.1.0)
- rspec-core (3.1.7)
- rspec-support (~> 3.1.0)
- rspec-expectations (3.1.2)
- diff-lcs (>= 1.2.0, < 2.0)
- rspec-support (~> 3.1.0)
- rspec-mocks (3.1.3)
- rspec-support (~> 3.1.0)
- rspec-support (3.1.2)
-
-PLATFORMS
- ruby
- x86-mingw32
-
-DEPENDENCIES
- rake
- rscons
- rspec
--- /dev/null
+#------------------------------------------------------------------------------
+# Build Configuration
+#------------------------------------------------------------------------------
+# Update these variables according to your requirements.
+
+# tools
+CC = c99
+LD = ${CC}
+AR = ar
+
+# flags
+INCS = -Isource/ -Itests/
+CPPFLAGS = -D_XOPEN_SOURCE=700
+CFLAGS += ${INCS} ${CPPFLAGS}
+LDFLAGS += ${LIBS}
+ARFLAGS = rcs
+
+#------------------------------------------------------------------------------
+# Build Targets and Rules
+#------------------------------------------------------------------------------
+SRCS = source/onward.c source/main.c
+OBJS = ${SRCS:.c=.o}
+LIB = libonward.a
+BIN = onward
+TEST_SRCS = tests/atf.c tests/main.c tests/test_interpreter.c tests/test_vars.c
+TEST_OBJS = ${TEST_SRCS:.c=.o}
+TEST_BIN = testonward
+
+all: options ${BIN} ${TEST_BIN}
+
+options:
+ @echo "Toolchain Configuration:"
+ @echo " CC = ${CC}"
+ @echo " CFLAGS = ${CFLAGS}"
+ @echo " LD = ${LD}"
+ @echo " LDFLAGS = ${LDFLAGS}"
+ @echo " AR = ${AR}"
+ @echo " ARFLAGS = ${ARFLAGS}"
+ @echo " ARFLAGS = ${MAKEDEPEND}"
+
+${LIB}: ${OBJS}
+ @echo AR $@
+ @${AR} ${ARFLAGS} $@ ${OBJS}
+
+${BIN}: ${LIB}
+ @echo LD $@
+ @${LD} -o $@ ${LIB} ${LDFLAGS}
+
+
+${TEST_BIN}: ${TEST_OBJS} ${LIB}
+ @echo LD $@
+ @${LD} -o $@ ${TEST_OBJS} ${LIB} ${LDFLAGS}
+ -./$@
+
+.c.o:
+ @echo CC $<
+ @${CC} ${CFLAGS} -c -o $@ $<
+
+clean:
+ @rm -f ${LIB} ${BIN} ${TEST_BIN} ${OBJS} ${TEST_OBJS}
+
+.PHONY: all options
+
+++ /dev/null
-#!/usr/bin/env ruby
-require './modules/build-system/setup'
-
-#------------------------------------------------------------------------------
-# Environment Definitions
-#------------------------------------------------------------------------------
-# Define the default compiler environment
-base_env = BuildEnv.new do |env|
- env.build_root = 'build/'
- # Compiler options
- env["CFLAGS"] += ['-DLEAK_DETECT_LEVEL=1', '--std=c99', '-Wall', '-Wextra']#, '-Werror']
- env["CPPPATH"] += Dir['source/**/']
-end
-
-# Define the release environment
-main_env = base_env.clone do |env|
- env.build_root = 'build/release/'
- env["CFLAGS"] += ['-O3']
-end
-
-# Define the test environment
-test_env = base_env.clone do |env|
- env.build_root = 'build/test/'
- env["CPPPATH"] += Dir['modules/atf/source/**/']
- env['CFLAGS'] += ['-O0']
- if Opts[:profile].include? "coverage"
- env['CFLAGS'] << '--coverage'
- env['LDFLAGS'] << '--coverage'
- end
-end
-
-#------------------------------------------------------------------------------
-# Test Build Targets
-#------------------------------------------------------------------------------
-unless Opts[:profile].include? "no-tests"
- test_env.Program('onward-tests', [
- 'source/onward.c',
- 'modules/atf/source/atf.c'] +
- Dir['tests/**/*.c'])
- test_env.Command('Unit Tests', ['./onward-tests'], 'CMD' => ['./onward-tests'])
-end
-
-#------------------------------------------------------------------------------
-# Release Build Targets
-#------------------------------------------------------------------------------
-main_env.Library('libonward.a', FileList['source/*.c'])
-main_env.Program('onward', FileList['source/*.c'],
- 'CFLAGS' => main_env['CFLAGS'] + ['-DSTANDALONE'])
-
--- /dev/null
+#include <onward.h>
+#include <onward_sys.h>
+
+/* System Calls
+ *****************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+
+static void syscall_open(void)
+{
+ intptr_t modenum = onward_aspop();
+ char* fname = (char*)onward_aspop();
+ char* mode;
+ switch (modenum) {
+ case 0: mode = "r"; break;
+ case 1: mode = "w"; break;
+ case 2: mode = "a"; break;
+ case 3: mode = "r+"; break;
+ case 4: mode = "w+"; break;
+ case 5: mode = "a+"; break;
+ default: mode = NULL; break;
+ }
+ onward_aspush(mode ? (intptr_t)fopen(fname, mode) : 0);
+}
+
+static void syscall_close(void)
+{
+ onward_aspush(fclose((FILE*)onward_aspop()));
+}
+
+static void syscall_read(void)
+{
+ size_t nbytes = (size_t)onward_aspop();
+ FILE* fhndl = (FILE*)onward_aspop();
+ void* dest = (void*)onward_aspop();
+ onward_aspush(nbytes != fread(dest, 1u, nbytes, fhndl));
+}
+
+static void syscall_write(void)
+{
+ size_t nbytes = (size_t)onward_aspop();
+ void* src = (void*)onward_aspop();
+ FILE* fhndl = (FILE*)onward_aspop();
+ onward_aspush(nbytes != fwrite(src, 1u, nbytes, fhndl));
+}
+
+static void syscall_seek(void)
+{
+ intptr_t nbytes = onward_aspop();
+ intptr_t origin = onward_aspop();
+ FILE* fhndl = (FILE*)onward_aspop();
+ origin = (origin == 0) ? SEEK_CUR : (origin < 0) ? SEEK_SET : SEEK_END;
+ onward_aspush(fseek(fhndl, nbytes, origin));
+}
+
+static void syscall_alloc(void)
+{
+ onward_aspush((intptr_t)malloc((size_t)onward_aspop()));
+}
+
+static void syscall_free(void)
+{
+ free((void*)onward_aspop());
+}
+
+typedef void (*syscall_fn_t)(void);
+
+static syscall_fn_t System_Calls[7] = {
+ /* File Operations */
+ &syscall_open,
+ &syscall_close,
+ &syscall_read,
+ &syscall_write,
+ &syscall_seek,
+
+ /* Memory Operations */
+ &syscall_alloc,
+ &syscall_free,
+};
+
+/* Standalone Interpreter
+ *****************************************************************************/
+#include <stdbool.h>
+
+static bool Newline_Consumed = false;
+value_t Argument_Stack[ARG_STACK_SZ];
+value_t Return_Stack[RET_STACK_SZ];
+value_t Word_Buffer[WORD_BUF_SZ];
+
+defvar("infile", infile, 0u, LATEST_BUILTIN);
+defvar("outfile", outfile, 0u, &infile_word);
+defvar("errfile", errfile, 0u, &outfile_word);
+defcode("syscall", syscall, &errfile_word, 0u) {
+ System_Calls[onward_aspop()]();
+}
+
+defcode("dumpw", dumpw, &syscall, 0u) {
+ word_t* word = (word_t*)onward_aspop();
+ printf("name:\t'%s'\n", word->name);
+ printf("flags:\t%#zx\n", word->flags);
+ printf("link:\t%p\n", word->link);
+ /* Print the word's instructions */
+ if (word->flags & F_PRIMITIVE_MSK) {
+ printf("code:\t%p\n", word->code);
+ } else {
+ printf("code:");
+ word_t** code = (word_t**)word->code;
+ while(*code) {
+ printf("\t%s", (*code)->name);
+ if ((*code == &lit) || (*code == &zbr) || (*code == &br))
+ printf(" %zd", (intptr_t)*(++code));
+ code++;
+ puts("");
+ }
+ printf("\tret\n");
+ }
+}
+
+value_t fetch_char(void)
+{
+ value_t ch = (value_t)fgetc((FILE*)infile);
+ if ((char)ch == '\n')
+ Newline_Consumed = true;
+ return ch;
+}
+
+void emit_char(value_t val)
+{
+ fputc((int)val, (FILE*)outfile);
+}
+
+void print_stack(void) {
+ value_t* base = (value_t*)asb;
+ value_t* top = (value_t*)asp;
+ printf("( ");
+ int i;
+ if (top-5 >= base)
+ printf("... ");
+ for (i = 4; i >= 0; i--) {
+ value_t* curr = top-i;
+ if (curr > base)
+ printf("%#zx ", *curr);
+ }
+ puts(")");
+ printf("errcode: %zd\n", errcode);
+ puts(!errcode ? "OK." : "?");
+}
+
+void parse(FILE* file) {
+ value_t old = infile;
+ infile = (value_t)file;
+ if (file == stdin)
+ printf(":> ");
+ while (!feof(file)) {
+ errcode = 0;
+ interp_code();
+ if ((file == stdin) && Newline_Consumed) {
+ print_stack();
+ printf(":> ");
+ Newline_Consumed = false;
+ errcode = 0;
+ }
+ }
+ infile = old;
+}
+
+void parse_file(char* fname) {
+ FILE* file = fopen(fname, "r");
+ if (file) {
+ parse(file);
+ fclose(file);
+ }
+}
+
+int main(int argc, char** argv) {
+ int i;
+ /* Initialize implementation specific words */
+ latest = (value_t)&dumpw;
+ infile = (value_t)stdin;
+ outfile = (value_t)stdout;
+ errfile = (value_t)stderr;
+ /* Load any dictionaries specified on the command line */
+ for (i = 1; i < argc; i++)
+ parse_file(argv[i]);
+ printf("Memory Usage: %zd / %zd\n", here - (value_t)Word_Buffer, sizeof(Word_Buffer));
+ /* Start the REPL */
+ parse(stdin);
+ return 0;
+}
return ret;
}
-/* System Calls
- *****************************************************************************/
-#ifdef STANDALONE
-#include <stdio.h>
-#include <stdlib.h>
-
-static void syscall_open(void)
-{
- intptr_t modenum = onward_aspop();
- char* fname = (char*)onward_aspop();
- char* mode;
- switch (modenum) {
- case 0: mode = "r"; break;
- case 1: mode = "w"; break;
- case 2: mode = "a"; break;
- case 3: mode = "r+"; break;
- case 4: mode = "w+"; break;
- case 5: mode = "a+"; break;
- default: mode = NULL; break;
- }
- onward_aspush(mode ? (intptr_t)fopen(fname, mode) : 0);
-}
-
-static void syscall_close(void)
-{
- onward_aspush(fclose((FILE*)onward_aspop()));
-}
-
-static void syscall_read(void)
-{
- size_t nbytes = (size_t)onward_aspop();
- FILE* fhndl = (FILE*)onward_aspop();
- void* dest = (void*)onward_aspop();
- onward_aspush(nbytes != fread(dest, 1u, nbytes, fhndl));
-}
-
-static void syscall_write(void)
-{
- size_t nbytes = (size_t)onward_aspop();
- void* src = (void*)onward_aspop();
- FILE* fhndl = (FILE*)onward_aspop();
- onward_aspush(nbytes != fwrite(src, 1u, nbytes, fhndl));
-}
-
-static void syscall_seek(void)
-{
- intptr_t nbytes = onward_aspop();
- intptr_t origin = onward_aspop();
- FILE* fhndl = (FILE*)onward_aspop();
- origin = (origin == 0) ? SEEK_CUR : (origin < 0) ? SEEK_SET : SEEK_END;
- onward_aspush(fseek(fhndl, nbytes, origin));
-}
-
-static void syscall_alloc(void)
-{
- onward_aspush((intptr_t)malloc((size_t)onward_aspop()));
-}
-
-static void syscall_free(void)
-{
- free((void*)onward_aspop());
-}
-
-typedef void (*syscall_fn_t)(void);
-
-static syscall_fn_t System_Calls[7] = {
- /* File Operations */
- &syscall_open,
- &syscall_close,
- &syscall_read,
- &syscall_write,
- &syscall_seek,
-
- /* Memory Operations */
- &syscall_alloc,
- &syscall_free,
-};
-#endif
-
-/* Standalone Interpreter
- *****************************************************************************/
-#ifdef STANDALONE
-#include <stdbool.h>
-
-static bool Newline_Consumed = false;
-value_t Argument_Stack[ARG_STACK_SZ];
-value_t Return_Stack[RET_STACK_SZ];
-value_t Word_Buffer[WORD_BUF_SZ];
-
-defvar("infile", infile, 0u, LATEST_BUILTIN);
-defvar("outfile", outfile, 0u, &infile_word);
-defvar("errfile", errfile, 0u, &outfile_word);
-defcode("syscall", syscall, &errfile_word, 0u) {
- System_Calls[onward_aspop()]();
-}
-
-defcode("dumpw", dumpw, &syscall, 0u) {
- word_t* word = (word_t*)onward_aspop();
- printf("name:\t'%s'\n", word->name);
- printf("flags:\t%#zx\n", word->flags);
- printf("link:\t%p\n", word->link);
- /* Print the word's instructions */
- if (word->flags & F_PRIMITIVE_MSK) {
- printf("code:\t%p\n", word->code);
- } else {
- printf("code:");
- word_t** code = (word_t**)word->code;
- while(*code) {
- printf("\t%s", (*code)->name);
- if ((*code == &lit) || (*code == &zbr) || (*code == &br))
- printf(" %zd", (intptr_t)*(++code));
- code++;
- puts("");
- }
- printf("\tret\n");
- }
-}
-
-value_t fetch_char(void)
-{
- value_t ch = (value_t)fgetc((FILE*)infile);
- if ((char)ch == '\n')
- Newline_Consumed = true;
- return ch;
-}
-
-void emit_char(value_t val)
-{
- fputc((int)val, (FILE*)outfile);
-}
-
-void print_stack(void) {
- value_t* base = (value_t*)asb;
- value_t* top = (value_t*)asp;
- printf("( ");
- int i;
- if (top-5 >= base)
- printf("... ");
- for (i = 4; i >= 0; i--) {
- value_t* curr = top-i;
- if (curr > base)
- printf("%#zx ", *curr);
- }
- puts(")");
- printf("errcode: %zd\n", errcode);
- puts(!errcode ? "OK." : "?");
-}
-
-void parse(FILE* file) {
- value_t old = infile;
- infile = (value_t)file;
- if (file == stdin)
- printf(":> ");
- while (!feof(file)) {
- errcode = 0;
- interp_code();
- if ((file == stdin) && Newline_Consumed) {
- print_stack();
- printf(":> ");
- Newline_Consumed = false;
- errcode = 0;
- }
- }
- infile = old;
-}
-
-void parse_file(char* fname) {
- FILE* file = fopen(fname, "r");
- if (file) {
- parse(file);
- fclose(file);
- }
-}
-
-int main(int argc, char** argv) {
- int i;
- /* Initialize implementation specific words */
- latest = (value_t)&dumpw;
- infile = (value_t)stdin;
- outfile = (value_t)stdout;
- errfile = (value_t)stderr;
- /* Load any dictionaries specified on the command line */
- for (i = 1; i < argc; i++)
- parse_file(argv[i]);
- printf("Memory Usage: %zd / %zd\n", here - (value_t)Word_Buffer, sizeof(Word_Buffer));
- /* Start the REPL */
- parse(stdin);
- return 0;
-}
-#endif
#define deccode(c_name) \
void c_name##_code(void); \
- const word_t c_name \
+ const word_t c_name
/** Define a built-in word that executes native code */
#define defcode(name_str, c_name, prev, flags) \
void c_name##_code(void)
#define decword(c_name) \
- const word_t c_name \
+ const word_t c_name
/** Define a built-in word that is defined by references to other words. */
#define defword(name_str, c_name, prev, flags) \
#define decvar(c_name) \
value_t c_name; \
- const word_t c_name##_word \
+ const word_t c_name##_word
/** Define a built-in word representing a variable with the provided value */
#define defvar(name_str, c_name, initial, prev) \
- value_t c_name = initial; \
+ extern value_t c_name; \
defcode(name_str, c_name##_word, prev, 0u) { \
- onward_aspush((value_t)&c_name); \
- }
+ onward_aspush((value_t)&c_name); } \
+ value_t c_name = initial
#define decconst(c_name) \
const value_t c_name; \
- const word_t c_name##_word \
+ const word_t c_name##_word
/** Define a built-in word representing a constant with the provided value */
#define defconst(name_str, c_name, value, prev) \
- const value_t c_name = value; \
+ extern const value_t c_name; \
defcode(name_str, c_name##_word, prev, 0u) { \
- onward_aspush(c_name); \
- }
+ onward_aspush(c_name); } \
+ const value_t c_name = value
#define ERR_NONE (0x00)
#define ERR_UNKNOWN_WORD (0x01)
--- /dev/null
+/**
+ @file atf.c
+ @brief See header for details
+ $Revision$
+ $HeadURL$
+*/
+#include "atf.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_SIGNALS
+#include <signal.h>
+#endif
+
+char* Curr_Test = NULL;
+char* Curr_File = NULL;
+unsigned int Curr_Line = 0;
+static unsigned int Total = 0;
+static unsigned int Failed = 0;
+
+#ifndef NO_SIGNALS
+static void handle_signal(int sig) {
+ /* Determine the signal name */
+ char* sig_name = NULL;
+ switch(sig) {
+ case SIGABRT: sig_name = "SIGABRT"; break;
+ case SIGBUS: sig_name = "SIGBUS"; break;
+ case SIGFPE: sig_name = "SIGFPE"; break;
+ case SIGILL: sig_name = "SIGILL"; break;
+ case SIGSEGV: sig_name = "SIGSEGV"; break;
+ case SIGSYS: sig_name = "SIGSYS"; break;
+ /* If we don't recognize it then just return and let the default handler
+ catch it. */
+ default: return;
+ }
+ /* Error and exit. No summary will be printed but the user will know which
+ test has crashed. */
+ fprintf(stderr,"%s:%d:0:%s:CRASH (signal: %d)\n", Curr_File, Curr_Line, Curr_Test, sig);
+ Failed++;
+ (void)atf_print_results();
+ exit(1);
+}
+#endif
+
+void atf_init(int argc, char** argv) {
+ /* I reserve the right to use these later */
+ (void)argc;
+ (void)argv;
+
+#ifndef NO_SIGNALS
+ /* Init signal handler */
+ signal(SIGABRT, handle_signal);
+ signal(SIGBUS, handle_signal);
+ signal(SIGFPE, handle_signal);
+ signal(SIGILL, handle_signal);
+ signal(SIGSEGV, handle_signal);
+ signal(SIGSYS, handle_signal);
+#endif
+}
+
+void atf_run_suite(suite_t suite) {
+ suite();
+}
+
+void atf_test_start(char* file, unsigned int line, char* name) {
+ Curr_File = file;
+ Curr_Line = line;
+ Curr_Test = name;
+ Total++;
+}
+
+bool atf_test_assert(bool success, char* expr, char* file, int line) {
+ bool failed = !success;
+ if (failed) atf_test_fail(expr,file,line);
+ return failed;
+}
+
+void atf_test_fail(char* expr, char* file, int line) {
+ Failed++;
+ printf("%s:%d:0:%s:FAIL:( %s )\n", file, line, Curr_Test, expr); \
+}
+
+int atf_print_results(void) {
+ static const char* results_string =
+ "\nUnit Test Summary"
+ "\n-----------------"
+ "\nTotal: %d"
+ "\nPassed: %d"
+ "\nFailed: %d"
+ "\n\n";
+ printf(results_string, Total, Total - Failed, Failed);
+ return Failed;
+}
+
--- /dev/null
+/**
+ @file atf.h
+ @brief Aardvark Test Framework main interface file.
+ $Revision$
+ $HeadURL$
+*/
+#ifndef TEST_H
+#define TEST_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+typedef void (*suite_t)(void);
+
+extern char* Curr_Test;
+
+void atf_init(int argc, char** argv);
+
+void atf_run_suite(suite_t suite);
+
+void atf_test_start(char* file, unsigned int line, char* name);
+
+bool atf_test_assert(bool success, char* expr_str, char* file, int line);
+
+void atf_test_fail(char* expr, char* file, int line);
+
+int atf_print_results(void);
+
+#define CHECK(expr) \
+ if(atf_test_assert((expr), #expr, __FILE__, __LINE__)) break
+
+#define TEST_SUITE(name) void name(void)
+
+#define TEST(desc) \
+ for(atf_test_start(__FILE__,__LINE__,#desc); Curr_Test != NULL; Curr_Test = NULL)
+
+#define RUN_EXTERN_TEST_SUITE(name) \
+ do { extern TEST_SUITE(name); atf_run_suite(&name); } while(0)
+
+#define RUN_TEST_SUITE(name) \
+ atf_run_suite(&name)
+
+#define PRINT_TEST_RESULTS atf_print_results
+
+#endif /* TEST_H */