Refactor for cleanliness

Move files into separate folders for ease of reading, include source
directory so we can use angle bracket includes, adjust build system to
make directories for objects
This commit is contained in:
2025-05-14 21:12:58 +01:00
parent ba5c0a4579
commit 12de1e8db9
18 changed files with 236 additions and 147 deletions

View File

@@ -1,6 +1,7 @@
CC=gcc CC=gcc
OUT=oats.out OUT=oats.out
LIBS=-I. INCLUDES=-I.
LIBS=
ARGS= ARGS=
RELEASE=0 RELEASE=0
@@ -16,7 +17,7 @@ CFLAGS=$(GFLAGS) $(DFLAGS)
endif endif
DIST=build DIST=build
SRC:=tag.c memory.c vec.c sv.c lisp.c reader.c eval.c main.c SRC:=lib/arena.c lib/vec.c lib/sv.c lisp/tag.c lisp/context.c lisp/lisp.c lisp/reader.c lisp/eval.c main.c
OBJ:=$(SRC:%.c=$(DIST)/%.o) OBJ:=$(SRC:%.c=$(DIST)/%.o)
DEPDIR=$(DIST)/dependencies DEPDIR=$(DIST)/dependencies
DEPS:=$(SRC:%.c=$(DEPDIR)/%.d) DEPS:=$(SRC:%.c=$(DEPDIR)/%.d)
@@ -25,10 +26,10 @@ DEPS:=$(SRC:%.c=$(DEPDIR)/%.d)
all: $(DIST)/$(OUT) all: $(DIST)/$(OUT)
$(DIST)/%.o: %.c | $(DIST) $(DEPDIR) $(DIST)/%.o: %.c | $(DIST) $(DEPDIR)
$(CC) $(CFLAGS) $(DEPFLAGS) $(DEPDIR)/$*.d -c $< -o $@ $(LIBS) $(CC) $(INCLUDES) $(CFLAGS) $(DEPFLAGS) $(DEPDIR)/$*.d -c $< -o $@ $(LIBS)
$(DIST)/$(OUT): $(OBJ) | $(DIST) $(DIST)/$(OUT): $(OBJ) | $(DIST)
$(CC) $(CFLAGS) $^ -o $@ $(LIBS) $(CC) $(INCLUDES) $(CFLAGS) $^ -o $@ $(LIBS)
.PHONY: run .PHONY: run
run: $(DIST)/$(OUT) run: $(DIST)/$(OUT)
@@ -38,11 +39,19 @@ run: $(DIST)/$(OUT)
clean: clean:
rm -rfv $(DIST)/* rm -rfv $(DIST)/*
$(DIST): $(DIST): | $(DIST)/lib $(DIST)/lisp
mkdir -p $(DIST) mkdir -p $(DIST)
$(DIST)/lib:
mkdir -p $(DIST)/lib
$(DIST)/lisp:
mkdir -p $(DIST)/lisp
$(DEPDIR): $(DEPDIR):
mkdir -p $(DEPDIR) mkdir -p $(DEPDIR)
mkdir -p $(DEPDIR)/lib
mkdir -p $(DEPDIR)/lisp
.PHONY: .PHONY:
watch: watch:

View File

@@ -13,7 +13,7 @@
* Description: Implementations for memory models. * Description: Implementations for memory models.
*/ */
#include "./memory.h" #include <lib/arena.h>
#include <malloc.h> #include <malloc.h>
#include <stdarg.h> #include <stdarg.h>
@@ -201,75 +201,3 @@ void arena_cleanup(arena_t *arena)
memset(arena, 0, sizeof(*arena)); memset(arena, 0, sizeof(*arena));
} }
// Allocates against stable memory i.e. we can have pointers of this lying
// around without any fear of them being thrown away.
void *context_alloc(context_t *context, u64 size)
{
return arena_alloc(&context->memory, size);
}
// Allocate against a "scratch space", separate from main memory, for internal
// use.
void *context_salloc(context_t *context, u64 size)
{
return arena_alloc(&context->scratch, size);
}
void context_reset_read(context_t *context)
{
arena_reset(&context->read);
}
void context_reset_scratch(context_t *context)
{
arena_reset(&context->scratch);
}
void context_reset(context_t *context)
{
arena_reset(&context->memory);
arena_reset(&context->read);
arena_reset(&context->scratch);
}
void context_cleanup(context_t *context)
{
if (!context)
return;
arena_cleanup(&context->memory);
arena_cleanup(&context->read);
arena_cleanup(&context->scratch);
memset(context, 0, sizeof(*context));
}
void context_report(context_t *context)
{
#if DEBUG
// Figure this out at runtime
u64 mem_used = 0, mem_cap = 0;
for (page_t *page = context->memory.start; page; page = page->next)
{
mem_used += page->size;
mem_cap += page->capacity;
}
u64 read_used = 0, read_cap = 0;
for (page_t *page = context->read.start; page; page = page->next)
{
read_used += page->size;
read_cap += page->capacity;
}
u64 scr_used = 0, scr_cap = 0;
for (page_t *page = context->scratch.start; page; page = page->next)
{
scr_used += page->size;
scr_cap += page->capacity;
}
info("<Context>: %luB/%luB main memory used\n", mem_used, mem_cap);
info("<Context>: %luB/%luB read space used\n", read_used, read_cap);
info("<Context>: %luB/%luB scratch space used\n", scr_used, scr_cap);
#endif
}

View File

@@ -10,13 +10,13 @@
* this program. If not, please go to <https://www.gnu.org/licenses/>. * this program. If not, please go to <https://www.gnu.org/licenses/>.
* Created: 2025-04-05 * Created: 2025-04-05
* Description: Memory management structures * Description: Arena
*/ */
#ifndef MEMORY_H #ifndef ARENA_H
#define MEMORY_H #define ARENA_H
#include "./base.h" #include <base.h>
#include <stdio.h> #include <stdio.h>
#define PAGE_DEFAULT_SIZE 1024 #define PAGE_DEFAULT_SIZE 1024
@@ -48,19 +48,4 @@ void arena_attach(arena_t *arena, page_t *page);
void arena_reset(arena_t *arena); void arena_reset(arena_t *arena);
void arena_cleanup(arena_t *arena); void arena_cleanup(arena_t *arena);
typedef struct Context
{
arena_t memory, read, scratch;
} context_t;
void *context_alloc(context_t *context, u64 size);
void *context_salloc(context_t *context, u64 size);
page_t *context_get_read_page(context_t *ctx);
void context_reset_read(context_t *context);
void context_reset_scratch(context_t *context);
void context_reset(context_t *context);
void context_cleanup(context_t *context);
void context_report(context_t *context);
#endif #endif

View File

@@ -13,7 +13,7 @@
* Description: String View implementation * Description: String View implementation
*/ */
#include "./sv.h" #include <lib/sv.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>

View File

@@ -16,7 +16,7 @@
#ifndef SV_H #ifndef SV_H
#define SV_H #define SV_H
#include "./memory.h" #include <lib/arena.h>
typedef struct SV typedef struct SV
{ {

View File

@@ -13,7 +13,7 @@
* Description: Vector implementation * Description: Vector implementation
*/ */
#include "./vec.h" #include <lib/vec.h>
#include <malloc.h> #include <malloc.h>
#include <string.h> #include <string.h>

View File

@@ -16,7 +16,7 @@
#ifndef VEC_H #ifndef VEC_H
#define VEC_H #define VEC_H
#include "./memory.h" #include <lib/arena.h>
typedef struct typedef struct
{ {

92
lisp/context.c Normal file
View File

@@ -0,0 +1,92 @@
/* Copyright (C) 2025 Aryadev Chavali
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License Version 2
* for details.
* You may distribute and modify this code under the terms of the
* GNU General Public License Version 2, which you should have received a copy
of along with this
* program. If not, please go to <https://www.gnu.org/licenses/>.
* Created: 2025-05-12
* Description:
*/
#include <lisp/context.h>
#include <string.h>
// Allocates against stable memory i.e. we can have pointers of this lying
// around without any fear of them being thrown away.
void *context_alloc(context_t *context, u64 size)
{
return arena_alloc(&context->memory, size);
}
// Allocate against a "scratch space", separate from main memory, for internal
// use.
void *context_salloc(context_t *context, u64 size)
{
return arena_alloc(&context->scratch, size);
}
void context_reset_read(context_t *context)
{
arena_reset(&context->read);
}
void context_reset_scratch(context_t *context)
{
arena_reset(&context->scratch);
}
void context_reset(context_t *context)
{
arena_reset(&context->memory);
arena_reset(&context->read);
arena_reset(&context->scratch);
}
void context_cleanup(context_t *context)
{
if (!context)
return;
arena_cleanup(&context->memory);
arena_cleanup(&context->read);
arena_cleanup(&context->scratch);
memset(context, 0, sizeof(*context));
}
void context_report(context_t *context)
{
#if DEBUG
// Figure this out at runtime
u64 mem_used = 0, mem_cap = 0;
for (page_t *page = context->memory.start; page; page = page->next)
{
mem_used += page->size;
mem_cap += page->capacity;
}
u64 read_used = 0, read_cap = 0;
for (page_t *page = context->read.start; page; page = page->next)
{
read_used += page->size;
read_cap += page->capacity;
}
u64 scr_used = 0, scr_cap = 0;
for (page_t *page = context->scratch.start; page; page = page->next)
{
scr_used += page->size;
scr_cap += page->capacity;
}
info("<Context>: %luB/%luB main memory used\n", mem_used, mem_cap);
info("<Context>: %luB/%luB read space used\n", read_used, read_cap);
info("<Context>: %luB/%luB scratch space used\n", scr_used, scr_cap);
#endif
}

38
lisp/context.h Normal file
View File

@@ -0,0 +1,38 @@
/* Copyright (C) 2025 Aryadev Chavali
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License Version 2
* for details.
* You may distribute and modify this code under the terms of the
* GNU General Public License Version 2, which you should have received a copy
of along with this
* program. If not, please go to <https://www.gnu.org/licenses/>.
* Created: 2025-05-12
* Description:
*/
#ifndef CONTEXT_H
#define CONTEXT_H
#include <lib/arena.h>
typedef struct Context
{
arena_t memory, read, scratch;
} context_t;
void *context_alloc(context_t *context, u64 size);
void *context_salloc(context_t *context, u64 size);
page_t *context_get_read_page(context_t *ctx);
void context_reset_read(context_t *context);
void context_reset_scratch(context_t *context);
void context_reset(context_t *context);
void context_cleanup(context_t *context);
void context_report(context_t *context);
#endif

View File

@@ -13,7 +13,7 @@
* Description: Evaluator implementation * Description: Evaluator implementation
*/ */
#include "./eval.h" #include <lisp/eval.h>
err_t eval(context_t *ctx, lisp_t *obj, lisp_t **ret) err_t eval(context_t *ctx, lisp_t *obj, lisp_t **ret)
{ {

View File

@@ -16,7 +16,7 @@
#ifndef EVAL_H #ifndef EVAL_H
#define EVAL_H #define EVAL_H
#include "./lisp.h" #include <lisp/lisp.h>
typedef enum typedef enum
{ {

View File

@@ -13,8 +13,8 @@
* Description: * Description:
*/ */
#include "./lisp.h" #include <lib/sv.h>
#include "./sv.h" #include <lisp/lisp.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
@@ -130,6 +130,13 @@ bool as_bool(lisp_t *obj)
return (bool)UNTAG(obj, BOOL); return (bool)UNTAG(obj, BOOL);
} }
f64 as_float(lisp_t *obj)
{
assert(IS_TAG(obj, FLOAT));
f64 *f = (f64 *)UNTAG(obj, FLOAT);
return f ? *f : 0;
}
vec_t *as_vec(lisp_t *obj) vec_t *as_vec(lisp_t *obj)
{ {
assert(IS_TAG(obj, VEC)); assert(IS_TAG(obj, VEC));
@@ -214,6 +221,19 @@ sv_t serialise(context_t *ctx, lisp_t *ptr)
, ,
as_bool(ptr) ? "#t" : "#f"); as_bool(ptr) ? "#t" : "#f");
} }
case TAG_FLOAT:
{
return sv_fmt(&ctx->scratch,
#if DEBUG > 1
"float["
#endif
"%lf"
#if DEBUG > 1
"]"
#endif
,
as_float(ptr));
}
case TAG_CONS: case TAG_CONS:
{ {
if (!CAR(ptr) && !CDR(ptr)) if (!CAR(ptr) && !CDR(ptr))

View File

@@ -16,11 +16,10 @@
#ifndef LISP_H #ifndef LISP_H
#define LISP_H #define LISP_H
#include "./base.h" #include <lib/sv.h>
#include "./memory.h" #include <lib/vec.h>
#include "./sv.h" #include <lisp/context.h>
#include "./tag.h" #include <lisp/tag.h>
#include "./vec.h"
typedef struct Cons typedef struct Cons
{ {
@@ -33,7 +32,6 @@ typedef struct Cell
u8 data[]; u8 data[];
} cell_t; } cell_t;
#define NIL 0
lisp_t *make_int(i64 integer); lisp_t *make_int(i64 integer);
lisp_t *make_sym(context_t *ctx, char *data, u64 size); lisp_t *make_sym(context_t *ctx, char *data, u64 size);
lisp_t *make_cons(context_t *ctx, lisp_t *car, lisp_t *cdr); lisp_t *make_cons(context_t *ctx, lisp_t *car, lisp_t *cdr);

View File

@@ -13,7 +13,7 @@
* Description: Implementation of parser * Description: Implementation of parser
*/ */
#include "./reader.h" #include <lisp/reader.h>
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
@@ -98,33 +98,38 @@ char input_next(input_t *input, u64 offset)
void input_skip(input_t *inp) void input_skip(input_t *inp)
{ {
// n + 2 lookup while (!input_eof(inp))
sv_t current = sv_cut(inp->str, inp->offset);
sv_t lookup = sv_chop(current, 2);
while ((!input_eof(inp) && is_space(lookup.data[0])) ||
lookup.data[0] == ';' || strncmp(lookup.data, "#|", 2) == 0)
{ {
if (lookup.data[0] == ';') sv_t current = sv_cut(inp->str, inp->offset);
// Skip any whitespace
inp->offset += sv_while(current, is_space);
current = sv_cut(inp->str, inp->offset);
// Is there a comment to skip?
if (current.size && current.data[0] == ';')
{ {
// Skip till newline
i64 newline = sv_find_subcstr(current, "\n", 1); i64 newline = sv_find_subcstr(current, "\n", 1);
if (newline < 0) if (newline < 0)
inp->offset = inp->str.size; inp->offset = inp->str.size;
else else
inp->offset += newline + 1; inp->offset += newline + 1;
// Then skip any whitespace
} }
else if (strncmp(lookup.data, "#|", 2) == 0) // Multiline comment to skip?
else if (current.size > 2 && strncmp(current.data, "#|", 2) == 0)
{ {
i64 offset = sv_find_subcstr(current, "|#", 2); i64 offset = sv_find_subcstr(current, "|#", 2);
if (offset < 0) if (offset < 0)
inp->offset = inp->str.size; inp->offset = inp->str.size;
else else
inp->offset += offset + 2; inp->offset += offset + 2;
// Then skip any whitespace
} }
// Nothing to skip, stop.
inp->offset += sv_while(sv_cut(inp->str, inp->offset), is_space); else
current = sv_cut(inp->str, inp->offset); break;
lookup = sv_chop(current, 2);
} }
return;
} }
perr_t parse_int(context_t *ctx, input_t *inp, lisp_t **ret) perr_t parse_int(context_t *ctx, input_t *inp, lisp_t **ret)
@@ -324,11 +329,13 @@ perr_t parse_reader_macro(context_t *ctx, input_t *inp, lisp_t **ret)
TODO("Not implemented reader macro for characters or weird bases"); TODO("Not implemented reader macro for characters or weird bases");
} }
else if (c == '(') else if (c == '(')
{
return parse_vec(ctx, inp, ret); return parse_vec(ctx, inp, ret);
}
else if (c == 't' || c == 'f') else if (c == 't' || c == 'f')
return parse_bool(ctx, inp, ret); return parse_bool(ctx, inp, ret);
else if (c == 'e')
{
// Scientific notation for floats
}
return PERR_UNEXPECTED_READER_MACRO_SYMBOL; return PERR_UNEXPECTED_READER_MACRO_SYMBOL;
} }

View File

@@ -16,9 +16,9 @@
#ifndef READER_H #ifndef READER_H
#define READER_H #define READER_H
#include "./lisp.h" #include <lib/vec.h>
#include "./memory.h" #include <lisp/context.h>
#include "./vec.h" #include <lisp/lisp.h>
#define INPUT_CHUNK_SIZE 512 #define INPUT_CHUNK_SIZE 512
static const char SYM_CHARS[] = static const char SYM_CHARS[] =

View File

@@ -13,8 +13,8 @@
* Description: * Description:
*/ */
#include <lisp/tag.h>
#include <string.h> #include <string.h>
#include <tag.h>
lisp_t *tag_int(i64 i) lisp_t *tag_int(i64 i)
{ {

View File

@@ -16,7 +16,7 @@
#ifndef TAG_H #ifndef TAG_H
#define TAG_H #define TAG_H
#include "./base.h" #include <base.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdlib.h> #include <stdlib.h>
@@ -25,18 +25,20 @@
// pointers // pointers
typedef struct Obj lisp_t; typedef struct Obj lisp_t;
#define NIL NULL
enum Tag enum Tag
{ {
TAG_NIL = 0b00000000, // Atomic types TAG_NIL = 0b00000000, // Atomic types
TAG_INT = 0b00000001, // special so we can encode 63 bit integers TAG_INT = 0b00000001, // special so we can encode 63 bit integers
TAG_SYM = 0b00000100, TAG_SYM = 0b00000100,
TAG_SSYM = 0b00001000, TAG_SSYM = 0b00001000,
TAG_CHAR = 0b00001100, TAG_CHAR = 0b00001100,
TAG_BOOL = 0b00010000, TAG_BOOL = 0b00010000,
// TAG_FLOAT = 0b00010100, TAG_FLOAT = 0b00010100,
TAG_CONS = 0b00000010, // Container types TAG_CONS = 0b00000010, // Container types
TAG_VEC = 0b00000110, TAG_VEC = 0b00000110,
TAG_STR = 0b00001010, TAG_STR = 0b00001010,
NUM_TAGS = 9, NUM_TAGS = 9,
}; };

24
main.c
View File

@@ -13,12 +13,10 @@
* Description: Entrypoint * Description: Entrypoint
*/ */
#include "./base.h" #include <lib/sv.h>
#include "./lisp.h" #include <lib/vec.h>
#include "./memory.h" #include <lisp/lisp.h>
#include "./reader.h" #include <lisp/reader.h>
#include "./sv.h"
#include "./vec.h"
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
@@ -27,6 +25,15 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
void usage(char *prog_name, FILE *fp)
{
fprintf(fp,
"Usage: %s [FILE]\n"
"Interpret FILE as scheme in the OATS interpreter.\n"
"\t[FILE]: name of file\n",
prog_name);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
int exit = 0; int exit = 0;
@@ -36,7 +43,10 @@ int main(int argc, char *argv[])
if (argc > 1) if (argc > 1)
filename = argv[1]; filename = argv[1];
else else
filename = "./r7rs-tests.scm"; {
usage(argv[0], stderr);
return 1;
}
FILE *fp = fopen(filename, "r"); FILE *fp = fopen(filename, "r");
if (!fp) if (!fp)