diff --git a/.gitignore b/.gitignore index d477e49..624ef41 100644 --- a/.gitignore +++ b/.gitignore @@ -57,3 +57,6 @@ dkms.conf .project .settings/ build/ + +# Munit +src/munit.* diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1bfece3 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "munit"] + path = munit + url = https://github.com/nemequ/munit.git diff --git a/Makefile b/Makefile index 688b419..3631865 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ else $(error Build mode $(BUILD_MODE) not supported by this Makefile) endif -SRC_DIR=$(PROJECT_ROOT)/src +SRC_DIR=$(PROJECT_ROOT)/src/c all: grendel diff --git a/README.md b/README.md index 6c37626..62d34b6 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,11 @@ Tags will be allocated as follows: | 3-bit value | 7-bit value | (Hex) | Interpretation | | ----------- | ----------- | ----- | ------------------------------------------------------------ | -| 0 | 0 | 0x0 | a pointer; an offset into the vector of words. | -| 1 | 1 | 0x1 | a signed 28 bit integer. | -| 2 | 2 | 0x2 | a character; possibly just a byte, or possibly a 16 bit wchar. | -| 3 | 3 | 0x3 | unassigned (possibly a floating point number, later.) | -| 4 | 4 | 0x4 | unassigned | +| 0 | 0 | 0x0 | an error object, whose payload is a 3 character error code. | +| 1 | 1 | 0x1 | a pointer; an offset into the vector of words. | +| 2 | 2 | 0x2 | a signed 28 bit integer. | +| 3 | 3 | 0x3 | a character; possibly just a byte, or possibly a 16 bit wchar. | +| 4 | 4 | 0x4 | unassigned (possibly a floating point number, later.) | | 5 | 5 | 0x5 | unassigned | | 6 | 6 | 0x6 | unassigned | | 7 | 7 | 0x7 | a cons cell | diff --git a/munit b/munit new file mode 160000 index 0000000..fbbdf14 --- /dev/null +++ b/munit @@ -0,0 +1 @@ +Subproject commit fbbdf1467eb0d04a6ee465def2e529e4c87f2118 diff --git a/src/c/day1.c b/src/c/day1.c new file mode 100644 index 0000000..cc9d7d5 --- /dev/null +++ b/src/c/day1.c @@ -0,0 +1,26 @@ +/** + * day1.c + * + * Grendel: a compiling Beowulf reimplementation. + * + * Day 1 of work towards a compiler... eventually.. + * + * This is a straight copy of Noah Zentzis' work. There's no original work of + * mine here, yet + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include + +__attribute__((__cdecl__)) +extern int lisp_entry(); + +int main(int argc, const char **argv) { + int val = lisp_entry(); + printf("%d\n", val); + return 0; +} diff --git a/src/c/error.c b/src/c/error.c new file mode 100644 index 0000000..3c60319 --- /dev/null +++ b/src/c/error.c @@ -0,0 +1,29 @@ +/** + * error.c + * + * Grendel: a compiling Beowulf reimplementation. + * + * The error handling subsystem. + * + * Error codes are detailed in section 6.3, page 32, of the + * Lisp 1.5 Programmer's Manual. I shall in so far as possible follow + * those codes. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include + +#include "error.h" +#include "memory.h" + +uint32_t make_error( char* code) { + uint32_t error = 0; + + strncpy( (char *)((&error) &1), code, 3); + + return error; +} diff --git a/src/c/error.h b/src/c/error.h new file mode 100644 index 0000000..0c09a42 --- /dev/null +++ b/src/c/error.h @@ -0,0 +1,45 @@ +/** + * error.h + * + * Grendel: a compiling Beowulf reimplementation. + * + * The error handling subsystem. + * + * Error codes are detailed in section 6.3, page 32, of the + * Lisp 1.5 Programmer's Manual. I shall in so far as possible follow + * those codes. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#ifndef __grendel_error_h +#define __grendel_error_h + +#include + +uint32_t make_error( char* code); + +/** + * @brief error codes + * + * Error codes are detailed in section 6.3, page 32, of the + * Lisp 1.5 Programmer's Manual. I shall in so far as possible follow + * those codes. + * + * Error codes comprise a one or two alphabetic character category, followed + * by a single digit number. A space is shown in the manual between the + * category and the number, but I have not followed that here for reasons. + */ + +#define APPLIED_FUNCTION_CALLED_ERROR (make_error( "A1")) +#define UNDEFINED_FUNCTION_APPLY_ERROR (make_error( "A2")) +#define COND_UNSATISFIED_ERROR (make_error( "A3")) +#define SETQ_ON_NONEXISTANT_VAR_ERROR (make_error( "A4")) +#define SET_ON_NONEXISTANT_VAR_ERROR (make_error( "A5")) +#define NO_TARGET_FOR_GO_ERROR (make_error( "A6")) +#define TOO_MANY_ARGUMENTS_ERROR (make_error( "A7")) +#define UNBOUND_VARIABLE_ERROR (make_error( "A8")) +#define UNDEFINED_FUNCTION_EVAL_ERROR (make_error( "A9")) + +#endif diff --git a/src/grendel.c b/src/c/grendel.c similarity index 70% rename from src/grendel.c rename to src/c/grendel.c index f6167fb..6421198 100644 --- a/src/grendel.c +++ b/src/c/grendel.c @@ -15,6 +15,11 @@ #include #include "memory.h" +#include "version.h" + +__attribute__((__cdecl__)) +extern int lisp_entry(); + void showbits( unsigned int x ) { @@ -28,18 +33,12 @@ void showbits( unsigned int x ) int main(int argc, char **argv) { - printf( "Grendel:\n"); - int i; - - for ( i = 0; i < 8; i++) { - printf( "\ti = %d (%b, 0x%x);\n", i, i, i); - } - for ( ; i < 128; i++) { - if ((i & TAG32MASK) == TAG32MASK) { - printf( "\ti = %d (%b, 0x%x);\n", i, i, i); - } - } + printf( "Grendel, a compiler for Beowulf: version %s\n", VERSION); + int val = lisp_entry(); + printf("%d\n", val); + return 0; +} return 0; } diff --git a/src/c/lisp.c b/src/c/lisp.c new file mode 100644 index 0000000..8b19cd2 --- /dev/null +++ b/src/c/lisp.c @@ -0,0 +1,19 @@ +/** + * lisp.c + * + * Grendel: a compiling Beowulf reimplementation. + * + * The compiler... eventually.. + * + * Error codes are detailed in section 6.3, page 32, of the + * Lisp 1.5 Programmer's Manual. I shall in so far as possible follow + * those codes. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#include +#include +#include + diff --git a/src/memory.h b/src/c/memory.h similarity index 80% rename from src/memory.h rename to src/c/memory.h index c768e39..07ad06f 100644 --- a/src/memory.h +++ b/src/c/memory.h @@ -16,64 +16,64 @@ /* Tags for 32 bit objects, with 3 bits of tag an one mark bit */ +#define ERRORTV (0) /** * @brief This pointer object is an actual pointer -- an offset into consspace. */ -#define OFFSETTV (0) +#define OFFSETTV (1) /** * @brief This pointer object is actually a 28 bit integer value. */ -#define INTEGERTV (1) +#define INTEGERTV (2) /** * @brief A character; initially just a byte. but potentially a 16 bit wchar. */ - #define CHARTV (2) + #define CHARTV (3) /** * @brief A 16 bit floating point number. (future expansion) * * Yes, it could be 28 bit, but I think that would hurt my brain. */ -#define FLOATTV (3) +#define FLOATTV (4) /* - * Values 4..6 inclusive reserved further data types, including maybe - * implementing reals later. + * Values 5 and 6 are available for further 32 bit data types. */ /** * @bried This is not actually a pointer at all but the first word of a cell. */ -#define CELLTV (7) +#define CELLTV (7) /** * @brief this cell is a symbol */ -#define SYMBOLTV (0xf) +#define SYMBOLTV (0xf) /** * @brief this cell is a pointer to a compiled function */ -#define FUNCTIONTV (0x17) +#define FUNCTIONTV (0x17) /** * @brief This cell is pointer to a compiled special form */ -#define SPECIALTV (0x1f) +#define SPECIALTV (0x1f) /** * @brief this cell is a rational number (future expansion) */ -#define RATIOTV (0x27) +#define RATIOTV (0x27) /** * @brief this cell is a digit of a big number (future expansion) */ -#define BIGNUMTV (0x2f) +#define BIGNUMTV (0x2f) /** * @brief this cell is part of a string (future expansion) */ -#define STRINGTV (0x37) +#define STRINGTV (0x37) // The possible potential values remain unassigned: // i = 63 (111111, 0x3f); @@ -85,14 +85,14 @@ // i = 111 (1101111, 0x6f); // i = 119 (1110111, 0x77); -#define FREETV (0x7f) +#define FREETV (0x7f) -#define MARKMASK ((unsigned int)1) -#define TAG32MASK ((unsigned int)7) -#define TAG64MASK ((unsigned int)0xf) +#define MARKMASK ((uint64_t)1) +#define TAG32MASK ((uint64_t)7) +#define TAG64MASK ((uint64_t)0xf) -#define MASK64 (0xffffffffffffffff) -#define MASK32 (0xffffffff) +#define MASK64 ((uint64_t)0xffffffffffffffff) +#define MASK32 ((uint64_t)0xffffffff) /** * @brief Return the mark bit of this object. diff --git a/src/c/version.h b/src/c/version.h new file mode 100644 index 0000000..17656c8 --- /dev/null +++ b/src/c/version.h @@ -0,0 +1,15 @@ +/** + * version.h + * + * Grendel: a compiling Beowulf reimplementation. + * + * (c) 2026 Simon Brooke + * Licensed under GPL version 2.0, or, at your option, any later version. + */ + +#ifndef __grendel_version_h +#define __grendel_version_h + +#define VERSIOM "Aelfhere" + +#ifndef diff --git a/src/guile/day1.scm b/src/guile/day1.scm new file mode 100644 index 0000000..2ff5c63 --- /dev/null +++ b/src/guile/day1.scm @@ -0,0 +1,30 @@ +(define emit (lambda args (apply simple-format #t args) + (newline))) + +(define (compile-program program) + (emit ".text") + (emit ".p2align 4,,15") + (emit ".globl lisp_entry") + (emit "lisp_entry:") + + ; handle incoming call from C + (emit "push %esi") + (emit "push %edi") + (emit "push %edx") + + ; our code goes here + (emit "movl $42, %eax") + + ; restore state for return to C + (emit "pop %edx") + (emit "pop %edi") + (emit "pop %esi") + (emit "ret")) + +(define (compile-to-binary program) + (begin + (with-output-to-file "/tmp/compiled.s" + (lambda () (compile-program program))) + (system "gcc -fomit-frame-pointer -m32 /tmp/compiled.s src/c/day1.c"))) + + \ No newline at end of file