// Copyright (c) 2023, Marvin Borner // SPDX-License-Identifier: MIT #include #include #include #include #include #include #include struct hashmap *all_terms; typedef enum { INV, ABS, APP, VAR } term_type_t; struct term { term_type_t type; hash_t hash; size_t refs; union { struct { hash_t term; } abs; struct { hash_t lhs; hash_t rhs; } app; struct { int index; } var; } u; }; static void deref_term(struct term *term) { if (term->type == ABS) { deref_term(hashmap_get(all_terms, term->u.abs.term)); } else if (term->type == APP) { deref_term(hashmap_get(all_terms, term->u.app.lhs)); deref_term(hashmap_get(all_terms, term->u.app.rhs)); } // TODO: remove from hashmap? if (--term->refs == 0) free(term); } static void hashmap_free_term(void *item) { struct term *term = *(struct term **)item; free(term); } static struct term *new_term(term_type_t type) { struct term *term = malloc(sizeof(*term)); if (!term) fatal("out of memory!\n"); term->type = type; return term; } // TODO: bit rec_bblc static hash_t rec_blc(char **term) { hash_t res = 0; struct term *res_term = 0; term_type_t res_type = 0; if (!**term) { fatal("invalid parsing state!\n"); } else if (**term == '0' && *(*term + 1) == '0') { (*term) += 2; res_type = ABS; hash_t inner_hash = rec_blc(term); res = hash((uint8_t *)&res_type, sizeof(res_type), inner_hash); struct term **handle = hashmap_get(all_terms, res); if (handle) { res_term = *handle; res_term->refs++; } else { res_term = new_term(ABS); res_term->refs = 1; res_term->hash = res; res_term->u.abs.term = inner_hash; hashmap_set(all_terms, &res_term, res); } } else if (**term == '0' && *(*term + 1) == '1') { (*term) += 2; res_type = APP; hash_t lhs_hash = rec_blc(term); hash_t rhs_hash = rec_blc(term); res = hash((uint8_t *)&res_type, sizeof(res_type), lhs_hash); res = hash((uint8_t *)&res, sizeof(res), rhs_hash); struct term **handle = hashmap_get(all_terms, res); if (handle) { res_term = *handle; res_term->refs++; } else { res_term = new_term(res_type); res_term->refs = 1; res_term->hash = res; res_term->u.app.lhs = lhs_hash; res_term->u.app.rhs = rhs_hash; hashmap_set(all_terms, &res_term, res); } } else if (**term == '1') { res_type = VAR; const char *cur = *term; while (**term == '1') (*term)++; int index = *term - cur - 1; res = hash((uint8_t *)&res_type, sizeof(res_type), index); struct term **handle = hashmap_get(all_terms, res); if (handle) { res_term = *handle; res_term->refs++; } else { res_term = new_term(res_type); res_term->refs = 1; res_term->hash = res; res_term->u.var.index = index; hashmap_set(all_terms, &res_term, res); } (*term)++; } else { (*term)++; res = rec_blc(term); } return res; } static char *read_file(FILE *f) { fseek(f, 0, SEEK_END); long fsize = ftell(f); fseek(f, 0, SEEK_SET); char *string = malloc(fsize + 1); if (!string) fatal("out of memory!\n"); int ret = fread(string, fsize, 1, f); if (ret != 1) { free(string); fatal("can't read file: %s\n", strerror(errno)); } string[fsize] = 0; return string; } static char *read_path(const char *path) { debug("reading from %s\n", path); FILE *f = fopen(path, "rb"); if (!f) fatal("can't open file %s: %s\n", path, strerror(errno)); char *string = read_file(f); fclose(f); return string; } int main(int argc, char *argv[]) { debug_enable(1); if (argc != 2) fatal("usage: %s \n", argv[0]); char *term = read_path(argv[1]); char *orig_term = term; all_terms = hashmap_new(sizeof(struct term *), 0, hashmap_free_term); rec_blc(&term); free(orig_term); hashmap_free(all_terms); return 0; }