aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/build.c117
-rw-r--r--src/free.c40
-rw-r--r--src/main.c100
-rw-r--r--src/parse.c161
-rw-r--r--src/print.c54
-rw-r--r--src/term.c19
6 files changed, 491 insertions, 0 deletions
diff --git a/src/build.c b/src/build.c
new file mode 100644
index 0000000..510afe0
--- /dev/null
+++ b/src/build.c
@@ -0,0 +1,117 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <build.h>
+#include <free.h>
+#include <parse.h>
+
+static void write_bit(char val, FILE *file, char *byte, int *bit)
+{
+ if (*bit > 7) { // flush byte
+ fwrite(byte, 1, 1, file);
+ *byte = 0;
+ *bit = 0;
+ }
+
+ if (val)
+ *byte |= 1UL << (7 - *bit);
+ (*bit)++;
+}
+
+static void rec_write_bblc(struct term *term, FILE *file, char *byte, int *bit)
+{
+ switch (term->type) {
+ case ABS:
+ write_bit(0, file, byte, bit);
+ write_bit(0, file, byte, bit);
+ rec_write_bblc(term->u.abs.term, file, byte, bit);
+ break;
+ case APP:
+ write_bit(0, file, byte, bit);
+ write_bit(1, file, byte, bit);
+ rec_write_bblc(term->u.app.lhs, file, byte, bit);
+ rec_write_bblc(term->u.app.rhs, file, byte, bit);
+ break;
+ case VAR:
+ for (int i = 0; i <= term->u.var.index; i++)
+ write_bit(1, file, byte, bit);
+ write_bit(0, file, byte, bit);
+ break;
+ default:
+ fprintf(stderr, "Invalid type %d\n", term->type);
+ }
+}
+
+// writes bit-encoded blc into file
+static void write_bblc(struct term *term, FILE *file)
+{
+ char byte = 0;
+ int bit = 0;
+ rec_write_bblc(term, file, &byte, &bit);
+
+ if (bit) // flush final
+ fwrite(&byte, 1, 1, file);
+}
+
+void write_bloc(struct term *term, const char *path)
+{
+ (void)term; // TODO
+
+ // example data
+ short length = 2;
+ struct term *M = parse_blc("0000000001100111100111100111100111011110");
+ struct term *N = parse_blc("00000000011001111001111001100111011110");
+
+ FILE *file = fopen(path, "wb");
+ fwrite(BLOC_IDENTIFIER, BLOC_IDENTIFIER_LENGTH, 1, file);
+ fwrite(&length, 2, 1, file);
+
+ write_bblc(M, file);
+ write_bblc(N, file);
+
+ // TODO
+ short table_index = 0;
+ char byte = 0;
+ int bit = 0;
+ write_bit(0, file, &byte, &bit);
+ write_bit(0, file, &byte, &bit);
+ write_bit(0, file, &byte, &bit);
+ write_bit(1, file, &byte, &bit);
+ write_bit(0, file, &byte, &bit);
+ write_bit(1, file, &byte, &bit);
+ write_bit(0, file, &byte, &bit);
+ write_bit(1, file, &byte, &bit);
+ write_bit(1, file, &byte, &bit);
+
+ for (int i = 0; i < 16; i++)
+ write_bit(0, file, &byte, &bit);
+
+ write_bit(0, file, &byte, &bit);
+ write_bit(0, file, &byte, &bit);
+ write_bit(1, file, &byte, &bit);
+
+ for (int i = 0; i < 16; i++)
+ write_bit(0, file, &byte, &bit);
+
+ write_bit(1, file, &byte, &bit);
+
+ for (int i = 0; i < 16; i++)
+ write_bit(0, file, &byte, &bit);
+
+ write_bit(1, file, &byte, &bit);
+
+ for (int i = 0; i < 16; i++)
+ write_bit(0, file, &byte, &bit);
+
+ if (bit) // flush final
+ fwrite(&byte, 1, 1, file);
+
+ fclose(file);
+
+ free_term(M);
+ free_term(N);
+}
diff --git a/src/free.c b/src/free.c
new file mode 100644
index 0000000..b22089e
--- /dev/null
+++ b/src/free.c
@@ -0,0 +1,40 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <free.h>
+
+void free_term(struct term *term)
+{
+ switch (term->type) {
+ case ABS:
+ free_term(term->u.abs.term);
+ free(term);
+ break;
+ case APP:
+ free_term(term->u.app.lhs);
+ free_term(term->u.app.rhs);
+ free(term);
+ break;
+ case VAR:
+ free(term);
+ break;
+ case REF:
+ free(term);
+ break;
+ default:
+ fprintf(stderr, "Invalid type %d\n", term->type);
+ }
+}
+
+void free_bloc(struct bloc_parsed *bloc)
+{
+ for (size_t i = 0; i < bloc->length; i++) {
+ free_term(bloc->entries[i]);
+ }
+
+ free(bloc->entries);
+ free(bloc);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..454c9d9
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,100 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <term.h>
+#include <print.h>
+#include <parse.h>
+#include <build.h>
+#include <free.h>
+
+#define BUF_SIZE 1024
+static char *read_stdin(void)
+{
+ char buffer[BUF_SIZE];
+ size_t size = 1;
+ char *string = malloc(sizeof(char) * BUF_SIZE);
+ if (!string)
+ return 0;
+ string[0] = '\0';
+ while (fgets(buffer, BUF_SIZE, stdin)) {
+ char *old = string;
+ size += strlen(buffer);
+ string = realloc(string, size);
+ if (!string) {
+ free(old);
+ return 0;
+ }
+ strcat(string, buffer);
+ }
+
+ if (ferror(stdin)) {
+ free(string);
+ fprintf(stderr, "Couldn't read from stdin\n");
+ return 0;
+ }
+ return string;
+}
+
+static char *read_file(const char *path)
+{
+ FILE *f = fopen(path, "rb");
+ if (!f) {
+ fprintf(stderr, "Can't open file %s: %s\n", path,
+ strerror(errno));
+ return 0;
+ }
+
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ char *string = malloc(fsize + 1);
+ int ret = fread(string, fsize, 1, f);
+ fclose(f);
+
+ if (ret != 1) {
+ fprintf(stderr, "Can't read file %s: %s\n", path,
+ strerror(errno));
+ return 0;
+ }
+
+ string[fsize] = 0;
+ return string;
+}
+
+int main(int argc, char **argv)
+{
+ /* if (argc < 2) { */
+ /* fprintf(stderr, "Invalid arguments\n"); */
+ /* return 1; */
+ /* } */
+
+ /* char *input; */
+ /* if (argv[1][0] == '-') { */
+ /* input = read_stdin(); */
+ /* } else { */
+ /* input = read_file(argv[1]); */
+ /* } */
+
+ /* if (!input) */
+ /* return 1; */
+
+ /* struct term *parsed = parse_blc(input); */
+ /* print_bruijn(parsed); */
+
+ write_bloc(0, "test.bloc");
+
+ const char *input = read_file("test.bloc");
+ struct bloc_parsed *bloc = parse_bloc(input);
+ struct term *term = from_bloc(bloc);
+ print_blc(term);
+
+ /* free_term(term); // TODO: Fix sharing user-after-free */
+
+ return 0;
+}
diff --git a/src/parse.c b/src/parse.c
new file mode 100644
index 0000000..8c69056
--- /dev/null
+++ b/src/parse.c
@@ -0,0 +1,161 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <term.h>
+#include <spec.h>
+#include <parse.h>
+
+static struct term *rec_blc(const char **term)
+{
+ struct term *res = 0;
+ if (!**term) {
+ fprintf(stderr, "invalid parsing state!\n");
+ } else if (**term == '0' && *(*term + 1) == '0') {
+ (*term) += 2;
+ res = new_term(ABS);
+ res->u.abs.term = rec_blc(term);
+ } else if (**term == '0' && *(*term + 1) == '1') {
+ (*term) += 2;
+ res = new_term(APP);
+ res->u.app.lhs = rec_blc(term);
+ res->u.app.rhs = rec_blc(term);
+ } else if (**term == '1') {
+ const char *cur = *term;
+ while (**term == '1')
+ (*term)++;
+ res = new_term(VAR);
+ res->u.var.index = *term - cur - 1;
+ (*term)++;
+ } else {
+ (*term)++;
+ res = rec_blc(term);
+ }
+ return res;
+}
+
+struct term *parse_blc(const char *term)
+{
+ return rec_blc(&term);
+}
+
+#define BIT_AT(i) (term[(i) / 8] & (1 << (7 - ((i) % 8))))
+
+// parses normal bit-encoded blc
+static struct term *parse_bblc(const char *term, size_t *bit)
+{
+ struct term *res = 0;
+ if (!BIT_AT(*bit) && !BIT_AT(*bit + 1)) {
+ (*bit) += 2;
+ res = new_term(ABS);
+ res->u.abs.term = parse_bblc(term, bit);
+ } else if (!BIT_AT(*bit) && BIT_AT(*bit + 1)) {
+ (*bit) += 2;
+ res = new_term(APP);
+ res->u.app.lhs = parse_bblc(term, bit);
+ res->u.app.rhs = parse_bblc(term, bit);
+ } else if (BIT_AT(*bit)) {
+ const size_t cur = *bit;
+ while (BIT_AT(*bit))
+ (*bit)++;
+ res = new_term(VAR);
+ res->u.var.index = *bit - cur - 1;
+ (*bit)++;
+ } else {
+ (*bit)++;
+ res = parse_bblc(term, bit);
+ }
+ return res;
+}
+
+// parses bloc's bit-encoded blc (1I => 2B index)
+static struct term *parse_bloc_bblc(const char *term, size_t *bit)
+{
+ struct term *res = 0;
+ if (!BIT_AT(*bit) && !BIT_AT(*bit + 1)) {
+ (*bit) += 2;
+ res = new_term(ABS);
+ res->u.abs.term = parse_bloc_bblc(term, bit);
+ } else if (!BIT_AT(*bit) && BIT_AT(*bit + 1)) {
+ (*bit) += 2;
+ res = new_term(APP);
+ res->u.app.lhs = parse_bloc_bblc(term, bit);
+ res->u.app.rhs = parse_bloc_bblc(term, bit);
+ } else if (BIT_AT(*bit)) {
+ (*bit) += 1;
+ res = new_term(REF);
+ short index = 0;
+ for (int i = 0; i < 16; i++)
+ index |= (BIT_AT(*bit) >> (7 - (*bit % 8))) << i;
+ res->u.ref.index = index;
+ (*bit) += 16;
+ } else {
+ (*bit)++;
+ res = parse_bloc_bblc(term, bit);
+ }
+ return res;
+}
+
+struct bloc_parsed *parse_bloc(const void *bloc)
+{
+ const struct bloc_header *header = bloc;
+ if (memcmp(header->identifier, BLOC_IDENTIFIER,
+ (size_t)BLOC_IDENTIFIER_LENGTH)) {
+ fprintf(stderr, "invalid BLoC identifier!\n");
+ return 0;
+ }
+
+ struct bloc_parsed *parsed = malloc(sizeof(*parsed));
+ parsed->length = header->length;
+ parsed->entries = malloc(header->length * sizeof(struct term *));
+
+ const struct bloc_entry *current = (const void *)&header->data;
+ for (size_t i = 0; i < parsed->length; i++) {
+ size_t len = 0;
+ parsed->entries[i] = parse_bblc((const char *)current, &len);
+ current =
+ (const struct bloc_entry *)(((const char *)current) +
+ (len / 8) + (len % 8 != 0));
+ }
+
+ size_t len = 0;
+ const char *term = (const char *)current;
+ parsed->term = parse_bloc_bblc(term, &len);
+
+ return parsed;
+}
+
+static struct term *rec_bloc(struct term *term, struct bloc_parsed *bloc)
+{
+ switch (term->type) {
+ case ABS:
+ rec_bloc(term->u.abs.term, bloc);
+ break;
+ case APP:
+ rec_bloc(term->u.app.lhs, bloc);
+ rec_bloc(term->u.app.rhs, bloc);
+ break;
+ case VAR:
+ fprintf(stderr, "bloc can't have vars\n");
+ return 0;
+ case REF:
+ if (term->u.ref.index >= bloc->length) {
+ fprintf(stderr, "invalid entry reference\n");
+ return 0;
+ }
+ memcpy(term, bloc->entries[term->u.ref.index], sizeof(*term));
+ break;
+ default:
+ fprintf(stderr, "invalid type %d\n", term->type);
+ return 0;
+ }
+ return term;
+}
+
+struct term *from_bloc(struct bloc_parsed *bloc)
+{
+ return rec_bloc(bloc->term, bloc);
+}
diff --git a/src/print.c b/src/print.c
new file mode 100644
index 0000000..425aedb
--- /dev/null
+++ b/src/print.c
@@ -0,0 +1,54 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+
+#include <print.h>
+
+void print_bruijn(struct term *term)
+{
+ switch (term->type) {
+ case ABS:
+ printf("[");
+ print_bruijn(term->u.abs.term);
+ printf("]");
+ break;
+ case APP:
+ printf("(");
+ print_bruijn(term->u.app.lhs);
+ printf(" ");
+ print_bruijn(term->u.app.rhs);
+ printf(")");
+ break;
+ case VAR:
+ printf("%d", term->u.var.index);
+ break;
+ case REF:
+ printf("<%ld>", term->u.ref.index);
+ break;
+ default:
+ fprintf(stderr, "Invalid type %d\n", term->type);
+ }
+}
+
+void print_blc(struct term *term)
+{
+ switch (term->type) {
+ case ABS:
+ printf("00");
+ print_blc(term->u.abs.term);
+ break;
+ case APP:
+ printf("01");
+ print_blc(term->u.app.lhs);
+ print_blc(term->u.app.rhs);
+ break;
+ case VAR:
+ for (int i = 0; i <= term->u.var.index; i++)
+ printf("1");
+ printf("0");
+ break;
+ default:
+ fprintf(stderr, "Invalid type %d\n", term->type);
+ }
+}
diff --git a/src/term.c b/src/term.c
new file mode 100644
index 0000000..7ab1a79
--- /dev/null
+++ b/src/term.c
@@ -0,0 +1,19 @@
+// Copyright (c) 2023, Marvin Borner <dev@marvinborner.de>
+// SPDX-License-Identifier: MIT
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <term.h>
+
+struct term *new_term(term_type type)
+{
+ struct term *term = malloc(sizeof(*term));
+ if (!term) {
+ fprintf(stderr, "Out of memory!\n");
+ abort();
+ }
+ term->type = type;
+ return term;
+}