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:
19
Makefile
19
Makefile
@@ -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:
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -13,7 +13,7 @@
|
||||
* Description: String View implementation
|
||||
*/
|
||||
|
||||
#include "./sv.h"
|
||||
#include <lib/sv.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef SV_H
|
||||
#define SV_H
|
||||
|
||||
#include "./memory.h"
|
||||
#include <lib/arena.h>
|
||||
|
||||
typedef struct SV
|
||||
{
|
||||
@@ -13,7 +13,7 @@
|
||||
* Description: Vector implementation
|
||||
*/
|
||||
|
||||
#include "./vec.h"
|
||||
#include <lib/vec.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
@@ -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
92
lisp/context.c
Normal 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
38
lisp/context.h
Normal 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
|
||||
@@ -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)
|
||||
{
|
||||
@@ -16,7 +16,7 @@
|
||||
#ifndef EVAL_H
|
||||
#define EVAL_H
|
||||
|
||||
#include "./lisp.h"
|
||||
#include <lisp/lisp.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -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))
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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[] =
|
||||
@@ -13,8 +13,8 @@
|
||||
* Description:
|
||||
*/
|
||||
|
||||
#include <lisp/tag.h>
|
||||
#include <string.h>
|
||||
#include <tag.h>
|
||||
|
||||
lisp_t *tag_int(i64 i)
|
||||
{
|
||||
@@ -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
24
main.c
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user