Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Garbage collection now working.
- Loading branch information
Showing
with
22 additions
and
16 deletions.
-
+1
−4
README.md
-
+4
−2
src/builtins.c
-
+3
−2
src/expression.c
-
+10
−6
src/lexer.c
-
+4
−2
src/scope.c
|
@@ -15,14 +15,14 @@ A dumb lisp interpreter, made for practice. |
|
|
- [(lambda (arg-a arg-b ...) stmnt-a stmnt-b ...)](#lambda-arg-a-arg-b--stmnt-a-stmnt-b-) |
|
|
- [Arithmatic Operators (+, -, /, *)](#arithmatic-operators-----) |
|
|
- [Comparison Operators (=, <, >)](#comparison-operators---) |
|
|
- [TODO](#todo) |
|
|
|
|
|
<!-- END doctoc generated TOC please keep comment here to allow auto update --> |
|
|
|
|
|
## Features |
|
|
- A libreadline-based REPL |
|
|
- Create `lambda` functions with closures |
|
|
- Create macros |
|
|
- Garbage collection using the Boehm GC |
|
|
- It's dumb |
|
|
|
|
|
## Built-in Functions |
|
@@ -58,6 +58,3 @@ A dumb lisp interpreter, made for practice. |
|
|
### Arithmatic Operators (+, -, /, *) |
|
|
|
|
|
### Comparison Operators (=, <, >) |
|
|
|
|
|
## TODO |
|
|
- Garbage collection |
|
@@ -4,6 +4,8 @@ |
|
|
#include <assert.h> |
|
|
#include <string.h> |
|
|
|
|
|
#include "gc.h" |
|
|
|
|
|
/* HELPER FUNCTIONS */ |
|
|
|
|
|
static int len(expr *list) { |
|
@@ -416,7 +418,7 @@ expr *builtin_strcat(scope *scope, expr *arguments) { |
|
|
assert(a != NULL && a->type == STRING_EXPR); |
|
|
assert(b != NULL && b->type == STRING_EXPR); |
|
|
|
|
|
char *newstring = malloc(strlen(a->string_value) + strlen(b->string_value) + 1); |
|
|
char *newstring = GC_MALLOC_ATOMIC(strlen(a->string_value) + strlen(b->string_value) + 1); |
|
|
strcpy(newstring, a->string_value); |
|
|
strcat(newstring, b->string_value); |
|
|
|
|
@@ -436,7 +438,7 @@ expr *builtin_substr(scope *scope, expr *arguments) { |
|
|
assert(start->int_value >= 0 && start->int_value <= strlen(string->string_value)); |
|
|
assert(n->int_value >= 0 && start->int_value + n->int_value <= strlen(string->string_value)); |
|
|
|
|
|
char *newstring = malloc(n->int_value + 1); |
|
|
char *newstring = GC_MALLOC_ATOMIC(n->int_value + 1); |
|
|
strncpy(newstring, string->string_value + start->int_value, n->int_value); |
|
|
newstring[n->int_value] = '\0'; |
|
|
|
|
|
|
@@ -5,9 +5,10 @@ |
|
|
#include "assert.h" |
|
|
#include "emitter.h" |
|
|
|
|
|
#include "gc.h" |
|
|
|
|
|
static inline expr *make_expr() { |
|
|
expr *e = malloc(sizeof(expr)); |
|
|
memset(e, 0, sizeof(expr)); |
|
|
expr *e = GC_MALLOC(sizeof(expr)); |
|
|
return e; |
|
|
} |
|
|
|
|
|
|
@@ -5,6 +5,8 @@ |
|
|
#include <ctype.h> |
|
|
#include "stringpool.h" |
|
|
|
|
|
#include "gc.h" |
|
|
|
|
|
void create_file_lexer(lexing_context *ctx, const char *filename) { |
|
|
ctx->filename = filename; |
|
|
ctx->lineno = 1; |
|
@@ -54,12 +56,12 @@ static void advance_until_newline(lexing_context *ctx) { |
|
|
|
|
|
// Read a string literal, ending on a close-quote |
|
|
const char *read_string(lexing_context *ctx) { |
|
|
char literal[MAX_LITERAL_SIZE]; |
|
|
char buffer[MAX_LITERAL_SIZE]; |
|
|
int position = 0; |
|
|
while (true) { |
|
|
int c = get_char(ctx); |
|
|
if (c == '\"') { |
|
|
literal[position] = '\0'; |
|
|
buffer[position] = '\0'; |
|
|
break; |
|
|
} |
|
|
|
|
@@ -81,10 +83,12 @@ const char *read_string(lexing_context *ctx) { |
|
|
} |
|
|
} |
|
|
|
|
|
literal[position] = c; |
|
|
buffer[position] = c; |
|
|
++position; |
|
|
} |
|
|
return strdup(literal); |
|
|
char *literal = GC_MALLOC_ATOMIC(strlen(buffer) + 1); |
|
|
strcpy(literal, buffer); |
|
|
return literal; |
|
|
} |
|
|
|
|
|
bool is_validsymbolchar(char c) { |
|
@@ -137,7 +141,7 @@ bool is_letter(char c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') |
|
|
bool is_alphanumeric(char c) { return is_letter(c) || is_digit(c); } |
|
|
|
|
|
void unget_token(lexing_context *ctx, token_t *token) { |
|
|
token_t *new_token = malloc(sizeof(token_t)); |
|
|
token_t *new_token = GC_MALLOC(sizeof(token_t)); |
|
|
memcpy(new_token, token, sizeof(token_t)); |
|
|
new_token->next = ctx->stack; |
|
|
ctx->stack = new_token; |
|
@@ -149,7 +153,7 @@ void get_next_token(lexing_context *ctx, token_t *token) { |
|
|
token_t *next_tok = ctx->stack; |
|
|
ctx->stack = next_tok->next; |
|
|
memcpy(token, next_tok, sizeof(token_t)); |
|
|
free(next_tok); |
|
|
GC_FREE(next_tok); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
@@ -3,6 +3,8 @@ |
|
|
#include "stdlib.h" |
|
|
#include "string.h" |
|
|
|
|
|
#include "gc.h" |
|
|
|
|
|
struct expr *scope_lookup(struct scope *scope, const char *symbol) { |
|
|
for (struct scope *curr = scope; curr != NULL; curr = curr->parent) { |
|
|
struct expr *e = scope_probe(curr, symbol); |
|
@@ -22,14 +24,14 @@ struct expr *scope_probe(struct scope *scope, const char *symbol) { |
|
|
} |
|
|
|
|
|
struct scope *scope_create(struct scope *parent) { |
|
|
struct scope *scope = malloc(sizeof(struct scope)); |
|
|
struct scope *scope = GC_MALLOC(sizeof(struct scope)); |
|
|
scope->parent = parent; |
|
|
scope->mappings = NULL; |
|
|
return scope; |
|
|
} |
|
|
|
|
|
void scope_add_mapping(struct scope *scope, const char *symbol, struct expr *value) { |
|
|
struct mapping *m = malloc(sizeof(struct mapping)); |
|
|
struct mapping *m = GC_MALLOC(sizeof(struct mapping)); |
|
|
m->symbol = symbol; |
|
|
m->value = value; |
|
|
|
|
|