initial commit
This commit is contained in:
commit
fdd1ee61b5
24 changed files with 5284 additions and 0 deletions
7
.editorconfig
Normal file
7
.editorconfig
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
root = true
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
[*.{c,h,grr}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
*.o
|
||||
.cache
|
||||
/growl
|
||||
/.envrc
|
||||
/compile_commands.json
|
||||
11
README
Normal file
11
README
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
.
|
||||
/ V\
|
||||
/ ` /
|
||||
<< |
|
||||
/ | Growl
|
||||
/ | A concatenative programming language.
|
||||
/ |
|
||||
/ \ \ /
|
||||
( ) | |
|
||||
________| _/_ | |
|
||||
<__________\______)\__)
|
||||
29
chunk.c
Normal file
29
chunk.c
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#include "chunk.h"
|
||||
#include "vendor/yar.h"
|
||||
|
||||
V chunk_emit_byte(Bc *chunk, U8 byte) { *yar_append(chunk) = byte; }
|
||||
|
||||
V chunk_emit_sleb128(Bc *chunk, I num) {
|
||||
I more = 1;
|
||||
while (more) {
|
||||
U8 byte = num & 0x7f;
|
||||
num >>= 7;
|
||||
if ((num == 0 && !(byte & 0x40)) || (num == -1 && (byte & 0x40))) {
|
||||
more = 0;
|
||||
} else {
|
||||
byte |= 0x80;
|
||||
}
|
||||
chunk_emit_byte(chunk, byte);
|
||||
}
|
||||
}
|
||||
|
||||
I chunk_add_constant(Bc *chunk, O value) {
|
||||
I mark = chunk->constants.count;
|
||||
*yar_append(&chunk->constants) = value;
|
||||
return mark;
|
||||
}
|
||||
|
||||
V chunk_free(Bc *chunk) {
|
||||
yar_free(&chunk->constants);
|
||||
yar_free(chunk);
|
||||
}
|
||||
22
chunk.h
Normal file
22
chunk.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef CHUNK_H
|
||||
#define CHUNK_H
|
||||
|
||||
#include "common.h"
|
||||
#include "object.h"
|
||||
|
||||
/** Bytecode chunk */
|
||||
typedef struct Bc {
|
||||
U8 *items;
|
||||
Z count, capacity;
|
||||
struct {
|
||||
O *items;
|
||||
Z count, capacity;
|
||||
} constants;
|
||||
} Bc;
|
||||
|
||||
V chunk_emit_byte(Bc *, U8);
|
||||
V chunk_emit_sleb128(Bc *, I);
|
||||
I chunk_add_constant(Bc *, O);
|
||||
V chunk_free(Bc *);
|
||||
|
||||
#endif
|
||||
15
common.h
Normal file
15
common.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void V;
|
||||
typedef intptr_t I;
|
||||
typedef uintptr_t U;
|
||||
typedef double F;
|
||||
typedef size_t Z;
|
||||
typedef uint8_t U8;
|
||||
typedef uint32_t U32;
|
||||
|
||||
#endif
|
||||
126
gc.c
Normal file
126
gc.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gc.h"
|
||||
#include "vendor/yar.h"
|
||||
|
||||
#define ALIGN(n) (((n) + 7) & ~7)
|
||||
static inline int infrom(Gc *gc, V *ptr) {
|
||||
const U8 *x = (const U8 *)ptr;
|
||||
return (x >= gc->from.start && x < gc->from.end);
|
||||
}
|
||||
|
||||
V gc_addroot(Gc *gc, O *ptr) { *yar_append(&gc->roots) = ptr; }
|
||||
I gc_mark(Gc *gc) { return gc->roots.count; }
|
||||
V gc_reset(Gc *gc, I mark) { gc->roots.count = mark; }
|
||||
|
||||
static O copy(Gc *gc, Hd *hdr) {
|
||||
assert(infrom(gc, hdr));
|
||||
assert(hdr->type != TYPE_FWD);
|
||||
|
||||
Z sz = ALIGN(hdr->size);
|
||||
Hd *new = (Hd *)gc->to.free;
|
||||
gc->to.free += sz;
|
||||
memcpy(new, hdr, sz);
|
||||
|
||||
hdr->type = TYPE_FWD;
|
||||
O *obj = (O *)(hdr + 1);
|
||||
*obj = BOX(new);
|
||||
return *obj;
|
||||
}
|
||||
|
||||
static O forward(Gc *gc, O obj) {
|
||||
if (obj == 0)
|
||||
return 0;
|
||||
if (IMM(obj))
|
||||
return obj;
|
||||
if (!infrom(gc, (V *)obj))
|
||||
return obj;
|
||||
|
||||
Hd *hdr = UNBOX(obj);
|
||||
if (hdr->type == TYPE_FWD) {
|
||||
O *o = (O *)(hdr + 1);
|
||||
return *o;
|
||||
} else {
|
||||
return copy(gc, hdr);
|
||||
}
|
||||
}
|
||||
|
||||
#if GC_DEBUG
|
||||
static V printstats(Gc *gc, const char *label) {
|
||||
Z used = (Z)(gc->from.free - gc->from.start);
|
||||
fprintf(stderr, "[%s] used=%zu/%zu bytes (%.1f%%)\n", label, used,
|
||||
(Z)HEAP_BYTES, (F)used / (F)HEAP_BYTES * 100.0);
|
||||
}
|
||||
#endif
|
||||
|
||||
V gc_collect(Gc *gc) {
|
||||
uint8_t *scan = gc->to.free;
|
||||
|
||||
#if GC_DEBUG
|
||||
printstats(gc, "before GC");
|
||||
#endif
|
||||
|
||||
for (Z i = 0; i < gc->roots.count; i++) {
|
||||
O *o = gc->roots.items[i];
|
||||
*o = forward(gc, *o);
|
||||
}
|
||||
|
||||
while (scan < gc->to.free) {
|
||||
if (scan >= gc->to.end) {
|
||||
fprintf(stderr, "fatal GC error: out of memory\n");
|
||||
abort();
|
||||
}
|
||||
Hd *hdr = (Hd *)scan;
|
||||
switch (hdr->type) {
|
||||
// TODO: the rest of the owl
|
||||
case TYPE_FWD:
|
||||
fprintf(stderr, "fatal GC error: forwarding pointer in to-space\n");
|
||||
abort();
|
||||
default:
|
||||
fprintf(stderr, "GC warning: junk object type %" PRId32 "\n", hdr->type);
|
||||
}
|
||||
scan += ALIGN(hdr->size);
|
||||
}
|
||||
|
||||
Gs tmp = gc->from;
|
||||
gc->from = gc->to;
|
||||
gc->to = tmp;
|
||||
gc->to.free = gc->to.start;
|
||||
|
||||
#if GC_DEBUG
|
||||
printstats(gc, "after GC");
|
||||
#endif
|
||||
}
|
||||
|
||||
void gc_init(Gc *gc) {
|
||||
gc->from.start = malloc(HEAP_BYTES);
|
||||
if (!gc->from.start)
|
||||
goto fatal;
|
||||
gc->from.end = gc->from.start + HEAP_BYTES;
|
||||
gc->from.free = gc->from.start;
|
||||
|
||||
gc->to.start = malloc(HEAP_BYTES);
|
||||
if (!gc->to.start)
|
||||
goto fatal;
|
||||
gc->to.end = gc->to.start + HEAP_BYTES;
|
||||
gc->to.free = gc->to.start;
|
||||
|
||||
gc->roots.capacity = 0;
|
||||
gc->roots.count = 0;
|
||||
gc->roots.items = NULL;
|
||||
return;
|
||||
|
||||
fatal:
|
||||
fprintf(stderr, "failed to allocate heap space\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
void gc_deinit(Gc *gc) {
|
||||
gc_collect(gc);
|
||||
free(gc->from.start);
|
||||
free(gc->to.start);
|
||||
yar_free(&gc->roots);
|
||||
}
|
||||
31
gc.h
Normal file
31
gc.h
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
#ifndef GC_H
|
||||
#define GC_H
|
||||
|
||||
#include "common.h"
|
||||
#include "object.h"
|
||||
|
||||
#define GC_DEBUG 1
|
||||
#define HEAP_BYTES (4 * 1024 * 1024)
|
||||
|
||||
typedef struct Gs {
|
||||
U8 *start, *end;
|
||||
U8 *free;
|
||||
} Gs;
|
||||
|
||||
typedef struct Gc {
|
||||
Gs from, to;
|
||||
struct {
|
||||
O **items;
|
||||
Z count, capacity;
|
||||
} roots;
|
||||
} Gc;
|
||||
|
||||
V gc_addroot(Gc *, O *);
|
||||
I gc_mark(Gc *);
|
||||
V gc_reset(Gc *, I);
|
||||
V gc_collect(Gc *);
|
||||
Hd *gc_alloc(Gc *, Z);
|
||||
V gc_init(Gc *);
|
||||
V gc_deinit(Gc *);
|
||||
|
||||
#endif
|
||||
89
main.c
Normal file
89
main.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "chunk.h"
|
||||
#include "gc.h"
|
||||
#include "parser.h"
|
||||
#include "vendor/mpc.h"
|
||||
#include "vm.h"
|
||||
|
||||
void dump(const V *data, Z size) {
|
||||
char ascii[17];
|
||||
Z i, j;
|
||||
ascii[16] = '\0';
|
||||
for (i = 0; i < size; ++i) {
|
||||
printf("%02X ", ((unsigned char *)data)[i]);
|
||||
if (((unsigned char *)data)[i] >= ' ' &&
|
||||
((unsigned char *)data)[i] <= '~') {
|
||||
ascii[i % 16] = ((unsigned char *)data)[i];
|
||||
} else {
|
||||
ascii[i % 16] = '.';
|
||||
}
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size) {
|
||||
printf(" ");
|
||||
if ((i + 1) % 16 == 0) {
|
||||
printf("| %s \n", ascii);
|
||||
} else if (i + 1 == size) {
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
if ((i + 1) % 16 <= 8) {
|
||||
printf(" ");
|
||||
}
|
||||
for (j = (i + 1) % 16; j < 16; ++j) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("| %s \n", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
I repl(void) {
|
||||
Bc chunk = {0};
|
||||
Vm vm = {0};
|
||||
|
||||
vm_init(&vm);
|
||||
|
||||
I idx = chunk_add_constant(&chunk, NUM(10));
|
||||
chunk_emit_byte(&chunk, OP_CONST);
|
||||
chunk_emit_sleb128(&chunk, idx);
|
||||
chunk_emit_byte(&chunk, OP_RETURN);
|
||||
|
||||
vm_run(&vm, &chunk, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
I loadfile(const char *fname) {
|
||||
Gc gc = {0};
|
||||
gc_init(&gc);
|
||||
|
||||
mpc_result_t res;
|
||||
if (!mpc_parse_contents(fname, Program, &res)) {
|
||||
mpc_err_print_to(res.error, stderr);
|
||||
mpc_err_delete(res.error);
|
||||
gc_deinit(&gc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
mpc_ast_print(res.output);
|
||||
mpc_ast_delete(res.output);
|
||||
gc_deinit(&gc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
parser_init();
|
||||
atexit(parser_deinit);
|
||||
|
||||
switch (argc) {
|
||||
case 1:
|
||||
return repl();
|
||||
case 2:
|
||||
return loadfile(argv[1]);
|
||||
default:
|
||||
fprintf(stderr, "usage: growl [file]\n");
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
11
makefile
Normal file
11
makefile
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
CC := cc
|
||||
CFLAGS := -Og -g -std=c99 -Wpedantic -Wall
|
||||
OBJS = chunk.o gc.o main.o object.o parser.o print.o vm.o vendor/mpc.o \
|
||||
vendor/yar.o
|
||||
|
||||
growl: $(OBJS)
|
||||
$(CC) -o growl $(OBJS)
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f growl $(OBJS)
|
||||
0
object.c
Normal file
0
object.c
Normal file
24
object.h
Normal file
24
object.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#ifndef OBJECT_H
|
||||
#define OBJECT_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#define NIL ((O)0)
|
||||
#define BOX(x) ((O)(x))
|
||||
#define UNBOX(x) ((Hd *)(x))
|
||||
#define IMM(x) ((O)(x) & (O)1)
|
||||
#define NUM(x) (((O)((intptr_t)(x) << 1)) | (O)1)
|
||||
#define ORD(x) ((O)(x) >> 1)
|
||||
|
||||
enum {
|
||||
TYPE_FWD,
|
||||
};
|
||||
|
||||
typedef uintptr_t O;
|
||||
|
||||
/** Object header */
|
||||
typedef struct Hd {
|
||||
U32 size, type;
|
||||
} Hd;
|
||||
|
||||
#endif
|
||||
51
parser.c
Normal file
51
parser.c
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
#include "parser.h"
|
||||
#include "vendor/mpc.h"
|
||||
|
||||
mpc_parser_t *Pragma, *Comment, *Expr, *Number, *String, *Word, *Definition,
|
||||
*Command, *List, *Table, *Quotation, *Program;
|
||||
|
||||
V parser_init(V) {
|
||||
Pragma = mpc_new("pragma");
|
||||
Comment = mpc_new("comment");
|
||||
Expr = mpc_new("expr");
|
||||
Number = mpc_new("number");
|
||||
String = mpc_new("string");
|
||||
Word = mpc_new("word");
|
||||
Definition = mpc_new("def");
|
||||
Command = mpc_new("command");
|
||||
List = mpc_new("list");
|
||||
Table = mpc_new("table");
|
||||
Quotation = mpc_new("quotation");
|
||||
Program = mpc_new("program");
|
||||
|
||||
mpc_err_t *err = mpca_lang(
|
||||
MPCA_LANG_DEFAULT,
|
||||
" pragma : '#' <word> ('(' <expr>* ')')? ; "
|
||||
" comment : /\\\\[^\\n]*/ ; "
|
||||
" expr : ( <pragma> | <def> | <command> | <quotation> "
|
||||
" | <number> | <list> | <table> | <string> "
|
||||
" | <word> | <comment> ) ; "
|
||||
" number : ( /0x[0-9A-Fa-f]+/ | /-?[0-9]+/ ) ; "
|
||||
" string : /\"(\\\\.|[^\"])*\"/ ; "
|
||||
" word : /[a-zA-Z0-9_!.,@#$%^&*_+\\-=><|\\/]+/ ; "
|
||||
" def : ':' <word> <expr>* ';' ; "
|
||||
" command : <word> ':' <expr>+ ';' ; "
|
||||
" list : '(' <expr>* ')' ; "
|
||||
" table : '{' <expr>* '}' ; "
|
||||
" quotation : '[' <expr>* ']' ; "
|
||||
" program : /^/ <expr>* /$/ ; ",
|
||||
Pragma, Comment, Expr, Number, String, Word, Definition, Command, List,
|
||||
Table, Quotation, Program, NULL);
|
||||
|
||||
// crash if i do a woopsie
|
||||
if (err != NULL) {
|
||||
mpc_err_print(err);
|
||||
mpc_err_delete(err);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
V parser_deinit(V) {
|
||||
mpc_cleanup(12, Pragma, Comment, Expr, Number, String, Word, Definition,
|
||||
Command, List, Table, Quotation, Program);
|
||||
}
|
||||
13
parser.h
Normal file
13
parser.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef PARSER_H
|
||||
#define PARSER_H
|
||||
|
||||
#include "common.h"
|
||||
#include "vendor/mpc.h"
|
||||
|
||||
|
||||
V parser_init(V);
|
||||
V parser_deinit(V);
|
||||
|
||||
extern mpc_parser_t *Program;
|
||||
|
||||
#endif
|
||||
0
print.c
Normal file
0
print.c
Normal file
0
print.h
Normal file
0
print.h
Normal file
7
shell.nix
Normal file
7
shell.nix
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = with pkgs; [
|
||||
clang-tools bear gdb tinycc
|
||||
];
|
||||
}
|
||||
3
test.grr
Normal file
3
test.grr
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
\ This is a comment.
|
||||
|
||||
: when [] if ;
|
||||
4128
vendor/mpc.c
vendored
Normal file
4128
vendor/mpc.c
vendored
Normal file
File diff suppressed because it is too large
Load diff
391
vendor/mpc.h
vendored
Normal file
391
vendor/mpc.h
vendored
Normal file
|
|
@ -0,0 +1,391 @@
|
|||
/*
|
||||
** mpc - Micro Parser Combinator library for C
|
||||
**
|
||||
** https://github.com/orangeduck/mpc
|
||||
**
|
||||
** Daniel Holden - contact@daniel-holden.com
|
||||
** Licensed under BSD3
|
||||
*/
|
||||
|
||||
#ifndef mpc_h
|
||||
#define mpc_h
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/*
|
||||
** State Type
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
long pos;
|
||||
long row;
|
||||
long col;
|
||||
int term;
|
||||
} mpc_state_t;
|
||||
|
||||
/*
|
||||
** Error Type
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
mpc_state_t state;
|
||||
int expected_num;
|
||||
char *filename;
|
||||
char *failure;
|
||||
char **expected;
|
||||
char received;
|
||||
} mpc_err_t;
|
||||
|
||||
void mpc_err_delete(mpc_err_t *e);
|
||||
char *mpc_err_string(mpc_err_t *e);
|
||||
void mpc_err_print(mpc_err_t *e);
|
||||
void mpc_err_print_to(mpc_err_t *e, FILE *f);
|
||||
|
||||
/*
|
||||
** Parsing
|
||||
*/
|
||||
|
||||
typedef void mpc_val_t;
|
||||
|
||||
typedef union {
|
||||
mpc_err_t *error;
|
||||
mpc_val_t *output;
|
||||
} mpc_result_t;
|
||||
|
||||
struct mpc_parser_t;
|
||||
typedef struct mpc_parser_t mpc_parser_t;
|
||||
|
||||
int mpc_parse(const char *filename, const char *string, mpc_parser_t *p, mpc_result_t *r);
|
||||
int mpc_nparse(const char *filename, const char *string, size_t length, mpc_parser_t *p, mpc_result_t *r);
|
||||
int mpc_parse_file(const char *filename, FILE *file, mpc_parser_t *p, mpc_result_t *r);
|
||||
int mpc_parse_pipe(const char *filename, FILE *pipe, mpc_parser_t *p, mpc_result_t *r);
|
||||
int mpc_parse_contents(const char *filename, mpc_parser_t *p, mpc_result_t *r);
|
||||
|
||||
/*
|
||||
** Function Types
|
||||
*/
|
||||
|
||||
typedef void(*mpc_dtor_t)(mpc_val_t*);
|
||||
typedef mpc_val_t*(*mpc_ctor_t)(void);
|
||||
|
||||
typedef mpc_val_t*(*mpc_apply_t)(mpc_val_t*);
|
||||
typedef mpc_val_t*(*mpc_apply_to_t)(mpc_val_t*,void*);
|
||||
typedef mpc_val_t*(*mpc_fold_t)(int,mpc_val_t**);
|
||||
|
||||
typedef int(*mpc_check_t)(mpc_val_t**);
|
||||
typedef int(*mpc_check_with_t)(mpc_val_t**,void*);
|
||||
|
||||
/*
|
||||
** Building a Parser
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_new(const char *name);
|
||||
mpc_parser_t *mpc_copy(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_define(mpc_parser_t *p, mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_undefine(mpc_parser_t *p);
|
||||
|
||||
void mpc_delete(mpc_parser_t *p);
|
||||
void mpc_cleanup(int n, ...);
|
||||
|
||||
/*
|
||||
** Basic Parsers
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_any(void);
|
||||
mpc_parser_t *mpc_char(char c);
|
||||
mpc_parser_t *mpc_range(char s, char e);
|
||||
mpc_parser_t *mpc_oneof(const char *s);
|
||||
mpc_parser_t *mpc_noneof(const char *s);
|
||||
mpc_parser_t *mpc_satisfy(int(*f)(char));
|
||||
mpc_parser_t *mpc_string(const char *s);
|
||||
|
||||
/*
|
||||
** Other Parsers
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_pass(void);
|
||||
mpc_parser_t *mpc_fail(const char *m);
|
||||
mpc_parser_t *mpc_failf(const char *fmt, ...);
|
||||
mpc_parser_t *mpc_lift(mpc_ctor_t f);
|
||||
mpc_parser_t *mpc_lift_val(mpc_val_t *x);
|
||||
mpc_parser_t *mpc_anchor(int(*f)(char,char));
|
||||
mpc_parser_t *mpc_state(void);
|
||||
|
||||
/*
|
||||
** Combinator Parsers
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_expect(mpc_parser_t *a, const char *e);
|
||||
mpc_parser_t *mpc_expectf(mpc_parser_t *a, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_apply(mpc_parser_t *a, mpc_apply_t f);
|
||||
mpc_parser_t *mpc_apply_to(mpc_parser_t *a, mpc_apply_to_t f, void *x);
|
||||
mpc_parser_t *mpc_check(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *e);
|
||||
mpc_parser_t *mpc_check_with(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *e);
|
||||
mpc_parser_t *mpc_checkf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_t f, const char *fmt, ...);
|
||||
mpc_parser_t *mpc_check_withf(mpc_parser_t *a, mpc_dtor_t da, mpc_check_with_t f, void *x, const char *fmt, ...);
|
||||
|
||||
mpc_parser_t *mpc_not(mpc_parser_t *a, mpc_dtor_t da);
|
||||
mpc_parser_t *mpc_not_lift(mpc_parser_t *a, mpc_dtor_t da, mpc_ctor_t lf);
|
||||
mpc_parser_t *mpc_maybe(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_maybe_lift(mpc_parser_t *a, mpc_ctor_t lf);
|
||||
|
||||
mpc_parser_t *mpc_many(mpc_fold_t f, mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_many1(mpc_fold_t f, mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_count(int n, mpc_fold_t f, mpc_parser_t *a, mpc_dtor_t da);
|
||||
|
||||
mpc_parser_t *mpc_or(int n, ...);
|
||||
mpc_parser_t *mpc_and(int n, mpc_fold_t f, ...);
|
||||
|
||||
mpc_parser_t *mpc_predictive(mpc_parser_t *a);
|
||||
|
||||
/*
|
||||
** Common Parsers
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_eoi(void);
|
||||
mpc_parser_t *mpc_soi(void);
|
||||
|
||||
mpc_parser_t *mpc_boundary(void);
|
||||
mpc_parser_t *mpc_boundary_newline(void);
|
||||
|
||||
mpc_parser_t *mpc_whitespace(void);
|
||||
mpc_parser_t *mpc_whitespaces(void);
|
||||
mpc_parser_t *mpc_blank(void);
|
||||
|
||||
mpc_parser_t *mpc_newline(void);
|
||||
mpc_parser_t *mpc_tab(void);
|
||||
mpc_parser_t *mpc_escape(void);
|
||||
|
||||
mpc_parser_t *mpc_digit(void);
|
||||
mpc_parser_t *mpc_hexdigit(void);
|
||||
mpc_parser_t *mpc_octdigit(void);
|
||||
mpc_parser_t *mpc_digits(void);
|
||||
mpc_parser_t *mpc_hexdigits(void);
|
||||
mpc_parser_t *mpc_octdigits(void);
|
||||
|
||||
mpc_parser_t *mpc_lower(void);
|
||||
mpc_parser_t *mpc_upper(void);
|
||||
mpc_parser_t *mpc_alpha(void);
|
||||
mpc_parser_t *mpc_underscore(void);
|
||||
mpc_parser_t *mpc_alphanum(void);
|
||||
|
||||
mpc_parser_t *mpc_int(void);
|
||||
mpc_parser_t *mpc_hex(void);
|
||||
mpc_parser_t *mpc_oct(void);
|
||||
mpc_parser_t *mpc_number(void);
|
||||
|
||||
mpc_parser_t *mpc_real(void);
|
||||
mpc_parser_t *mpc_float(void);
|
||||
|
||||
mpc_parser_t *mpc_char_lit(void);
|
||||
mpc_parser_t *mpc_string_lit(void);
|
||||
mpc_parser_t *mpc_regex_lit(void);
|
||||
|
||||
mpc_parser_t *mpc_ident(void);
|
||||
|
||||
/*
|
||||
** Useful Parsers
|
||||
*/
|
||||
|
||||
mpc_parser_t *mpc_startwith(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_endwith(mpc_parser_t *a, mpc_dtor_t da);
|
||||
mpc_parser_t *mpc_whole(mpc_parser_t *a, mpc_dtor_t da);
|
||||
|
||||
mpc_parser_t *mpc_stripl(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_stripr(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_strip(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_tok(mpc_parser_t *a);
|
||||
mpc_parser_t *mpc_sym(const char *s);
|
||||
mpc_parser_t *mpc_total(mpc_parser_t *a, mpc_dtor_t da);
|
||||
|
||||
mpc_parser_t *mpc_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);
|
||||
mpc_parser_t *mpc_parens(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_braces(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_brackets(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_squares(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
|
||||
mpc_parser_t *mpc_tok_between(mpc_parser_t *a, mpc_dtor_t ad, const char *o, const char *c);
|
||||
mpc_parser_t *mpc_tok_parens(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_tok_braces(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_tok_brackets(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
mpc_parser_t *mpc_tok_squares(mpc_parser_t *a, mpc_dtor_t ad);
|
||||
|
||||
mpc_parser_t *mpc_sepby1(mpc_fold_t f, mpc_parser_t *sep, mpc_parser_t *a);
|
||||
|
||||
/*
|
||||
** Common Function Parameters
|
||||
*/
|
||||
|
||||
void mpcf_dtor_null(mpc_val_t *x);
|
||||
|
||||
mpc_val_t *mpcf_ctor_null(void);
|
||||
mpc_val_t *mpcf_ctor_str(void);
|
||||
|
||||
mpc_val_t *mpcf_free(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_int(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_hex(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_oct(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_float(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_strtriml(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_strtrimr(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_strtrim(mpc_val_t *x);
|
||||
|
||||
mpc_val_t *mpcf_escape(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_escape_regex(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_escape_string_raw(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_escape_char_raw(mpc_val_t *x);
|
||||
|
||||
mpc_val_t *mpcf_unescape(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_unescape_regex(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_unescape_string_raw(mpc_val_t *x);
|
||||
mpc_val_t *mpcf_unescape_char_raw(mpc_val_t *x);
|
||||
|
||||
mpc_val_t *mpcf_null(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_fst(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_snd(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_trd(int n, mpc_val_t** xs);
|
||||
|
||||
mpc_val_t *mpcf_fst_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_snd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_trd_free(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_all_free(int n, mpc_val_t** xs);
|
||||
|
||||
mpc_val_t *mpcf_freefold(int n, mpc_val_t** xs);
|
||||
mpc_val_t *mpcf_strfold(int n, mpc_val_t** xs);
|
||||
|
||||
/*
|
||||
** Regular Expression Parsers
|
||||
*/
|
||||
|
||||
enum {
|
||||
MPC_RE_DEFAULT = 0,
|
||||
MPC_RE_M = 1,
|
||||
MPC_RE_S = 2,
|
||||
MPC_RE_MULTILINE = 1,
|
||||
MPC_RE_DOTALL = 2
|
||||
};
|
||||
|
||||
mpc_parser_t *mpc_re(const char *re);
|
||||
mpc_parser_t *mpc_re_mode(const char *re, int mode);
|
||||
|
||||
/*
|
||||
** AST
|
||||
*/
|
||||
|
||||
typedef struct mpc_ast_t {
|
||||
char *tag;
|
||||
char *contents;
|
||||
mpc_state_t state;
|
||||
int children_num;
|
||||
struct mpc_ast_t** children;
|
||||
} mpc_ast_t;
|
||||
|
||||
mpc_ast_t *mpc_ast_new(const char *tag, const char *contents);
|
||||
mpc_ast_t *mpc_ast_build(int n, const char *tag, ...);
|
||||
mpc_ast_t *mpc_ast_add_root(mpc_ast_t *a);
|
||||
mpc_ast_t *mpc_ast_add_child(mpc_ast_t *r, mpc_ast_t *a);
|
||||
mpc_ast_t *mpc_ast_add_tag(mpc_ast_t *a, const char *t);
|
||||
mpc_ast_t *mpc_ast_add_root_tag(mpc_ast_t *a, const char *t);
|
||||
mpc_ast_t *mpc_ast_tag(mpc_ast_t *a, const char *t);
|
||||
mpc_ast_t *mpc_ast_state(mpc_ast_t *a, mpc_state_t s);
|
||||
|
||||
void mpc_ast_delete(mpc_ast_t *a);
|
||||
void mpc_ast_print(mpc_ast_t *a);
|
||||
void mpc_ast_print_to(mpc_ast_t *a, FILE *fp);
|
||||
|
||||
int mpc_ast_get_index(mpc_ast_t *ast, const char *tag);
|
||||
int mpc_ast_get_index_lb(mpc_ast_t *ast, const char *tag, int lb);
|
||||
mpc_ast_t *mpc_ast_get_child(mpc_ast_t *ast, const char *tag);
|
||||
mpc_ast_t *mpc_ast_get_child_lb(mpc_ast_t *ast, const char *tag, int lb);
|
||||
|
||||
typedef enum {
|
||||
mpc_ast_trav_order_pre,
|
||||
mpc_ast_trav_order_post
|
||||
} mpc_ast_trav_order_t;
|
||||
|
||||
typedef struct mpc_ast_trav_t {
|
||||
mpc_ast_t *curr_node;
|
||||
struct mpc_ast_trav_t *parent;
|
||||
int curr_child;
|
||||
mpc_ast_trav_order_t order;
|
||||
} mpc_ast_trav_t;
|
||||
|
||||
mpc_ast_trav_t *mpc_ast_traverse_start(mpc_ast_t *ast,
|
||||
mpc_ast_trav_order_t order);
|
||||
|
||||
mpc_ast_t *mpc_ast_traverse_next(mpc_ast_trav_t **trav);
|
||||
|
||||
void mpc_ast_traverse_free(mpc_ast_trav_t **trav);
|
||||
|
||||
/*
|
||||
** Warning: This function currently doesn't test for equality of the `state` member!
|
||||
*/
|
||||
int mpc_ast_eq(mpc_ast_t *a, mpc_ast_t *b);
|
||||
|
||||
mpc_val_t *mpcf_fold_ast(int n, mpc_val_t **as);
|
||||
mpc_val_t *mpcf_str_ast(mpc_val_t *c);
|
||||
mpc_val_t *mpcf_state_ast(int n, mpc_val_t **xs);
|
||||
|
||||
mpc_parser_t *mpca_tag(mpc_parser_t *a, const char *t);
|
||||
mpc_parser_t *mpca_add_tag(mpc_parser_t *a, const char *t);
|
||||
mpc_parser_t *mpca_root(mpc_parser_t *a);
|
||||
mpc_parser_t *mpca_state(mpc_parser_t *a);
|
||||
mpc_parser_t *mpca_total(mpc_parser_t *a);
|
||||
|
||||
mpc_parser_t *mpca_not(mpc_parser_t *a);
|
||||
mpc_parser_t *mpca_maybe(mpc_parser_t *a);
|
||||
|
||||
mpc_parser_t *mpca_many(mpc_parser_t *a);
|
||||
mpc_parser_t *mpca_many1(mpc_parser_t *a);
|
||||
mpc_parser_t *mpca_count(int n, mpc_parser_t *a);
|
||||
|
||||
mpc_parser_t *mpca_or(int n, ...);
|
||||
mpc_parser_t *mpca_and(int n, ...);
|
||||
|
||||
enum {
|
||||
MPCA_LANG_DEFAULT = 0,
|
||||
MPCA_LANG_PREDICTIVE = 1,
|
||||
MPCA_LANG_WHITESPACE_SENSITIVE = 2
|
||||
};
|
||||
|
||||
mpc_parser_t *mpca_grammar(int flags, const char *grammar, ...);
|
||||
|
||||
mpc_err_t *mpca_lang(int flags, const char *language, ...);
|
||||
mpc_err_t *mpca_lang_file(int flags, FILE *f, ...);
|
||||
mpc_err_t *mpca_lang_pipe(int flags, FILE *f, ...);
|
||||
mpc_err_t *mpca_lang_contents(int flags, const char *filename, ...);
|
||||
|
||||
/*
|
||||
** Misc
|
||||
*/
|
||||
|
||||
|
||||
void mpc_print(mpc_parser_t *p);
|
||||
void mpc_optimise(mpc_parser_t *p);
|
||||
void mpc_stats(mpc_parser_t *p);
|
||||
|
||||
int mpc_test_pass(mpc_parser_t *p, const char *s, const void *d,
|
||||
int(*tester)(const void*, const void*),
|
||||
mpc_dtor_t destructor,
|
||||
void(*printer)(const void*));
|
||||
|
||||
int mpc_test_fail(mpc_parser_t *p, const char *s, const void *d,
|
||||
int(*tester)(const void*, const void*),
|
||||
mpc_dtor_t destructor,
|
||||
void(*printer)(const void*));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2
vendor/yar.c
vendored
Normal file
2
vendor/yar.c
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
#define YAR_IMPLEMENTATION
|
||||
#include "yar.h"
|
||||
229
vendor/yar.h
vendored
Normal file
229
vendor/yar.h
vendored
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
/* yar - dynamic arrays in C - public domain Nicholas Rixson 2025
|
||||
*
|
||||
* https://github.com/segcore/yar
|
||||
*
|
||||
* Licence: see end of file
|
||||
|
||||
Sample usage:
|
||||
#define YAR_IMPLEMENTATION
|
||||
#include "yar.h"
|
||||
|
||||
int main() {
|
||||
// struct { double *items; size_t count; size_t capacity; } numbers = {0};
|
||||
yar(double) numbers = {0};
|
||||
*yar_append(&numbers) = 3.14159;
|
||||
*yar_append(&numbers) = 2.71828;
|
||||
*yar_append(&numbers) = 1.61803;
|
||||
|
||||
for(size_t i = 0; i < numbers.count; i++) {
|
||||
printf("%f\n", numbers.items[i]);
|
||||
}
|
||||
|
||||
yar_free(&numbers);
|
||||
}
|
||||
*/
|
||||
#ifndef YAR_H
|
||||
#define YAR_H
|
||||
|
||||
#include <stddef.h> // size_t
|
||||
#include <string.h> // strlen
|
||||
|
||||
/*
|
||||
* yar(type) - Declare a new basic dynamic array
|
||||
*
|
||||
* yar_append(array) - Add a new item at the end of the array, and return a pointer to it
|
||||
*
|
||||
* yar_reserve(array, extra) - Reserve space for `extra` count of items
|
||||
*
|
||||
* yar_append_many(array, data, num) - Append a copy of existing data
|
||||
*
|
||||
* yar_append_cstr(array, data) - Append a C string (nul-terminated char array)
|
||||
*
|
||||
* yar_insert(array, index, num) - Insert items somewhere within the array. Moves items to higher indexes as required. Returns &array[index]
|
||||
*
|
||||
* yar_remove(array, index, num) - Remove items from somewhere within the array. Moves items to lower indexes as required.
|
||||
*
|
||||
* yar_reset(array) - Reset the count of elements to 0, to re-use the memory. Does not free the memory.
|
||||
*
|
||||
* yar_init(array) - Set items, count, and capacity to 0. Can usually be avoided with <declaration> = {0};
|
||||
*
|
||||
* yar_free(array) - Free items memory, and set the items, count, and capacity to 0.
|
||||
*/
|
||||
|
||||
#define yar(type) struct { type *items; size_t count; size_t capacity; }
|
||||
#define yar_append(array) ((_yar_append((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0])) ? \
|
||||
&(array)->items[(array)->count - 1] : NULL))
|
||||
#define yar_reserve(array, extra) ((_yar_reserve((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), (extra)) ? \
|
||||
&(array)->items[(array)->count] : NULL))
|
||||
#define yar_append_many(array, data, num) ((_yar_append_many((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), 1 ? (data) : ((array)->items), (num)) ))
|
||||
#define yar_append_cstr(array, data) yar_append_many(array, data, strlen(data))
|
||||
#define yar_insert(array, index, num) ((_yar_insert((void**)&(array)->items, &(array)->count, &(array)->capacity, sizeof((array)->items[0]), index, num) ))
|
||||
#define yar_remove(array, index, num) ((_yar_remove((void**)&(array)->items, &(array)->count, sizeof((array)->items[0]), index, num) ))
|
||||
#define yar_reset(array) (((array)->count = 0))
|
||||
#define yar_init(array) ((array)->items = NULL, (array)->count = 0, (array)->capacity = 0)
|
||||
#define yar_free(array) ((_yar_free((array)->items)), (array)->items = NULL, (array)->count = 0, (array)->capacity = 0)
|
||||
|
||||
#ifndef YARAPI
|
||||
#define YARAPI // nothing; overridable if needed.
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Implementation functions
|
||||
YARAPI void* _yar_append(void** items_pointer, size_t* count, size_t* capacity, size_t item_size);
|
||||
YARAPI void* _yar_append_many(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, void* data, size_t extra);
|
||||
YARAPI void* _yar_reserve(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t extra);
|
||||
YARAPI void* _yar_insert(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t index, size_t extra);
|
||||
YARAPI void* _yar_remove(void** items_pointer, size_t* count, size_t item_size, size_t index, size_t remove);
|
||||
YARAPI void* _yar_realloc(void* p, size_t new_size);
|
||||
YARAPI void _yar_free(void* p);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // YAR_H
|
||||
|
||||
#if defined(YAR_IMPLEMENTATION)
|
||||
|
||||
#ifndef YAR_MIN_CAP
|
||||
#define YAR_MIN_CAP 16
|
||||
#endif
|
||||
|
||||
#ifndef YAR_REALLOC
|
||||
#define YAR_REALLOC realloc
|
||||
#endif
|
||||
|
||||
#ifndef YAR_FREE
|
||||
#define YAR_FREE free
|
||||
#endif
|
||||
|
||||
#include <string.h> // mem* functions
|
||||
YARAPI void* _yar_append(void** items_pointer, size_t* count, size_t* capacity, size_t item_size)
|
||||
{
|
||||
void* result = _yar_reserve(items_pointer, count, capacity, item_size, 1);
|
||||
if (result != NULL) *count += 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
YARAPI void* _yar_append_many(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, void* data, size_t extra)
|
||||
{
|
||||
void* result = _yar_reserve(items_pointer, count, capacity, item_size, extra);
|
||||
if (result != NULL) {
|
||||
memcpy(result, data, item_size * extra);
|
||||
*count += extra;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
YARAPI void* _yar_reserve(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t extra)
|
||||
{
|
||||
char* items = *items_pointer;
|
||||
size_t newcount = *count + extra;
|
||||
if (newcount > *capacity) {
|
||||
size_t newcap = (*capacity < YAR_MIN_CAP) ? YAR_MIN_CAP : *capacity * 8 / 5;
|
||||
if (newcap < newcount) newcap = newcount;
|
||||
void* next = _yar_realloc(items, newcap * item_size);
|
||||
if (next == NULL) return NULL;
|
||||
items = next;
|
||||
*items_pointer = next;
|
||||
*capacity = newcap;
|
||||
}
|
||||
void* result = items + (*count * item_size);
|
||||
if (extra && result) memset(result, 0, item_size * extra);
|
||||
return result;
|
||||
}
|
||||
|
||||
YARAPI void* _yar_insert(void** items_pointer, size_t* count, size_t* capacity, size_t item_size, size_t index, size_t extra)
|
||||
{
|
||||
void* next = _yar_reserve(items_pointer, count, capacity, item_size, extra);
|
||||
if(next == NULL) return NULL;
|
||||
|
||||
char* items = *items_pointer;
|
||||
if (index < *count)
|
||||
{
|
||||
memmove(&items[item_size * (index + extra)], &items[item_size * index], (*count - index) * item_size);
|
||||
memset(&items[item_size * index], 0, extra * item_size);
|
||||
}
|
||||
*count += extra;
|
||||
return items + index * item_size;
|
||||
}
|
||||
|
||||
YARAPI void* _yar_remove(void** items_pointer, size_t* count, size_t item_size, size_t index, size_t remove)
|
||||
{
|
||||
if(remove >= *count) {
|
||||
*count = 0;
|
||||
return *items_pointer;
|
||||
}
|
||||
if (index >= *count) {
|
||||
return *items_pointer;
|
||||
}
|
||||
char* items = *items_pointer;
|
||||
memmove(&items[item_size * index], &items[item_size * (index + remove)], item_size * (*count - (index + remove)));
|
||||
*count -= remove;
|
||||
return items + item_size * index;
|
||||
}
|
||||
|
||||
YARAPI void* _yar_realloc(void* p, size_t new_size)
|
||||
{
|
||||
// Declaration, so we can call it if the definition is overridden
|
||||
extern void* YAR_REALLOC(void *ptr, size_t size);
|
||||
return YAR_REALLOC(p, new_size);
|
||||
}
|
||||
|
||||
YARAPI void _yar_free(void* p)
|
||||
{
|
||||
extern void YAR_FREE(void *ptr);
|
||||
YAR_FREE(p);
|
||||
}
|
||||
|
||||
#endif // YAR_IMPLEMENTATION
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
|
||||
Copyright (c) 2025 Nicholas Rixson
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
||||
60
vm.c
Normal file
60
vm.c
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#include "vm.h"
|
||||
#include "gc.h"
|
||||
|
||||
static I decode_sleb128(U8 **ptr) {
|
||||
I result = 0;
|
||||
I shift = 0;
|
||||
U8 byte;
|
||||
|
||||
do {
|
||||
byte = **ptr;
|
||||
(*ptr)++;
|
||||
result |= (I)(byte & 0x7F) << shift;
|
||||
shift += 7;
|
||||
} while (byte & 0x80);
|
||||
|
||||
if ((shift < 64) && (byte & 0x40)) {
|
||||
result |= -(1LL << shift);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
V vm_init(Vm *vm) {
|
||||
vm->sp = vm->stack;
|
||||
vm->rsp = vm->rstack;
|
||||
gc_init(&vm->gc);
|
||||
|
||||
for (Z i = 0; i < STACK_SIZE; i++) {
|
||||
vm->stack[i] = NIL;
|
||||
gc_addroot(&vm->gc, &vm->stack[i]);
|
||||
}
|
||||
}
|
||||
|
||||
V vm_push(Vm *vm, O o) { *vm->sp++ = o; }
|
||||
O vm_pop(Vm *vm) { return *--vm->sp; }
|
||||
O vm_peek(Vm *vm) { return *(vm->sp - 1); }
|
||||
|
||||
V vm_run(Vm *vm, Bc *chunk, I offset) {
|
||||
I mark = gc_mark(&vm->gc);
|
||||
for (Z i = 0; i < chunk->constants.count; i++)
|
||||
gc_addroot(&vm->gc, &chunk->constants.items[i]);
|
||||
|
||||
vm->ip = chunk->items + offset;
|
||||
for (;;) {
|
||||
U8 opcode;
|
||||
switch (opcode = *vm->ip++) {
|
||||
case OP_NOP:
|
||||
break;
|
||||
case OP_RETURN:
|
||||
return;
|
||||
case OP_CONST: {
|
||||
I idx = decode_sleb128(&vm->ip);
|
||||
vm_push(vm, chunk->constants.items[idx]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gc_reset(&vm->gc, mark);
|
||||
}
|
||||
30
vm.h
Normal file
30
vm.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef VM_H
|
||||
#define VM_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "chunk.h"
|
||||
#include "gc.h"
|
||||
#include "object.h"
|
||||
|
||||
enum {
|
||||
OP_NOP = 0,
|
||||
OP_RETURN,
|
||||
OP_CONST,
|
||||
};
|
||||
|
||||
#define STACK_SIZE 256
|
||||
|
||||
typedef struct Vm {
|
||||
Gc gc;
|
||||
O stack[256], *sp;
|
||||
U rstack[256], *rsp;
|
||||
U8 *ip;
|
||||
} Vm;
|
||||
|
||||
V vm_init(Vm *);
|
||||
V vm_push(Vm *, O);
|
||||
O vm_pop(Vm *);
|
||||
O vm_peek(Vm *);
|
||||
V vm_run(Vm *, Bc *, I);
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue