update
This commit is contained in:
parent
e65c1ab9dc
commit
ecdd2828b2
|
@ -6,6 +6,8 @@ os:
|
||||||
|
|
||||||
dist: bionic
|
dist: bionic
|
||||||
|
|
||||||
|
sudo: required
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
- gcc
|
- gcc
|
||||||
- clang
|
- clang
|
||||||
|
@ -19,3 +21,6 @@ script:
|
||||||
- ./configure
|
- ./configure
|
||||||
- make
|
- make
|
||||||
- make check
|
- make check
|
||||||
|
- sudo make install
|
||||||
|
- command -v u6a u6ac
|
||||||
|
# - whatis u6a u6ac # broken on macOS...
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# u6a
|
# u6a
|
||||||
|
|
||||||
[![license](https://img.shields.io/badge/licence-GPLv3-blue.svg)](LICENSE)
|
[![Travis CI](https://travis-ci.com/CismonX/u6a.svg)](https://travis-ci.com/CismonX/u6a)
|
||||||
|
[![LICENSE](https://img.shields.io/badge/licence-GPLv3-blue.svg)](LICENSE)
|
||||||
|
|
||||||
Implementation of Unlambda, an esoteric programming language.
|
Implementation of Unlambda, an esoteric programming language.
|
||||||
|
|
||||||
|
|
22
configure.ac
22
configure.ac
|
@ -1,19 +1,33 @@
|
||||||
AC_PREREQ([2.69])
|
AC_PREREQ([2.69])
|
||||||
AC_INIT([u6a], [0.01], [https://cismon.net])
|
AC_INIT([u6a], [0.01], [bug-report@cismon.net])
|
||||||
AM_INIT_AUTOMAKE([foreign])
|
AM_INIT_AUTOMAKE([foreign])
|
||||||
AC_CONFIG_SRCDIR([src/u6a.c])
|
AC_CONFIG_SRCDIR([src/u6a.c])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile])
|
AC_CONFIG_FILES([Makefile src/Makefile man/Makefile])
|
||||||
|
|
||||||
|
dnl Check for operating system
|
||||||
|
AC_CANONICAL_HOST
|
||||||
|
case "${host_os}" in
|
||||||
|
linux*)
|
||||||
|
AC_SUBST([MANPATH_CONF], [/etc/manpath.config])
|
||||||
|
AC_SUBST([REBUILD_MANDB], [mandb])
|
||||||
|
;;
|
||||||
|
darwin*)
|
||||||
|
AC_SUBST([MANPATH_CONF], [/private/etc/man.conf])
|
||||||
|
AC_SUBST([REBUILD_MANDB], [/usr/libexec/makewhatis])
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_ERROR(["Unsupported OS: ${host_os}"])
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC_C99
|
AC_PROG_CC_C99
|
||||||
|
|
||||||
dnl Checks for libraries.
|
|
||||||
|
|
||||||
dnl Checks for header files.
|
dnl Checks for header files.
|
||||||
AC_CHECK_HEADERS([arpa/inet.h inttypes.h stddef.h stdint.h stdlib.h string.h unistd.h],
|
AC_CHECK_HEADERS([arpa/inet.h inttypes.h stddef.h stdint.h stdlib.h string.h unistd.h],
|
||||||
[],
|
[],
|
||||||
[AC_MSG_ERROR("required header(s) not found")])
|
[AC_MSG_ERROR(["required header(s) not found"])])
|
||||||
|
|
||||||
dnl Checks for typedefs, structures, and compiler characteristics.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_CHECK_HEADER_STDBOOL
|
AC_CHECK_HEADER_STDBOOL
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
MAN_DIR = $(prefix)/share/man/man1
|
MANPATH_MAP = $(shell cat $(MANPATH_CONF) | grep -w -m1 $(prefix))
|
||||||
MAN_FILES = u6ac.1 u6a.1
|
MAN_DIR = $(word 3, $(MANPATH_MAP))
|
||||||
|
MAN1_DIR = $(MAN_DIR)/man1
|
||||||
|
MAN_FILES = u6ac.1 u6a.1
|
||||||
|
|
||||||
install: $(MAN_FILES)
|
install: $(MAN_FILES)
|
||||||
mkdir -p $(MAN_DIR) && cp -t $(MAN_DIR) $^
|
cp -t $(MAN1_DIR) $^ && $(REBUILD_MANDB) $(MAN_DIR)
|
||||||
|
|
||||||
uninstall: $(MAN_FILES)
|
uninstall: $(MAN_FILES)
|
||||||
pushd $(MAN_DIR) && rm -f $^ && popd
|
pushd $(MAN1_DIR) && rm -f $^ && popd && $(REBUILD_MANDB) $(MAN_DIR)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
bin_PROGRAMS = u6ac u6a
|
bin_PROGRAMS = u6ac u6a
|
||||||
|
|
||||||
u6ac_SOURCES = logging.c lexer.c parser.c codegen.c u6ac.c
|
u6ac_SOURCES = logging.c lexer.c parser.c codegen.c u6ac.c
|
||||||
u6a_SOURCES = logging.c vm_stack.c vm_pool.c runtime.c u6a.c
|
u6a_SOURCES = logging.c vm_stack.c vm_pool.c runtime.c u6a.c
|
||||||
|
|
|
@ -144,6 +144,7 @@ u6a_codegen(struct u6a_ast_node* ast_arr, uint32_t ast_len) {
|
||||||
if (peek_ins.opcode == u6a_vo_app && operand_first.fn == u6a_tf_out && !operand_second.fn) {
|
if (peek_ins.opcode == u6a_vo_app && operand_first.fn == u6a_tf_out && !operand_second.fn) {
|
||||||
rodata_buffer[rodata_len++] = operand_first.ch;
|
rodata_buffer[rodata_len++] = operand_first.ch;
|
||||||
} else {
|
} else {
|
||||||
|
++stack_top;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,7 +179,7 @@ u6a_codegen(struct u6a_ast_node* ast_arr, uint32_t ast_len) {
|
||||||
struct ins_with_offset* top_elem = stack + stack_top--;
|
struct ins_with_offset* top_elem = stack + stack_top--;
|
||||||
if (top_elem->ins.opcode == u6a_vo_sa) {
|
if (top_elem->ins.opcode == u6a_vo_sa) {
|
||||||
text_buffer[text_len].opcode = u6a_vo_sa;
|
text_buffer[text_len].opcode = u6a_vo_sa;
|
||||||
stack[stack_top++] = (struct ins_with_offset) {
|
stack[++stack_top] = (struct ins_with_offset) {
|
||||||
.ins.opcode = u6a_vo_la,
|
.ins.opcode = u6a_vo_la,
|
||||||
.offset = text_len++
|
.offset = text_len++
|
||||||
};
|
};
|
||||||
|
|
|
@ -255,7 +255,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
|
||||||
ins = text + func.ref;
|
ins = text + func.ref;
|
||||||
func = acc;
|
func = acc;
|
||||||
// The `s2` function incremenets IP before pushing `j`, so decrement IP here
|
// The `s2` function incremenets IP before pushing `j`, so decrement IP here
|
||||||
if (func.token.fn = u6a_vf_s2) {
|
if (func.token.fn == u6a_vf_s2) {
|
||||||
--ins;
|
--ins;
|
||||||
}
|
}
|
||||||
arg = STACK_POP();
|
arg = STACK_POP();
|
||||||
|
@ -279,7 +279,7 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
|
||||||
case u6a_vf_d1_c:
|
case u6a_vf_d1_c:
|
||||||
func = POOL_GET1(func.ref);
|
func = POOL_GET1(func.ref);
|
||||||
goto do_apply;
|
goto do_apply;
|
||||||
case u6a_vf_d1_s: ;
|
case u6a_vf_d1_s:
|
||||||
tuple = POOL_GET2(func.ref);
|
tuple = POOL_GET2(func.ref);
|
||||||
STACK_PUSH1(tuple.v1.fn);
|
STACK_PUSH1(tuple.v1.fn);
|
||||||
acc = tuple.v2.fn;
|
acc = tuple.v2.fn;
|
||||||
|
@ -339,8 +339,8 @@ u6a_runtime_execute(FILE* restrict istream, FILE* restrict ostream) {
|
||||||
break;
|
break;
|
||||||
case u6a_vo_del:
|
case u6a_vo_del:
|
||||||
delay:
|
delay:
|
||||||
acc = U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text);
|
STACK_PUSH1(U6A_VM_VAR_FN_REF(u6a_vf_d1_d, ins + 1 - text));
|
||||||
ins = text + ins->operand.offset;
|
ins = text + text_subst_len + ins->operand.offset;
|
||||||
continue;
|
continue;
|
||||||
case u6a_vo_lc:
|
case u6a_vo_lc:
|
||||||
switch (ins->opcode_ex) {
|
switch (ins->opcode_ex) {
|
||||||
|
|
|
@ -53,20 +53,20 @@ enum u6a_vm_opcode_ex {
|
||||||
enum u6a_vm_fn {
|
enum u6a_vm_fn {
|
||||||
u6a_vf_placeholder_,
|
u6a_vf_placeholder_,
|
||||||
u6a_vf_k, u6a_vf_s, u6a_vf_i, u6a_vf_v, u6a_vf_c, u6a_vf_d, u6a_vf_e,
|
u6a_vf_k, u6a_vf_s, u6a_vf_i, u6a_vf_v, u6a_vf_c, u6a_vf_d, u6a_vf_e,
|
||||||
u6a_vf_in, /* @ */
|
u6a_vf_in, /* @ */
|
||||||
u6a_vf_pipe, /* | */
|
u6a_vf_pipe, /* | */
|
||||||
u6a_vf_out = U6A_VM_FN_CHAR, /* .X */
|
u6a_vf_out = U6A_VM_FN_CHAR, /* .X */
|
||||||
u6a_vf_cmp, /* ?X */
|
u6a_vf_cmp, /* ?X */
|
||||||
u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */
|
u6a_vf_k1 = U6A_VM_FN_REF, /* `kX */
|
||||||
u6a_vf_s1, /* `sX */
|
u6a_vf_s1, /* `sX */
|
||||||
u6a_vf_s2, /* ``sXY */
|
u6a_vf_s2, /* ``sXY */
|
||||||
u6a_vf_c1, /* `cX */
|
u6a_vf_c1, /* `cX */
|
||||||
u6a_vf_d1_s = U6A_VM_FN_PROMISE, /* `d`XZ */
|
u6a_vf_d1_s = U6A_VM_FN_PROMISE, /* `d`XZ */
|
||||||
u6a_vf_d1_c, /* `dX */
|
u6a_vf_d1_c, /* `dX */
|
||||||
u6a_vf_d1_d, /* `dF */
|
u6a_vf_d1_d, /* `dF */
|
||||||
u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */
|
u6a_vf_j = U6A_VM_FN_INTERNAL, /* (jump) */
|
||||||
u6a_vf_f, /* (finalize) */
|
u6a_vf_f, /* (finalize) */
|
||||||
u6a_vf_p /* (print) */
|
u6a_vf_p /* (print) */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct u6a_vm_ins {
|
struct u6a_vm_ins {
|
||||||
|
|
|
@ -90,20 +90,20 @@ free_stack_pop() {
|
||||||
|
|
||||||
bool
|
bool
|
||||||
u6a_vm_pool_init(uint32_t pool_len_, uint32_t ins_len) {
|
u6a_vm_pool_init(uint32_t pool_len_, uint32_t ins_len) {
|
||||||
const uint32_t pool_size = sizeof(struct vm_pool) + pool_len * sizeof(struct vm_pool_elem);
|
const uint32_t pool_size = sizeof(struct vm_pool) + pool_len_ * sizeof(struct vm_pool_elem);
|
||||||
active_pool = malloc(pool_size);
|
active_pool = malloc(pool_size);
|
||||||
if (UNLIKELY(active_pool == NULL)) {
|
if (UNLIKELY(active_pool == NULL)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const uint32_t holes_size = sizeof(struct vm_pool_elem_ptrs) + pool_len * sizeof(struct vm_pool_elem*);
|
const uint32_t holes_size = sizeof(struct vm_pool_elem_ptrs) + pool_len_ * sizeof(struct vm_pool_elem*);
|
||||||
holes = malloc(holes_size);
|
holes = malloc(holes_size);
|
||||||
if (UNLIKELY(active_pool == NULL)) {
|
if (UNLIKELY(holes == NULL)) {
|
||||||
free(active_pool);
|
free(holes);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const uint32_t free_stack_size = fstack_len * sizeof(struct vm_pool_elem*);
|
const uint32_t free_stack_size = ins_len * sizeof(struct vm_pool_elem*);
|
||||||
fstack = malloc(free_stack_size);
|
fstack = malloc(free_stack_size);
|
||||||
if (UNLIKELY(active_pool == NULL)) {
|
if (UNLIKELY(fstack == NULL)) {
|
||||||
free(active_pool);
|
free(active_pool);
|
||||||
free(holes);
|
free(holes);
|
||||||
return false;
|
return false;
|
||||||
|
@ -150,10 +150,8 @@ u6a_vm_pool_alloc2(struct u6a_vm_var_fn v1, struct u6a_vm_var_fn v2) {
|
||||||
if (UNLIKELY(elem == NULL)) {
|
if (UNLIKELY(elem == NULL)) {
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
elem = &(struct vm_pool_elem) {
|
elem->values = (struct u6a_vm_var_tuple) { .v1.fn = v1, .v2.fn = v2 };
|
||||||
.values = { .v1.fn = v1, .v2.fn = v2 },
|
elem->flags = 0;
|
||||||
.flags = 0
|
|
||||||
};
|
|
||||||
return elem - active_pool->elems;
|
return elem - active_pool->elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,10 +161,8 @@ u6a_vm_pool_alloc2_ptr(void* v1, void* v2) {
|
||||||
if (UNLIKELY(elem == NULL)) {
|
if (UNLIKELY(elem == NULL)) {
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
elem = &(struct vm_pool_elem) {
|
elem->values = (struct u6a_vm_var_tuple) { .v1.ptr = v1, .v2.ptr = v2 };
|
||||||
.values = { .v1.ptr = v1, .v2.ptr = v2 },
|
elem->flags = POOL_ELEM_HOLDS_PTR;
|
||||||
.flags = POOL_ELEM_HOLDS_PTR
|
|
||||||
};
|
|
||||||
return elem - active_pool->elems;
|
return elem - active_pool->elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +182,7 @@ u6a_vm_pool_free(uint32_t offset) {
|
||||||
fstack_top = UINT32_MAX;
|
fstack_top = UINT32_MAX;
|
||||||
do {
|
do {
|
||||||
if (--elem->refcnt == 0) {
|
if (--elem->refcnt == 0) {
|
||||||
holes->elems[holes->pos] = elem;
|
holes->elems[++holes->pos] = elem;
|
||||||
if (elem->flags & POOL_ELEM_HOLDS_PTR) {
|
if (elem->flags & POOL_ELEM_HOLDS_PTR) {
|
||||||
// Continuation destroyed before used
|
// Continuation destroyed before used
|
||||||
u6a_vm_stack_discard(elem->values.v1.ptr);
|
u6a_vm_stack_discard(elem->values.v1.ptr);
|
||||||
|
@ -195,7 +191,7 @@ u6a_vm_pool_free(uint32_t offset) {
|
||||||
free_stack_push(elem->values.v2);
|
free_stack_push(elem->values.v2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (elem = free_stack_pop());
|
} while ((elem = free_stack_pop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -35,27 +35,26 @@ static uint32_t stack_seg_len;
|
||||||
|
|
||||||
static inline struct vm_stack*
|
static inline struct vm_stack*
|
||||||
vm_stack_create(struct vm_stack* prev, uint32_t top) {
|
vm_stack_create(struct vm_stack* prev, uint32_t top) {
|
||||||
const uint32_t size = sizeof(struct vm_stack) + stack_seg_len * sizeof(union u6a_vm_var);
|
const uint32_t size = sizeof(struct vm_stack) + stack_seg_len * sizeof(struct u6a_vm_var_fn);
|
||||||
struct vm_stack* vs = malloc(size);
|
struct vm_stack* vs = malloc(size);
|
||||||
if (UNLIKELY(vs == NULL)) {
|
if (UNLIKELY(vs == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return vs = &(struct vm_stack) {
|
vs->prev = prev;
|
||||||
.prev = prev,
|
vs->top = top;
|
||||||
.top = top,
|
vs->refcnt = 1;
|
||||||
.refcnt = 1
|
return vs;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct vm_stack*
|
static inline struct vm_stack*
|
||||||
vm_stack_dup() {
|
vm_stack_dup() {
|
||||||
struct vm_stack* vs = active_stack;
|
struct vm_stack* vs = active_stack;
|
||||||
const uint32_t size = sizeof(struct vm_stack) + stack_seg_len * sizeof(union u6a_vm_var);
|
const uint32_t size = sizeof(struct vm_stack) + stack_seg_len * sizeof(struct u6a_vm_var_fn);
|
||||||
struct vm_stack* dup_stack = malloc(size);
|
struct vm_stack* dup_stack = malloc(size);
|
||||||
if (UNLIKELY(dup_stack == NULL)) {
|
if (UNLIKELY(dup_stack == NULL)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
memcpy(dup_stack, vs, sizeof(struct vm_stack) + (vs->top + 1) * sizeof(union u6a_vm_var));
|
memcpy(dup_stack, vs, sizeof(struct vm_stack) + (vs->top + 1) * sizeof(struct u6a_vm_var_fn));
|
||||||
dup_stack->refcnt = 1;
|
dup_stack->refcnt = 1;
|
||||||
return dup_stack;
|
return dup_stack;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue