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
OUT=oats.out
LIBS=-I.
INCLUDES=-I.
LIBS=
ARGS=
RELEASE=0
@@ -16,7 +17,7 @@ CFLAGS=$(GFLAGS) $(DFLAGS)
endif
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)
DEPDIR=$(DIST)/dependencies
DEPS:=$(SRC:%.c=$(DEPDIR)/%.d)
@@ -25,10 +26,10 @@ DEPS:=$(SRC:%.c=$(DEPDIR)/%.d)
all: $(DIST)/$(OUT)
$(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)
$(CC) $(CFLAGS) $^ -o $@ $(LIBS)
$(CC) $(INCLUDES) $(CFLAGS) $^ -o $@ $(LIBS)
.PHONY: run
run: $(DIST)/$(OUT)
@@ -38,11 +39,19 @@ run: $(DIST)/$(OUT)
clean:
rm -rfv $(DIST)/*
$(DIST):
$(DIST): | $(DIST)/lib $(DIST)/lisp
mkdir -p $(DIST)
$(DIST)/lib:
mkdir -p $(DIST)/lib
$(DIST)/lisp:
mkdir -p $(DIST)/lisp
$(DEPDIR):
mkdir -p $(DEPDIR)
mkdir -p $(DEPDIR)/lib
mkdir -p $(DEPDIR)/lisp
.PHONY:
watch:

View File

@@ -13,7 +13,7 @@
* Description: Implementations for memory models.
*/
#include "./memory.h"
#include <lib/arena.h>
#include <malloc.h>
#include <stdarg.h>
@@ -201,75 +201,3 @@ void arena_cleanup(arena_t *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/>.
* Created: 2025-04-05
* Description: Memory management structures
* Description: Arena
*/
#ifndef MEMORY_H
#define MEMORY_H
#ifndef ARENA_H
#define ARENA_H
#include "./base.h"
#include <base.h>
#include <stdio.h>
#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_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

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@
#ifndef VEC_H
#define VEC_H
#include "./memory.h"
#include <lib/arena.h>
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
*/
#include "./eval.h"
#include <lisp/eval.h>
err_t eval(context_t *ctx, lisp_t *obj, lisp_t **ret)
{

View File

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

View File

@@ -13,8 +13,8 @@
* Description:
*/
#include "./lisp.h"
#include "./sv.h"
#include <lib/sv.h>
#include <lisp/lisp.h>
#include <stdio.h>
#include <string.h>
@@ -130,6 +130,13 @@ bool as_bool(lisp_t *obj)
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)
{
assert(IS_TAG(obj, VEC));
@@ -214,6 +221,19 @@ sv_t serialise(context_t *ctx, lisp_t *ptr)
,
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:
{
if (!CAR(ptr) && !CDR(ptr))

View File

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

View File

@@ -13,7 +13,7 @@
* Description: Implementation of parser
*/
#include "./reader.h"
#include <lisp/reader.h>
#include <ctype.h>
#include <string.h>
@@ -98,33 +98,38 @@ char input_next(input_t *input, u64 offset)
void input_skip(input_t *inp)
{
// n + 2 lookup
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)
while (!input_eof(inp))
{
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);
if (newline < 0)
inp->offset = inp->str.size;
else
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);
if (offset < 0)
inp->offset = inp->str.size;
else
inp->offset += offset + 2;
// Then skip any whitespace
}
inp->offset += sv_while(sv_cut(inp->str, inp->offset), is_space);
current = sv_cut(inp->str, inp->offset);
lookup = sv_chop(current, 2);
// Nothing to skip, stop.
else
break;
}
return;
}
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");
}
else if (c == '(')
{
return parse_vec(ctx, inp, ret);
}
else if (c == 't' || c == 'f')
return parse_bool(ctx, inp, ret);
else if (c == 'e')
{
// Scientific notation for floats
}
return PERR_UNEXPECTED_READER_MACRO_SYMBOL;
}

View File

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

View File

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

View File

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

24
main.c
View File

@@ -13,12 +13,10 @@
* Description: Entrypoint
*/
#include "./base.h"
#include "./lisp.h"
#include "./memory.h"
#include "./reader.h"
#include "./sv.h"
#include "./vec.h"
#include <lib/sv.h>
#include <lib/vec.h>
#include <lisp/lisp.h>
#include <lisp/reader.h>
#include <assert.h>
#include <ctype.h>
@@ -27,6 +25,15 @@
#include <stdio.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 exit = 0;
@@ -36,7 +43,10 @@ int main(int argc, char *argv[])
if (argc > 1)
filename = argv[1];
else
filename = "./r7rs-tests.scm";
{
usage(argv[0], stderr);
return 1;
}
FILE *fp = fopen(filename, "r");
if (!fp)