~pmikkelsen/apl-prolog

3b7a78ff16d15e3eac865b515dd8bf0d45a23214 — Peter Mikkelsen 6 months ago 9b7caf1
This is a pretty big re-organisation of the code.

I hope it will make it easier to port to Plan 9 soon.
40 files changed, 547 insertions(+), 373 deletions(-)

M .builds/linux.yml
M .builds/openbsd.yml
A .gitignore
D Makefile
D array.h
A build.sh
D error.h
D eval.h
A include/clpl.h
D lexer.h
R arithprims.c => libclpl/arithprims.c
R array.c => libclpl/array.c
A libclpl/array.h
A libclpl/clpl.c
R cmpprims.c => libclpl/cmpprims.c
R error.c => libclpl/error.c
A libclpl/error.h
R eval.c => libclpl/eval.c
A libclpl/eval.h
R lexer.c => libclpl/lexer.c
A libclpl/lexer.h
R memory.c => libclpl/memory.c
R memory.h => libclpl/memory.h
A libclpl/platform.h
A libclpl/posix/platformtypes.h
A libclpl/posix/posix.c
A libclpl/sources
A libclpl/stack.c
A libclpl/stack.h
A libclpl/symtab.c
A libclpl/symtab.h
A libclpl/token.h
A libclpl/types.h
D main.c
A platform/posix/main.c
D stack.c
D stack.h
D symtab.c
D symtab.h
D token.h
M .builds/linux.yml => .builds/linux.yml +2 -2
@@ 4,7 4,7 @@ sources:
tasks:
- build: |
    cd apl-prolog
    make
    ./build.sh
- test: |
    cd apl-prolog
    ./hehe
    ./out/clpl

M .builds/openbsd.yml => .builds/openbsd.yml +2 -4
@@ 1,12 1,10 @@
image: openbsd/latest
sources:
- https://git.sr.ht/~pmikkelsen/apl-prolog
packages:
    - gmake
tasks:
- build: |
    cd apl-prolog
    gmake CC=cc
    make
- test: |
    cd apl-prolog
    ./hehe
    ./out/clpl

A .gitignore => .gitignore +2 -0
@@ 0,0 1,2 @@
out/
obj/

D Makefile => Makefile +0 -14
@@ 1,14 0,0 @@
CC=gcc
CFLAGS=-pedantic -Wall -Wextra -Werror -g
TARG=hehe
CFILES=main.c lexer.c error.c memory.c symtab.c eval.c array.c stack.c arithprims.c cmpprims.c
OFILES=${CFILES:.c=.o}

%.o: %.c
	$(CC) $(CFLAGS) -c $<

$(TARG): $(OFILES)
	$(CC) $(OFILES) -o $@
	
clean:
	rm -rf $(TARG) *.o

D array.h => array.h +0 -30
@@ 1,30 0,0 @@
/* At the moment we have a lot of overhead on arrays, but we can always improve it later */
typedef enum {
	ArrayInt64,
	ArrayFloat64,
	ArrayChar,
	ArrayArray,
} ArrayType;


typedef struct Array Array;
struct Array {
	ArrayType type;
	size_t rank;
	union {
		size_t vecsize;  /* Only used when rank == 1 */
		Array *highrank; /* Used when rank > 1 */
	} shape;
	union {
		void *v;
		int64_t *i64;
		double *f64;
		wchar_t *c;
		Array **a;
	} data;
};

size_t arraytypesize(ArrayType);
size_t arraysize(Array *);
Array *getarray(ArrayType, size_t, size_t);
Array *simplifyarray(Array *);

A build.sh => build.sh +58 -0
@@ 0,0 1,58 @@
#!/bin/sh

if [ $# -ne 1 ]
then
	echo Usage: ./build.sh platform
	echo "	defaults to platform: posix"
	PLATFORM=posix
else
	PLATFORM=$1
fi

PLATFORMSRCS=$(ls platform/$PLATFORM/*.c)

LIBSRCS=$(ls libclpl/*.c libclpl/$PLATFORM/*.c)
LIBOBJS=$(echo $LIBSRCS | sed 's/\.c/\.o/g' | sed 's/libclpl/obj/g')
LIBHEADER="include/clpl.h"
PROG=out/clpl
CC=cc
CFLAGS="-std=c99 -pedantic -Wall -Wextra -Werror -g -fPIC -Iinclude"
MAKEFILE=Makefile

mkdir -p out
mkdir -p obj
mkdir -p obj/$PLATFORM

# generate a makefile (assume posix system for now)

cat > $MAKEFILE << EOF
# THIS MAKEFILE IS AUTO-GENERATED. DO NOT EDIT

all: $PROG $PROG.a $PROG.so

$PROG: $PLATFORMSRCS $PROG.a $LIBHEADER
	$CC $CFLAGS -Iinclude $PLATFORMSRCS $PROG.a -o $PROG

$PROG.a: $LIBOBJS
	ar rcs $PROG.a $LIBOBJS

$PROG.so: $LIBOBJS
	$CC -shared $LIBOBJS -o $PROG.so

EOF

for CFILE in $LIBSRCS
do
	HFILES=$(cat $CFILE | grep "#include \"" | sed 's/"$//' | sed 's/^.*"/libclpl\//')
	OFILE=$(echo $CFILE | sed 's/\.c/\.o/' | sed 's/libclpl/obj/')

cat >> $MAKEFILE << EOF
$OFILE: $CFILE $LIBHEADER $(echo $HFILES)
	$CC $CFLAGS -Ilibclpl/$PLATFORM/ -c $CFILE -o $OFILE

EOF
done

make
rm $MAKEFILE


D error.h => error.h +0 -9
@@ 1,9 0,0 @@
typedef enum {
	ErrorSyntax,
	ErrorLimit,
	ErrorInternal,
	ErrorDomain,
} ErrorNum;

_Noreturn void errorf(ErrorNum, wchar_t *, ...);
void check(ErrorNum, int, wchar_t *, ...);

D eval.h => eval.h +0 -33
@@ 1,33 0,0 @@
typedef enum {
	FunctionPrimitive,
} FunctionType;

typedef struct {
	FunctionType type;
	union {
		Token prim;
	} f;
} Function;

typedef struct {
	TokenData *tokens;	/* All the tokens */
	size_t ntoks;		/* The number of tokens */
	size_t offset;		/* Current offset in the code stream */

	Array *left;
	Array *right;
	Array *result;
	Function *func;	
} Code;

void eval(void);


/* Function prototypes for the dyadic primitives */
Array *primfn2plus(Array *, Array *);
Array *primfn2minus(Array *, Array *);

/* Function prototypes for the monadic primitives */
Array *primfn1plus(Array *);
Array *primfn1minus(Array *);
Array *primfn1gradeup(Array *);

A include/clpl.h => include/clpl.h +12 -0
@@ 0,0 1,12 @@
#ifndef _CLPL_H
#define _CLPL_H

#include <stdint.h>
#include <stddef.h>

typedef struct Clpl Clpl;

Clpl *clplinit(void);
void clpleval(Clpl *, wchar_t *);

#endif

D lexer.h => lexer.h +0 -2
@@ 1,2 0,0 @@
Code *tokenize(wchar_t *);
wchar_t *untokenize(TokenData *, size_t);

R arithprims.c => libclpl/arithprims.c +2 -6
@@ 1,9 1,5 @@
#include <stddef.h>
#include <stdint.h>
#include "array.h"
#include "symtab.h"
#include "token.h"
#include "eval.h"
#include <platformtypes.h>
#include "types.h"

/* The + primitve */
Array *

R array.c => libclpl/array.c +13 -13
@@ 1,15 1,15 @@
#include <stddef.h>
#include <stdint.h>
#include <platformtypes.h>
#include "platform.h"
#include "types.h"
#include "array.h"
#include "error.h"
#include "memory.h"
#include "array.h"


size_t
Usize
arraytypesize(ArrayType type)
{
	Array a;
	size_t s;
	Usize s;
	switch(type){
	case ArrayInt64:
		s = sizeof(*a.data.i64);


@@ 29,28 29,28 @@ arraytypesize(ArrayType type)
	return s;
}

size_t
Usize
arraysize(Array *a)
{
	size_t s = 1;
	Usize s = 1;
	if(a->rank == 1)
		s = a->shape.vecsize;
	else{
		for(size_t i = 0; i < a->rank; i++)
		for(Usize i = 0; i < a->rank; i++)
			s *= a->shape.highrank->data.i64[i];
	}
	return s;
}

Array *
getarray(ArrayType type, size_t rank, size_t elemcount) 
getarray(ArrayType type, Usize rank, Usize elemcount) 
{
	size_t base = sizeof(Array);
	size_t extra = elemcount * arraytypesize(type);
	Usize base = sizeof(Array);
	Usize extra = elemcount * arraytypesize(type);
	Array *a = alloc(NULL, base + extra);
	a->type = type;
	a->rank = rank;
	a->data.v = ((int8_t*)a) + base;
	a->data.v = ((S8int*)a) + base;
	if(rank == 1)
		a->shape.vecsize = elemcount;
	else if(rank > 1)

A libclpl/array.h => libclpl/array.h +4 -0
@@ 0,0 1,4 @@
Usize arraytypesize(ArrayType);
Usize arraysize(Array *);
Array *getarray(ArrayType, Usize, Usize);
Array *simplifyarray(Array *);

A libclpl/clpl.c => libclpl/clpl.c +27 -0
@@ 0,0 1,27 @@
#include <platformtypes.h>
#include <clpl.h>
#include "types.h"
#include "symtab.h"
#include "stack.h"
#include "lexer.h"
#include "eval.h"
#include "memory.h"

Clpl *
clplinit(void)
{
	Clpl *clpl = alloc(NULL, sizeof(Clpl));
	initsymtab(clpl);
	initstack(clpl);

	return clpl;
}

void
clpleval(Clpl *clpl, Wchar *code)
{
	StackFrame repl = stackpush(clpl, StackRepl);
	clpl->stack[repl].data.code = tokenize(clpl, code);

	eval(clpl); /* Go */
}

R cmpprims.c => libclpl/cmpprims.c +3 -4
@@ 1,8 1,7 @@
#include <stddef.h>
#include <stdint.h>
#include <platformtypes.h>
#include <clpl.h>
#include "types.h"
#include "array.h"
#include "symtab.h"
#include "token.h"
#include "eval.h"

/* The comparison primitives */

R error.c => libclpl/error.c +14 -14
@@ 1,12 1,12 @@
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h>
#include <platformtypes.h>
#include "platform.h"
#include "types.h"
#include "error.h"

static wchar_t *
static Wchar *
errorstr(ErrorNum en)
{
	wchar_t *str;
	Wchar *str;

	switch(en){
	case ErrorSyntax:


@@ 28,17 28,17 @@ errorstr(ErrorNum en)
	return str;
}

static _Noreturn void
verrorf(ErrorNum en, wchar_t *format, va_list args)
static void
verrorf(ErrorNum en, Wchar *format, va_list args)
{
	wprintf(L"%ls: ", errorstr(en));
	vwprintf(format, args);	
	wprintf(L"\n");
	exit(EXIT_FAILURE);
	wprint(L"%ls: ", errorstr(en));
	wvprint(format, args);	
	wprint(L"\n");
	exitfailure();
}

_Noreturn void
errorf(ErrorNum en, wchar_t *format, ...)
void
errorf(ErrorNum en, Wchar *format, ...)
{
	va_list v;
	va_start(v, format);


@@ 46,7 46,7 @@ errorf(ErrorNum en, wchar_t *format, ...)
}

void
check(ErrorNum en, int ok, wchar_t *format, ...)
check(ErrorNum en, int ok, Wchar *format, ...)
{
	if(!ok){
		va_list v;

A libclpl/error.h => libclpl/error.h +2 -0
@@ 0,0 1,2 @@
void errorf(ErrorNum, Wchar *, ...);
void check(ErrorNum, int, Wchar *, ...);

R eval.c => libclpl/eval.c +21 -17
@@ 1,13 1,16 @@
#include <stddef.h>
#include <stdint.h>
#include <platformtypes.h>
#include <clpl.h>

/* TODO: fix this */
#include <wchar.h>
#include "memory.h"
/* end of todo */

#include "types.h"
#include "eval.h"
#include "array.h"
#include "symtab.h"
#include "token.h"
#include "error.h"
#include "eval.h"
#include "lexer.h"
#include "memory.h"
#include "stack.h"

static Array * 


@@ 25,6 28,7 @@ applydyadic(Function *f, Array *l, Array *r)
	default:
		errorf(ErrorInternal, L"Missing case in applydyadic()");
	}
	return NULL;
}

static Array * 


@@ 43,7 47,7 @@ applymonadic(Function *f, Array *r)
	default:
		errorf(ErrorInternal, L"Missing case in applydyadic()");
	}
errorf(ErrorInternal, L"Monadic function application not implemented");	
	return NULL;
}

static int


@@ 68,13 72,13 @@ apply(Code *c)
}

static void
parse(StackFrame f)
parse(Clpl *clpl, StackFrame f)
{
	Code *c = STACK[f].data.code;
	wchar_t *str = untokenize(c->tokens, c->ntoks);
	Code *c = clpl->stack[f].data.code;
	Wchar *str = untokenize(clpl, c->tokens, c->ntoks);
	wprintf(L"Trying to run code:\n%ls\nat token offset %ld\n", str, c->offset);
	Token t;
	size_t n;
	Usize n;

	while(c->offset-- > 0){
		if(c->result){


@@ 95,7 99,7 @@ parse(StackFrame f)
			for(n = 1; (c->offset - n) != 0 && c->tokens[c->offset - n].token == TokenConstant; n++);
			if(n > 1){
				c->result = getarray(ArrayArray, 1, n);
				for(size_t i = 0; i < n; i++)
				for(Usize i = 0; i < n; i++)
					c->result->data.a[n-(i+1)] = c->tokens[c->offset-i].data.array;
				/* The array might need to be simplified to avoid nested scalars */
				c->result = simplifyarray(c->result);


@@ 134,17 138,17 @@ parse(StackFrame f)
}

void
eval()
eval(Clpl *clpl)
{
	/* Look at the top of the stack, and evaluate it (whatever that means) */	
	Array *a;

	StackFrame f;
	while(STACK[f = stacktop()].type != StackBottom) switch(STACK[f].type){
	while(clpl->stack[f = stacktop(clpl)].type != StackBottom) switch(clpl->stack[f].type){
	case StackRepl:
		parse(f);
		a = STACK[f].data.code->result;
		stackpop();
		parse(clpl, f);
		a = clpl->stack[f].data.code->result;
		stackpop(clpl);
		wprintf(L"Result produced. Rank=%ld, type=%d. Wouldn't it be nice if we had array printing code\n", a->rank, a->type);
		break;
	default:

A libclpl/eval.h => libclpl/eval.h +11 -0
@@ 0,0 1,11 @@
void eval(Clpl *);


/* Function prototypes for the dyadic primitives */
Array *primfn2plus(Array *, Array *);
Array *primfn2minus(Array *, Array *);

/* Function prototypes for the monadic primitives */
Array *primfn1plus(Array *);
Array *primfn1minus(Array *);
Array *primfn1gradeup(Array *);

R lexer.c => libclpl/lexer.c +31 -33
@@ 1,37 1,34 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <wchar.h>
#include <wctype.h>
#include "array.h"
#include <platformtypes.h>
#include "platform.h"
#include <clpl.h>
#include "types.h"
#include "lexer.h"
#include "symtab.h"
#include "token.h"
#include "error.h"
#include "memory.h"
#include "eval.h"
#include "lexer.h"
#include "error.h"
#include "array.h"

enum {
	MaxTokens = 1024 /* Arbitrary limit which should be removed later */
};

static int
isnamechar(wchar_t c, int first)
isnamechar(Wchar c, int first)
{
	int ok = 0;
	ok = NULL != wcschr(L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c);
	ok = NULL != wstrchr(L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", c);
	if(!(first || ok))
		ok = iswdigit(c);
		ok = wisdigit(c);
	return ok;
}

Code *
tokenize(wchar_t *str)
tokenize(Clpl *clpl, Wchar *str)
{
	TokenData *toks = alloc(NULL, sizeof(TokenData) * MaxTokens);
	size_t t = 0, s = 0; /* t: token index, s: string index */
	Usize t = 0, s = 0; /* t: token index, s: string index */
	int line = 1, col = 1;
	wchar_t c = str[0];
	Wchar c = str[0];

#define NextChar	do{s++; col++; c=str[s];}while(0)
#define EmitTok(v)	do{NextChar; toks[t++].token = v; goto Lnexttok;}while(0)


@@ 73,8 70,8 @@ Lnexttok:

	/* Handle names */
	if(isnamechar(c, 1)){
		wchar_t buf[256]; /* NOTE: arbitrary limit, which isn't checked :) */
		wchar_t *p = buf;
		Wchar buf[256]; /* NOTE: arbitrary limit, which isn't checked :) */
		Wchar *p = buf;
	
		while(isnamechar(c, 0)){
			*p = c;


@@ 83,15 80,15 @@ Lnexttok:
		}
		BackOff;
		*p = 0;
		toks[t].data.sym = getsym(buf);
		toks[t].data.sym = getsym(clpl, buf);
		EmitTok(TokenSymbol);
	}

	/* Handle numbers */
	if(iswdigit(c)){
		wchar_t buf[64]; /* NOTE: arbitrary limit, which isn't checked :) */
		wchar_t *p = buf;
		while(iswdigit(c)){
	if(wisdigit(c)){
		Wchar buf[64]; /* NOTE: arbitrary limit, which isn't checked :) */
		Wchar *p = buf;
		while(wisdigit(c)){
			*p = c;
			p++;
			NextChar;


@@ 99,8 96,8 @@ Lnexttok:
		BackOff;
		*p = 0;

		wchar_t *end;
		int64_t n = wcstoll(buf, &end, 10);
		Wchar *end;
		S64int n = wstrtoll(buf, &end, 10);
		check(ErrorSyntax, end == p, L"Unexpected error lexing number: %ls", buf);
		toks[t].data.array = getarray(ArrayInt64, 0, 1);
		toks[t].data.array->data.i64[0] = n;


@@ 110,22 107,23 @@ Lnexttok:
	/* If we got here, we have a syntax error */
	dealloc(toks);
	errorf(ErrorSyntax, L"Unexpected symbol at line %d offset %d: '%lc'", line, col, c);
	return NULL;
#undef NextChar
#undef EmitTok
#undef CheckEnd
#undef BackOff
}

wchar_t *
untokenize(TokenData *toks, size_t ntoks)
Wchar *
untokenize(Clpl *clpl, TokenData *toks, Usize ntoks)
{
	/* Note: this function could consider the line information in the tokens as well, but it doesn't */
#define EmitChar(c) do{*p = c; p++; col++;}while(0)
	wchar_t *str = alloc(NULL, sizeof(wchar_t) * 1024); /* NOTE: arbitrary limit which isn't checked :) */
	wchar_t *p = str;
	size_t col = 1;
	Wchar *str = alloc(NULL, sizeof(Wchar) * 1024); /* NOTE: arbitrary limit which isn't checked :) */
	Wchar *p = str;
	Usize col = 1;

	for(size_t i = 0; i < ntoks; i++){
	for(Usize i = 0; i < ntoks; i++){
		while(toks[i].col > col)
			EmitChar(L' ');



@@ 150,7 148,7 @@ untokenize(TokenData *toks, size_t ntoks)
			switch(toks[i].data.array->type){
			case ArrayInt64:{
				/* NOTE: wrong limit */
				int n = swprintf(p, 1024, L"%ld", toks[i].data.array->data.i64[0]);
				int n = wsprint(p, 1024, L"%ld", toks[i].data.array->data.i64[0]);
				p += n;
				col += n;
				break;


@@ 160,7 158,7 @@ untokenize(TokenData *toks, size_t ntoks)
			}
			break;
		case TokenSymbol:
			for(wchar_t *x = SYMTAB[toks[i].data.sym].name; *x; x++)
			for(Wchar *x = clpl->symtab[toks[i].data.sym].name; *x; x++)
				EmitChar(*x);
			break;
		default:

A libclpl/lexer.h => libclpl/lexer.h +2 -0
@@ 0,0 1,2 @@
Code *tokenize(Clpl *, Wchar *);
Wchar *untokenize(Clpl *, TokenData *, Usize);

R memory.c => libclpl/memory.c +4 -3
@@ 1,10 1,11 @@
#include <stdlib.h>
#include <stddef.h>
#include <platformtypes.h>
#include "platform.h"
#include "types.h"
#include "error.h"
#include "memory.h"

void *
alloc(void *old, size_t s)
alloc(void *old, Usize s)
{
	void *p;
	if(old)

R memory.h => libclpl/memory.h +1 -1
@@ 1,2 1,2 @@
void *alloc(void *, size_t);
void *alloc(void *, Usize);
void dealloc(void *);

A libclpl/platform.h => libclpl/platform.h +15 -0
@@ 0,0 1,15 @@
void exitfailure(void);
Wchar *wstrchr(Wchar *, Wchar);
int wisdigit(Wchar);
long long wstrtoll(Wchar *, Wchar **, int);
int wstrcmp(Wchar *, Wchar *);
Usize wstrlen(Wchar *);
int wsprint(Wchar *, Usize, Wchar *, ...);
int wprint(Wchar *, ...);
int wvprint(Wchar *, va_list);

void *realloc(void *, Usize);
void *malloc(Usize);
void free(void *);
void *memset(void *, int, Usize);
void *memcpy(void *, const void *, Usize);

A libclpl/posix/platformtypes.h => libclpl/posix/platformtypes.h +9 -0
@@ 0,0 1,9 @@
#include <stdarg.h>
#include <stdint.h>
#include <wchar.h>

typedef size_t Usize;
typedef int64_t S64int;
typedef int8_t S8int;
typedef wchar_t Wchar;


A libclpl/posix/posix.c => libclpl/posix/posix.c +70 -0
@@ 0,0 1,70 @@
#include <platformtypes.h>
#include <../platform.h>

#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <wchar.h>
#include <wctype.h>

Wchar *
wstrchr(Wchar *s, Wchar c)
{
	return wcschr(s, c);
}

int
wisdigit(Wchar c)
{
	return iswdigit(c);
}

long long
wstrtoll(Wchar *nptr, Wchar **endptr, int base)
{
	return wcstoll(nptr, endptr, base);
}

int
wsprint(Wchar *str, Usize maxlen, Wchar *fmt, ...)
{
	va_list v;
	va_start(v, fmt);
	int ret = vswprintf(str, maxlen, fmt, v);
	va_end(v);
	return ret;
}

int
wprint(Wchar *fmt, ...)
{
	va_list v;
	va_start(v, fmt);
	int ret = vwprintf(fmt, v);
	va_end(v);
	return ret;
}

int
wvprint(Wchar *a, va_list args)
{
	return vwprintf(a, args);
}

int
wstrcmp(Wchar *a, Wchar *b)
{
	return wcscmp(a, b);
}

Usize
wstrlen(Wchar *s)
{
	return wcslen(s);
}

void
exitfailure(void)
{
	exit(EXIT_FAILURE);
}

A libclpl/sources => libclpl/sources +2 -0
@@ 0,0 1,2 @@
eval.c


A libclpl/stack.c => libclpl/stack.c +47 -0
@@ 0,0 1,47 @@
#include <platformtypes.h>
#include <clpl.h>
#include "types.h"
#include "stack.h"
#include "memory.h"
#include "error.h"


void
initstack(Clpl *clpl)
{
	clpl->stacksize = 1;
	clpl->stacktop = 0;
	clpl->stack = alloc(NULL, sizeof(*clpl->stack) * clpl->stacksize);
	clpl->stack[clpl->stacktop].type = StackBottom;
}

StackFrame
stacktop(Clpl *clpl)
{
	return clpl->stacktop;
}

StackFrame
stackpush(Clpl *clpl, StackType type)
{
	clpl->stacktop++;
	if(clpl->stacktop == clpl->stacksize){
		/* Grow the stack a bit.. */
		clpl->stacksize += 16;
		clpl->stack = alloc(clpl->stack, sizeof(*clpl->stack) * clpl->stacksize);
	}
	clpl->stack[clpl->stacktop].type = type;
	return clpl->stacktop;
}

void
stackpop(Clpl *clpl)
{
	switch(clpl->stack[clpl->stacktop].type){
	case StackRepl:
		/* Nothing to do yet */
		break;
	default: errorf(ErrorInternal, L"Unhandled case in stackpop()");
	}
	clpl->stacktop--;	
}

A libclpl/stack.h => libclpl/stack.h +4 -0
@@ 0,0 1,4 @@
void initstack(Clpl *);
StackFrame stacktop(Clpl *);
StackFrame stackpush(Clpl *, StackType);
void stackpop(Clpl *);

A libclpl/symtab.c => libclpl/symtab.c +35 -0
@@ 0,0 1,35 @@
#include <platformtypes.h>
#include "platform.h"
#include <clpl.h>
#include "types.h"
#include "symtab.h"
#include "memory.h"

void
initsymtab(Clpl *clpl)
{
	clpl->symtab = alloc(NULL, sizeof(*clpl->symtab));
	clpl->symtab[0].name = NULL;
}

Symbol
getsym(Clpl *clpl, Wchar *name)
{
	Symbol s = 0;
	for(s = 0; clpl->symtab[s].name != NULL; s++){
		if(wstrcmp(name, clpl->symtab[s].name) == 0)
			break;	
	}

	if(clpl->symtab[s].name == NULL){
		/* New symbol, extend the symbol table */
		clpl->symtab = alloc(clpl->symtab, sizeof(*clpl->symtab) * (s+2));
		clpl->symtab[s+1].name = NULL;
		Usize size = sizeof(Wchar) * (wstrlen(name) + 1);
		clpl->symtab[s].name = alloc(NULL, size);
		memcpy(clpl->symtab[s].name, name, size);
	}

	return s;
}


A libclpl/symtab.h => libclpl/symtab.h +2 -0
@@ 0,0 1,2 @@
void initsymtab(Clpl *);
Symbol getsym(Clpl *, Wchar *);

A libclpl/token.h => libclpl/token.h +7 -0
@@ 0,0 1,7 @@
/* Adding a new token:
 * 1) Add it to the Token enum
 * 2) If it needs any data, add that to the TokenData.data union
 * 3) Add a rule for it in tokenize()
 * 4) Add a matching rule in untokenize()
 */


A libclpl/types.h => libclpl/types.h +129 -0
@@ 0,0 1,129 @@
/*
 * This file defines all the enums and structs and unions we need.
 * Pretty much all C files have to include this file.
 *
 * The primtive types must be defined before including this header.
 * This is typically done by including a platform specific header first.
 */

typedef enum {
	ArrayInt64,
	ArrayFloat64,
	ArrayChar,
	ArrayArray,
} ArrayType;

typedef enum {
	ErrorSyntax,
	ErrorLimit,
	ErrorInternal,
	ErrorDomain,
} ErrorNum;

typedef enum {
	FunctionPrimitive,
} FunctionType;

typedef enum {
	StackBottom,	/* The bottom frame */
	StackRepl,	/* A line of code from the repl */
	StackCall,	/* A function */
} StackType;

typedef enum {
	NameClassUndefined,
	NameClassArray,
	NameClassMonadFun,
	NameClassDyadFun,
} NameClass;

typedef enum {
	TokenDel,		/* ∇ */
	TokenLeftArrow,		/* ← */
	TokenDiamond,		/* ⋄ */
	TokenPlus,		/* + */
	TokenMinus,		/* - */
	TokenGradeUp,		/* ⍋ */
	TokenNewline,		/* \n */
	TokenConstant,		/* A literal constant */
	TokenSymbol
} Token;

typedef Usize StackFrame; /* An index into the stack */
typedef Usize Symbol; /* A symbol is an index into the global symbol table */

typedef struct Array Array;
typedef struct Function Function;
typedef struct Code Code;
typedef struct StackData StackData;
typedef struct SymbolData SymbolData;
typedef struct TokenData TokenData;

/* At the moment we have a lot of overhead on arrays, but we can always improve it later */
struct Array {
	ArrayType type;
	Usize rank;
	union {
		Usize vecsize;  /* Only used when rank == 1 */
		Array *highrank; /* Used when rank > 1 */
	} shape;
	union {
		void *v;
		S64int *i64;
		double *f64;
		Wchar *c;
		Array **a;
	} data;
};

struct Function {
	FunctionType type;
	union {
		Token prim;
	} f;
};

struct Code {
	TokenData *tokens;	/* All the tokens */
	Usize ntoks;		/* The number of tokens */
	Usize offset;		/* Current offset in the code stream */

	Array *left;
	Array *right;
	Array *result;
	Function *func;	
};

struct StackData {
	StackType type;
	union {
		Code *code;
	} data;
};

struct SymbolData {
	Wchar *name;
	NameClass nc;	
	union {
		Array *a;
	} data;
};

struct TokenData {
	Token token;
	Usize line;
	Usize col;
	union {
		Symbol sym;	/* For TokenSymbol */
		Array *array;	/* For TokenConstant */	
	} data;	
};


struct Clpl {
	StackData *stack;
	Usize stacksize;
	StackFrame stacktop;

	SymbolData *symtab;
};

D main.c => main.c +0 -28
@@ 1,28 0,0 @@
#include <stdio.h>
#include <stdint.h>
#include <wchar.h>
#include <locale.h>
#include "array.h"
#include "symtab.h"
#include "token.h"
#include "eval.h"
#include "lexer.h"
#include "stack.h"
#include "error.h"

int
main(void)
{	
	setlocale(LC_ALL, ""); /* Ugh */

	initsymtab();
	initstack();

	/* wchar_t test[] = L"∇ R←X Plus Y \n  R←X+Y\n∇"; */
	wchar_t test[] = L"⍋1+-100+10 20";

	StackFrame repl = stackpush(StackRepl);
	STACK[repl].data.code = tokenize(test);

	eval(); /* Go */
}

A platform/posix/main.c => platform/posix/main.c +16 -0
@@ 0,0 1,16 @@
#include <locale.h>
#include <clpl.h>

int
main(void)
{
	setlocale(LC_ALL, ""); /* Ugh */

	Clpl *interpreter = clplinit();

	/* wchar_t test[] = L"∇ R←X Plus Y \n  R←X+Y\n∇"; */
	wchar_t test[] = L"⍋1+-100+10 20";

	clpleval(interpreter, test);

}

D stack.c => stack.c +0 -53
@@ 1,53 0,0 @@
#include <stddef.h>
#include <stdint.h>
#include "memory.h"
#include "error.h"
#include "array.h"
#include "symtab.h"
#include "token.h"
#include "eval.h"
#include "stack.h"

StackData *STACK; /* The global stack */
static size_t size = 0;
static StackFrame top = 0;

void
initstack(void)
{
	size = 1;
	top = 0;
	STACK = alloc(NULL, sizeof(*STACK) * size);
	STACK[top].type = StackBottom;
}

StackFrame
stacktop(void)
{
	return top;
}

StackFrame
stackpush(StackType type)
{
	top++;
	if(top == size){
		/* Grow the stack a bit.. */
		size += 16;
		STACK = alloc(STACK, sizeof(*STACK) * size);
	}
	STACK[top].type = type;
	return top;
}

void
stackpop(void)
{
	switch(STACK[top].type){
	case StackRepl:
		/* Nothing to do yet */
		break;
	default: errorf(ErrorInternal, L"Unhandled case in stackpop()");
	}
	top--;	
}

D stack.h => stack.h +0 -21
@@ 1,21 0,0 @@
typedef enum {
	StackBottom,	/* The bottom frame */
	StackRepl,	/* A line of code from the repl */
	StackCall,	/* A function */
} StackType;

typedef struct {
	StackType type;
	union {
		Code *code;
	} data;
} StackData;

typedef size_t StackFrame; /* An index into the stack */

extern StackData *STACK;

void initstack(void);
StackFrame stacktop(void);
StackFrame stackpush(StackType);
void stackpop(void);

D symtab.c => symtab.c +0 -38
@@ 1,38 0,0 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <wchar.h>
#include "memory.h"
#include "array.h"
#include "symtab.h"

SymbolData *SYMTAB;

void
initsymtab(void)
{
	SYMTAB = alloc(NULL, sizeof(*SYMTAB));
	SYMTAB[0].name = NULL;
}

Symbol
getsym(wchar_t *name)
{
	Symbol s = 0;
	for(s = 0; SYMTAB[s].name != NULL; s++){
		if(wcscmp(name, SYMTAB[s].name) == 0)
			break;	
	}

	if(SYMTAB[s].name == NULL){
		/* New symbol, extend the symbol table */
		SYMTAB = alloc(SYMTAB, sizeof(*SYMTAB) * (s+2));
		SYMTAB[s+1].name = NULL;
		size_t size = sizeof(wchar_t) * (wcslen(name) + 1);
		SYMTAB[s].name = alloc(NULL, size);
		memcpy(SYMTAB[s].name, name, size);
	}

	return s;
}


D symtab.h => symtab.h +0 -21
@@ 1,21 0,0 @@
typedef size_t Symbol; /* A symbol is an index into the global symbol table */

typedef enum {
	NameClassUndefined,
	NameClassArray,
	NameClassMonadFun,
	NameClassDyadFun,
} NameClass;

typedef struct {
	wchar_t *name;
	NameClass nc;	
	union {
		Array *a;
	} data;
} SymbolData;

extern SymbolData *SYMTAB; /* The global symbol table. */

void initsymtab(void);
Symbol getsym(wchar_t *);

D token.h => token.h +0 -27
@@ 1,27 0,0 @@
/* Adding a new token:
 * 1) Add it to the Token enum
 * 2) If it needs any data, add that to the TokenData.data union
 * 3) Add a rule for it in tokenize()
 * 4) Add a matching rule in untokenize()
 */
typedef enum {
	TokenDel,		/* ∇ */
	TokenLeftArrow,		/* ← */
	TokenDiamond,		/* ⋄ */
	TokenPlus,		/* + */
	TokenMinus,		/* - */
	TokenGradeUp,		/* ⍋ */
	TokenNewline,		/* \n */
	TokenConstant,		/* A literal constant */
	TokenSymbol
} Token;

typedef struct {
	Token token;
	size_t line;
	size_t col;
	union {
		Symbol sym;	/* For TokenSymbol */
		Array *array;	/* For TokenConstant */	
	} data;	
} TokenData;