From 05540fc6038f452f5dc5f18412c918c33ad96027 Mon Sep 17 00:00:00 2001 From: Kai Stevenson Date: Thu, 16 Feb 2023 14:32:56 -0800 Subject: changed project structure --- Makefile | 2 +- doc/pcdt_examples/boolean.pcdt | 18 ----- doc/pcdt_examples/example.pcdt | 2 - doc/pcdt_examples/helloworld.pcdt | 3 - doc/pcdt_examples/includetest.pcdt | 2 - eval.c | 134 ---------------------------------- eval.h | 9 --- examples/boolean.pcdt | 18 +++++ examples/example.pcdt | 2 + examples/helloworld.pcdt | 3 + examples/includetest.pcdt | 2 + hashtable.c | 39 ---------- hashtable.h | 19 ----- parse.c | 143 ------------------------------------- parse.h | 40 ----------- precedent.c | 104 --------------------------- precedent.h | 7 -- scope.c | 20 ------ scope.h | 13 ---- src/eval.c | 134 ++++++++++++++++++++++++++++++++++ src/eval.h | 9 +++ src/hashtable.c | 39 ++++++++++ src/hashtable.h | 19 +++++ src/parse.c | 143 +++++++++++++++++++++++++++++++++++++ src/parse.h | 40 +++++++++++ src/precedent.c | 104 +++++++++++++++++++++++++++ src/precedent.h | 7 ++ src/scope.c | 20 ++++++ src/scope.h | 13 ++++ 29 files changed, 554 insertions(+), 554 deletions(-) delete mode 100644 doc/pcdt_examples/boolean.pcdt delete mode 100644 doc/pcdt_examples/example.pcdt delete mode 100644 doc/pcdt_examples/helloworld.pcdt delete mode 100644 doc/pcdt_examples/includetest.pcdt delete mode 100644 eval.c delete mode 100644 eval.h create mode 100644 examples/boolean.pcdt create mode 100644 examples/example.pcdt create mode 100644 examples/helloworld.pcdt create mode 100644 examples/includetest.pcdt delete mode 100644 hashtable.c delete mode 100644 hashtable.h delete mode 100644 parse.c delete mode 100644 parse.h delete mode 100644 precedent.c delete mode 100644 precedent.h delete mode 100644 scope.c delete mode 100644 scope.h create mode 100644 src/eval.c create mode 100644 src/eval.h create mode 100644 src/hashtable.c create mode 100644 src/hashtable.h create mode 100644 src/parse.c create mode 100644 src/parse.h create mode 100644 src/precedent.c create mode 100644 src/precedent.h create mode 100644 src/scope.c create mode 100644 src/scope.h diff --git a/Makefile b/Makefile index bf83693..9390a29 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ PREFIX ?= /usr BINDIR ?= ${PREFIX}/bin generate: - $(CC) -o precedent precedent.c hashtable.c scope.c parse.c eval.c $(CFLAGS) + $(CC) -o precedent src/precedent.c src/hashtable.c src/scope.c src/parse.c src/eval.c $(CFLAGS) clean: rm precedent diff --git a/doc/pcdt_examples/boolean.pcdt b/doc/pcdt_examples/boolean.pcdt deleted file mode 100644 index e6becd6..0000000 --- a/doc/pcdt_examples/boolean.pcdt +++ /dev/null @@ -1,18 +0,0 @@ -store(14; var1;) -store(12; var2;) - -store( -eq(var1() var2()) -res;) - -print(var1()) - -if(res() -print(equals;) -) - -if(not(res()) -print(does not equal;) -) - -print(var2()) diff --git a/doc/pcdt_examples/example.pcdt b/doc/pcdt_examples/example.pcdt deleted file mode 100644 index 68d0a84..0000000 --- a/doc/pcdt_examples/example.pcdt +++ /dev/null @@ -1,2 +0,0 @@ -store(hello;myVar;) -print(myVar()) diff --git a/doc/pcdt_examples/helloworld.pcdt b/doc/pcdt_examples/helloworld.pcdt deleted file mode 100644 index 6ad1398..0000000 --- a/doc/pcdt_examples/helloworld.pcdt +++ /dev/null @@ -1,3 +0,0 @@ -store(print(hello world;) HelloWorldFunc;) -HelloWorldFunc() -HelloWorldFunc() diff --git a/doc/pcdt_examples/includetest.pcdt b/doc/pcdt_examples/includetest.pcdt deleted file mode 100644 index 81aa285..0000000 --- a/doc/pcdt_examples/includetest.pcdt +++ /dev/null @@ -1,2 +0,0 @@ -@helloworld.pcdt -HelloWorldFunc() diff --git a/eval.c b/eval.c deleted file mode 100644 index b1d4e0a..0000000 --- a/eval.c +++ /dev/null @@ -1,134 +0,0 @@ -#include -#include -#include -#include "eval.h" -#include "hashtable.h" -#include "parse.h" - -hashtable_t* ht; -const int hashtableSize = 1000; -const int trueVal = 1; -sym_t trueSym = {LITERAL, INT, (void*)&trueVal, NULL, 0}; -const int falseVal = 0; -sym_t falseSym = {LITERAL, INT, (void*)&falseVal, NULL, 0}; - -void init_eval() { - ht = init_hashtable(hashtableSize); -} -/* TODO: read base hashtable from file to allow modularity -pair value value? */ -void exec_all(sym_t** symbols, int count) { - for (int i = 0; i < count; i++) { - /* dispose of result */ - eval(symbols[i]); - } -} -sym_t* eval(sym_t* symbol) { - if (symbol->province == LITERAL) { - return(symbol); - } - else if (symbol->province == KEY_REF) { - sym_t* ir = try_eval_internal(symbol); - if (ir != NULL) { - return ir; - } - else { - /* not an internal function, search hashtable for - next symbol */ - /* TODO: scope */ - pair_t* p = hashtable_get_pair(ht, (char*)symbol->name); - if (p != NULL) { - return eval((sym_t*)p->value); - } - else { - printf("no matching pair in hashtable\n"); - return NULL; - } - } - } - else { - printf("no symbol province\n"); - return NULL; - } -} -/* internal functions? -this function has side-effects */ -sym_t* try_eval_internal(sym_t* symbol) { - unsigned int hash = get_hash((char*)symbol->name); - /* TODO: return last arg. that's the function return line */ - if (hash == get_hash("root")) { - /* execute all args as roots */ - exec_all(symbol->args, symbol->argCount); - return &trueSym; - } - else if (hash == get_hash("store")) { - /* TODO: scope */ - /* first arg is value, remaining args are names */ - /* TODO: recursion for multiple pairs */ - char* k = symtos(eval(symbol->args[1])); - sym_t* v = symbol->args[0]; - pair_t* p = init_pair(k, (void*)v); - hashtable_add_pair(ht, p); - return &trueSym; - } - /* TODO: release()/free() method? */ - else if (hash == get_hash("eq")) { - litType_t type = NO_TYPE; - void* lastVal = NULL; - for (int i = 0; i < symbol->argCount; i++) { - sym_t* v = eval(symbol->args[i]); - /* initialize */ - if (type == NO_TYPE) { - type = v->litType; - lastVal = v->name; - } - else { - /* interpret type */ - if (type == INT) { - if (symtoi(v) != *((int*)lastVal)) { - return &falseSym; - } - } - if (type == STRING) { - if (strcmp(symtos(v), (char*)lastVal) != 0) { - return &falseSym; - } - } - /* TODO: float */ - } - } - return &trueSym; - } - else if (hash == get_hash("if")) { - sym_t* v = eval(symbol->args[0]); - if (symtoi(v) != 0) { - exec_all(symbol->args + 1, symbol->argCount - 1); - return &trueSym; - } - return &falseSym; - } - else if (hash == get_hash("not")) { - sym_t* v = eval(symbol->args[0]); - int b = symtoi(v); - return b ? &falseSym : &trueSym; - } - else if (hash == get_hash("print")) { - sym_t* v = eval(symbol->args[0]); - switch (v->litType) { - case NO_TYPE: - break; - case INT: - printf("%d\n", symtoi(v)); - break; - case FLOAT: - break; - case STRING: - printf("%s\n", symtos(v)); - break; - } - return &trueSym; - } - else { - return NULL; - } -} diff --git a/eval.h b/eval.h deleted file mode 100644 index b91c621..0000000 --- a/eval.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "parse.h" -#ifndef EVAL -#define EVAL -void init_eval(void); -void throw(char* error, int symbolLocale); -void exec_all(sym_t** symbols, int count); -sym_t* eval(sym_t* symbol); -sym_t* try_eval_internal(sym_t* symbol); -#endif diff --git a/examples/boolean.pcdt b/examples/boolean.pcdt new file mode 100644 index 0000000..e6becd6 --- /dev/null +++ b/examples/boolean.pcdt @@ -0,0 +1,18 @@ +store(14; var1;) +store(12; var2;) + +store( +eq(var1() var2()) +res;) + +print(var1()) + +if(res() +print(equals;) +) + +if(not(res()) +print(does not equal;) +) + +print(var2()) diff --git a/examples/example.pcdt b/examples/example.pcdt new file mode 100644 index 0000000..68d0a84 --- /dev/null +++ b/examples/example.pcdt @@ -0,0 +1,2 @@ +store(hello;myVar;) +print(myVar()) diff --git a/examples/helloworld.pcdt b/examples/helloworld.pcdt new file mode 100644 index 0000000..6ad1398 --- /dev/null +++ b/examples/helloworld.pcdt @@ -0,0 +1,3 @@ +store(print(hello world;) HelloWorldFunc;) +HelloWorldFunc() +HelloWorldFunc() diff --git a/examples/includetest.pcdt b/examples/includetest.pcdt new file mode 100644 index 0000000..81aa285 --- /dev/null +++ b/examples/includetest.pcdt @@ -0,0 +1,2 @@ +@helloworld.pcdt +HelloWorldFunc() diff --git a/hashtable.c b/hashtable.c deleted file mode 100644 index 7cb253c..0000000 --- a/hashtable.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include -#include "hashtable.h" - -const unsigned int fnvPrime = 16777619; -const unsigned int fnvOffset = 2166136261U; - -pair_t* init_pair(char* key, void* value) { - pair_t* p = malloc(sizeof(pair_t)); - p->key = key; - p->value = value; - return p; -} -hashtable_t* init_hashtable(unsigned int capacity) { - hashtable_t* ht = malloc(sizeof(hashtable_t)); - ht->pairs = calloc(capacity, sizeof(pair_t*)); - ht->capacity = capacity; - return ht; -} -//FNV-1a hash -unsigned int get_hash(char* str) { - unsigned int hash = fnvOffset; - while (*str != '\0') { - hash = (hash ^ *str) * fnvPrime; - str++; - } - return hash; -} -/* TODO: handle collision -TODO: return 0 if something goes wrong */ -unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair) { - unsigned int hash = get_hash(pair->key); - hashtable->pairs[hash % hashtable->capacity] = pair; - return hash; -} -pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key) { - unsigned int hash = get_hash(key); - return hashtable->pairs[hash % hashtable->capacity]; -} diff --git a/hashtable.h b/hashtable.h deleted file mode 100644 index 43ab23a..0000000 --- a/hashtable.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef HASHTABLE -#define HASHTABLE - -typedef struct HashPair { - char* key; - void* value; -} pair_t; -pair_t* init_pair(char* key, void* value); -typedef struct HashTable { - pair_t** pairs; - int capacity; - int itemCount; -} hashtable_t; -hashtable_t* init_hashtable(unsigned int capacity); -unsigned int get_hash(char* str); -unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair); -pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key); - -#endif diff --git a/parse.c b/parse.c deleted file mode 100644 index 27ee417..0000000 --- a/parse.c +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include -#include -#include -#include "parse.h" -#include "hashtable.h" - -int symtoi(sym_t* symbol) { - return *((int*)symbol->name); -} -float symtof(sym_t* symbol) { - return *((float*)symbol->name); -} -char* symtos(sym_t* symbol) { - return (char*)symbol->name; -} - -void symbol_add_arg(sym_t* symbol, sym_t* arg) { - symbol->argCount += 1; - if (symbol->argCount == 1) { - symbol->args = malloc(sizeof(sym_t*)); - } - else { - symbol->args = realloc(symbol->args, symbol->argCount * (sizeof(sym_t*))); - } - (symbol->args)[symbol->argCount - 1] = arg; -} -void symset_add_symbol(symset_t* symbolSet, sym_t* symbol) { - symbolSet->count += 1; - if (symbolSet->count == 1) { - symbolSet->symbols = malloc(sizeof(sym_t*)); - } - else { - symbolSet->symbols = realloc(symbolSet->symbols, symbolSet->count * (sizeof(sym_t*))); - } - (symbolSet->symbols)[symbolSet->count - 1] = symbol; -} -symset_t* parse_symbols(char** str) { - symset_t* symbolSet = malloc(sizeof(symset_t)); - symbolSet->count = 0; - while (1) { - /* clear whitespace */ - while (!isalnum(**str) && **str != '(' && **str != ')' && **str != '\0') { - (*str)++; - } - if (**str == ')') { - (*str)++; - return symbolSet; - } - else if (**str == '\0') { - return symbolSet; - } - char* symbolName = calloc(30, sizeof(char)); - int i = 0; - while (1) { - symbolName[i] = **str; - if (**str == ',' || **str == ';') { - (*str)++; - sym_t* symbol = malloc(sizeof(sym_t)); - symbol->province = LITERAL; - symbol->argCount = 0; - symbolName[i] = '\0'; - /* TODO: float */ - /* string */ - if (isalpha(symbolName[0])) { - //symbolName = realloc(symbolName, i * sizeof(char)); - symbol->name = symbolName; - symbol->litType = STRING; - } - /* int */ - else { - int v = atoi(symbolName); - int* vp = malloc(sizeof(int)); - *vp = v; - symbol->name = (void*)vp; - free(symbolName); - symbol->litType = INT; - } - symset_add_symbol(symbolSet, symbol); - break; - } - else if (**str == '(') { - (*str)++; - symbolName[i] = '\0'; - sym_t* symbol = malloc(sizeof(sym_t)); - symbol->province = KEY_REF; - symbol->argCount = 0; - if (i > 1) { - symbol->name = symbolName; - } - else { - symbol->name = "root"; - } - symset_t* symbols = parse_symbols(str); - for (int s = 0; s < symbols->count; s++) { - symbol_add_arg(symbol, symbols->symbols[s]); - } - symset_add_symbol(symbolSet, symbol); - break; - } - i++; - (*str)++; - } - } -} -sym_t* parse_symbol_final(char* str) { - char** strp = malloc(sizeof(char**)); - *strp = str; - symset_t* finalSymset = parse_symbols(strp); - sym_t* root = malloc(sizeof(sym_t)); - root->name = "root"; - root->province = KEY_REF; - root->argCount = 0; - for (int s = 0; s < finalSymset->count; s++) { - symbol_add_arg(root, finalSymset->symbols[s]); - } - return root; -} -void write_symbol_visual(sym_t* symbol, int offset) { - for (int o = 0; o < offset; o++) { - printf(" "); - } - if (symbol->province == KEY_REF) { - printf("%s (%s)\n", (char*)(symbol->name), "KEY"); - } - else if (symbol->province == LITERAL) { - if (symbol->litType == INT) { - printf("%d (%s)\n", *(int*)(symbol->name), "LITERAL"); - } - else if (symbol->litType == FLOAT) { - printf("%f (%s)\n", *(float*)(symbol->name), "LITERAL"); - } - else if (symbol->litType == STRING) { - printf("%s (%s)\n", (char*)(symbol->name), "LITERAL"); - } - } - else { - printf("symbol parse error\n"); - } - for (int i = 0; i < symbol->argCount; i++) { - write_symbol_visual(symbol->args[i], offset + 4); - } -} diff --git a/parse.h b/parse.h deleted file mode 100644 index 27ce444..0000000 --- a/parse.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef PARSE -#define PARSE - -/* keyword hashes */ -#define VAR_H 2317739966u -#define DEFINE_H 1788839250 - -typedef enum SymbolProvince { - NO_PROVINCE, - KEY_REF, - LITERAL -} prov_t; -typedef enum LiteralType { - NO_TYPE, - INT, - FLOAT, - STRING -} litType_t; -typedef struct Symbol { - prov_t province; - litType_t litType; - void* name; - struct Symbol** args; - int argCount; -} sym_t; -typedef struct SymbolSet { - sym_t** symbols; - int count; -} symset_t; - -int symtoi(sym_t* symbol); -float symtof(sym_t* symbol); -char* symtos(sym_t* symbol); -void symbol_add_arg(sym_t* symbol, sym_t* arg); -void symset_add_symbol(symset_t* symbolSet, sym_t* symbol); -symset_t* parse_symbols(char** str); -sym_t* parse_symbol_final(char* str); -void write_symbol_visual(sym_t* symbol, int offset); - -#endif diff --git a/precedent.c b/precedent.c deleted file mode 100644 index 81555b9..0000000 --- a/precedent.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include -#include -#include "precedent.h" -#include "hashtable.h" -#include "parse.h" -#include "eval.h" - -int main(int argc, char** argv) { - int visual = 0; - if (argc > 1) { - for (int i = 1; i < argc; i++) { - if (strcmp("--version", argv[i]) == 0) { - printf("precedent, version 0.1\n"); - printf("Copyright 2023 Kai Stevenson\n"); - printf("All rights reserved. No part of the software may be sold\nor used in derivative works without explicit consent\n"); - return 0; - } - else if (strcmp("--help", argv[i]) == 0) { - printf("usage: precedent [--visualize] [--version] [--help]\n"); - return 0; - } - else if (strcmp("--visualize", argv[i]) == 0) { - visual = 1; - } - } - } - else { - printf("usage: precedent [--visualize] [--version] [--help]\n"); - return 0; - } - /* dirname may modify path, copy first */ - char* path = argv[1]; - char* pathCpy = malloc((strlen(path) + 1) * sizeof(char)); - strcpy(pathCpy, path); - char* dirName = dirname(pathCpy); - char* baseDir = malloc((strlen(dirName) + 2) * sizeof(char)); - strcpy(baseDir, dirName); - strcat(baseDir, "/"); - sym_t* finalSymbol = parse_symbol_final(read_file(path)); - if (visual) { - printf("--BEGIN VISUALIZATION--\n"); - write_symbol_visual(finalSymbol, 0); - printf("--END VISUALIZATION--\n"); - } - init_eval(); - eval(finalSymbol); - free(dirName); - free(pathCpy); - free(baseDir); - return 0; -} -char* read_file(char* path) { - FILE* file = fopen(path, "r"); - fseek(file, 0, SEEK_END); - unsigned long int length = ftell(file); - fseek(file, 0, SEEK_SET); - char* out = malloc((length + 1) * sizeof(char)); - fread(out, length, 1, file); - fclose(file); - out[length] = '\0'; - return out; -} -/* wtf */ -char* preprocess(char* str, char* baseDir) { - char* final = str; - while (1) { - int i = 0; - while (str[i] != '@') { - i++; - if (str[i] == '\0') { - printf("%s\n", final); - return final; - } - } - i++; - char* includeName = malloc(20 * sizeof(char)); - int f = 0; - while (isalnum(str[i]) || str[i] == '/' || str[i] == '.' || str[i] == '_') { - includeName[f] = str[i]; - str[i] = ' '; - i++; - f++; - } - final = str; - includeName[f] = '\0'; - char* path = malloc((strlen(baseDir) + strlen(includeName) + 1) * sizeof(char)); - strcpy(path, baseDir); - strcat(path, includeName); - char* toInclude = preprocess(read_file(path), baseDir); - char* newStr = malloc((strlen(toInclude) + strlen(final) + 1) * sizeof(char)); - strcpy(newStr, toInclude); - strcat(newStr, final); - /* - free(includeName); - free(path); - free(str); - free(toInclude); - */ - final = newStr; - } -} diff --git a/precedent.h b/precedent.h deleted file mode 100644 index 8a5110e..0000000 --- a/precedent.h +++ /dev/null @@ -1,7 +0,0 @@ -#include "parse.h" -#include "hashtable.h" -#ifndef PRECEDENT -char* read_file(char* path); -char* preprocess(char* str, char* baseDir); -#define PRECEDENT -#endif diff --git a/scope.c b/scope.c deleted file mode 100644 index afb9d5c..0000000 --- a/scope.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include "scope.h" -#include "hashtable.h" - -scope_t* init_scope(scope_t parent) { - scope_t* scope = malloc(sizeof(scope_t)); - scope->hashtable = init_hashtable(1000); - *(scope->parent) = parent; - return scope; -} -pair_t* get_pair_global(scope_t* scope, char* key) { - while (scope->parent != NULL) { - pair_t* pair = hashtable_get_pair(scope->hashtable, key); - if (pair != NULL) { - return pair; - } - scope = scope->parent; - } - return NULL; -} diff --git a/scope.h b/scope.h deleted file mode 100644 index d1cda0d..0000000 --- a/scope.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "hashtable.h" -#ifndef SCOPE -#define SCOPE - -typedef struct Scope { - hashtable_t* hashtable; - struct Scope* parent; -} scope_t; -scope_t* init_scope(scope_t parent); -pair_t* get_pair_global(scope_t* scope, char* key); -pair_t* get_pair_local(scope_t* scope, char* key); - -#endif diff --git a/src/eval.c b/src/eval.c new file mode 100644 index 0000000..b1d4e0a --- /dev/null +++ b/src/eval.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include "eval.h" +#include "hashtable.h" +#include "parse.h" + +hashtable_t* ht; +const int hashtableSize = 1000; +const int trueVal = 1; +sym_t trueSym = {LITERAL, INT, (void*)&trueVal, NULL, 0}; +const int falseVal = 0; +sym_t falseSym = {LITERAL, INT, (void*)&falseVal, NULL, 0}; + +void init_eval() { + ht = init_hashtable(hashtableSize); +} +/* TODO: read base hashtable from file to allow modularity +pair value value? */ +void exec_all(sym_t** symbols, int count) { + for (int i = 0; i < count; i++) { + /* dispose of result */ + eval(symbols[i]); + } +} +sym_t* eval(sym_t* symbol) { + if (symbol->province == LITERAL) { + return(symbol); + } + else if (symbol->province == KEY_REF) { + sym_t* ir = try_eval_internal(symbol); + if (ir != NULL) { + return ir; + } + else { + /* not an internal function, search hashtable for + next symbol */ + /* TODO: scope */ + pair_t* p = hashtable_get_pair(ht, (char*)symbol->name); + if (p != NULL) { + return eval((sym_t*)p->value); + } + else { + printf("no matching pair in hashtable\n"); + return NULL; + } + } + } + else { + printf("no symbol province\n"); + return NULL; + } +} +/* internal functions? +this function has side-effects */ +sym_t* try_eval_internal(sym_t* symbol) { + unsigned int hash = get_hash((char*)symbol->name); + /* TODO: return last arg. that's the function return line */ + if (hash == get_hash("root")) { + /* execute all args as roots */ + exec_all(symbol->args, symbol->argCount); + return &trueSym; + } + else if (hash == get_hash("store")) { + /* TODO: scope */ + /* first arg is value, remaining args are names */ + /* TODO: recursion for multiple pairs */ + char* k = symtos(eval(symbol->args[1])); + sym_t* v = symbol->args[0]; + pair_t* p = init_pair(k, (void*)v); + hashtable_add_pair(ht, p); + return &trueSym; + } + /* TODO: release()/free() method? */ + else if (hash == get_hash("eq")) { + litType_t type = NO_TYPE; + void* lastVal = NULL; + for (int i = 0; i < symbol->argCount; i++) { + sym_t* v = eval(symbol->args[i]); + /* initialize */ + if (type == NO_TYPE) { + type = v->litType; + lastVal = v->name; + } + else { + /* interpret type */ + if (type == INT) { + if (symtoi(v) != *((int*)lastVal)) { + return &falseSym; + } + } + if (type == STRING) { + if (strcmp(symtos(v), (char*)lastVal) != 0) { + return &falseSym; + } + } + /* TODO: float */ + } + } + return &trueSym; + } + else if (hash == get_hash("if")) { + sym_t* v = eval(symbol->args[0]); + if (symtoi(v) != 0) { + exec_all(symbol->args + 1, symbol->argCount - 1); + return &trueSym; + } + return &falseSym; + } + else if (hash == get_hash("not")) { + sym_t* v = eval(symbol->args[0]); + int b = symtoi(v); + return b ? &falseSym : &trueSym; + } + else if (hash == get_hash("print")) { + sym_t* v = eval(symbol->args[0]); + switch (v->litType) { + case NO_TYPE: + break; + case INT: + printf("%d\n", symtoi(v)); + break; + case FLOAT: + break; + case STRING: + printf("%s\n", symtos(v)); + break; + } + return &trueSym; + } + else { + return NULL; + } +} diff --git a/src/eval.h b/src/eval.h new file mode 100644 index 0000000..b91c621 --- /dev/null +++ b/src/eval.h @@ -0,0 +1,9 @@ +#include "parse.h" +#ifndef EVAL +#define EVAL +void init_eval(void); +void throw(char* error, int symbolLocale); +void exec_all(sym_t** symbols, int count); +sym_t* eval(sym_t* symbol); +sym_t* try_eval_internal(sym_t* symbol); +#endif diff --git a/src/hashtable.c b/src/hashtable.c new file mode 100644 index 0000000..7cb253c --- /dev/null +++ b/src/hashtable.c @@ -0,0 +1,39 @@ +#include +#include +#include "hashtable.h" + +const unsigned int fnvPrime = 16777619; +const unsigned int fnvOffset = 2166136261U; + +pair_t* init_pair(char* key, void* value) { + pair_t* p = malloc(sizeof(pair_t)); + p->key = key; + p->value = value; + return p; +} +hashtable_t* init_hashtable(unsigned int capacity) { + hashtable_t* ht = malloc(sizeof(hashtable_t)); + ht->pairs = calloc(capacity, sizeof(pair_t*)); + ht->capacity = capacity; + return ht; +} +//FNV-1a hash +unsigned int get_hash(char* str) { + unsigned int hash = fnvOffset; + while (*str != '\0') { + hash = (hash ^ *str) * fnvPrime; + str++; + } + return hash; +} +/* TODO: handle collision +TODO: return 0 if something goes wrong */ +unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair) { + unsigned int hash = get_hash(pair->key); + hashtable->pairs[hash % hashtable->capacity] = pair; + return hash; +} +pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key) { + unsigned int hash = get_hash(key); + return hashtable->pairs[hash % hashtable->capacity]; +} diff --git a/src/hashtable.h b/src/hashtable.h new file mode 100644 index 0000000..43ab23a --- /dev/null +++ b/src/hashtable.h @@ -0,0 +1,19 @@ +#ifndef HASHTABLE +#define HASHTABLE + +typedef struct HashPair { + char* key; + void* value; +} pair_t; +pair_t* init_pair(char* key, void* value); +typedef struct HashTable { + pair_t** pairs; + int capacity; + int itemCount; +} hashtable_t; +hashtable_t* init_hashtable(unsigned int capacity); +unsigned int get_hash(char* str); +unsigned int hashtable_add_pair(hashtable_t* hashtable, pair_t* pair); +pair_t* hashtable_get_pair(hashtable_t* hashtable, char* key); + +#endif diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..27ee417 --- /dev/null +++ b/src/parse.c @@ -0,0 +1,143 @@ +#include +#include +#include +#include +#include "parse.h" +#include "hashtable.h" + +int symtoi(sym_t* symbol) { + return *((int*)symbol->name); +} +float symtof(sym_t* symbol) { + return *((float*)symbol->name); +} +char* symtos(sym_t* symbol) { + return (char*)symbol->name; +} + +void symbol_add_arg(sym_t* symbol, sym_t* arg) { + symbol->argCount += 1; + if (symbol->argCount == 1) { + symbol->args = malloc(sizeof(sym_t*)); + } + else { + symbol->args = realloc(symbol->args, symbol->argCount * (sizeof(sym_t*))); + } + (symbol->args)[symbol->argCount - 1] = arg; +} +void symset_add_symbol(symset_t* symbolSet, sym_t* symbol) { + symbolSet->count += 1; + if (symbolSet->count == 1) { + symbolSet->symbols = malloc(sizeof(sym_t*)); + } + else { + symbolSet->symbols = realloc(symbolSet->symbols, symbolSet->count * (sizeof(sym_t*))); + } + (symbolSet->symbols)[symbolSet->count - 1] = symbol; +} +symset_t* parse_symbols(char** str) { + symset_t* symbolSet = malloc(sizeof(symset_t)); + symbolSet->count = 0; + while (1) { + /* clear whitespace */ + while (!isalnum(**str) && **str != '(' && **str != ')' && **str != '\0') { + (*str)++; + } + if (**str == ')') { + (*str)++; + return symbolSet; + } + else if (**str == '\0') { + return symbolSet; + } + char* symbolName = calloc(30, sizeof(char)); + int i = 0; + while (1) { + symbolName[i] = **str; + if (**str == ',' || **str == ';') { + (*str)++; + sym_t* symbol = malloc(sizeof(sym_t)); + symbol->province = LITERAL; + symbol->argCount = 0; + symbolName[i] = '\0'; + /* TODO: float */ + /* string */ + if (isalpha(symbolName[0])) { + //symbolName = realloc(symbolName, i * sizeof(char)); + symbol->name = symbolName; + symbol->litType = STRING; + } + /* int */ + else { + int v = atoi(symbolName); + int* vp = malloc(sizeof(int)); + *vp = v; + symbol->name = (void*)vp; + free(symbolName); + symbol->litType = INT; + } + symset_add_symbol(symbolSet, symbol); + break; + } + else if (**str == '(') { + (*str)++; + symbolName[i] = '\0'; + sym_t* symbol = malloc(sizeof(sym_t)); + symbol->province = KEY_REF; + symbol->argCount = 0; + if (i > 1) { + symbol->name = symbolName; + } + else { + symbol->name = "root"; + } + symset_t* symbols = parse_symbols(str); + for (int s = 0; s < symbols->count; s++) { + symbol_add_arg(symbol, symbols->symbols[s]); + } + symset_add_symbol(symbolSet, symbol); + break; + } + i++; + (*str)++; + } + } +} +sym_t* parse_symbol_final(char* str) { + char** strp = malloc(sizeof(char**)); + *strp = str; + symset_t* finalSymset = parse_symbols(strp); + sym_t* root = malloc(sizeof(sym_t)); + root->name = "root"; + root->province = KEY_REF; + root->argCount = 0; + for (int s = 0; s < finalSymset->count; s++) { + symbol_add_arg(root, finalSymset->symbols[s]); + } + return root; +} +void write_symbol_visual(sym_t* symbol, int offset) { + for (int o = 0; o < offset; o++) { + printf(" "); + } + if (symbol->province == KEY_REF) { + printf("%s (%s)\n", (char*)(symbol->name), "KEY"); + } + else if (symbol->province == LITERAL) { + if (symbol->litType == INT) { + printf("%d (%s)\n", *(int*)(symbol->name), "LITERAL"); + } + else if (symbol->litType == FLOAT) { + printf("%f (%s)\n", *(float*)(symbol->name), "LITERAL"); + } + else if (symbol->litType == STRING) { + printf("%s (%s)\n", (char*)(symbol->name), "LITERAL"); + } + } + else { + printf("symbol parse error\n"); + } + for (int i = 0; i < symbol->argCount; i++) { + write_symbol_visual(symbol->args[i], offset + 4); + } +} diff --git a/src/parse.h b/src/parse.h new file mode 100644 index 0000000..27ce444 --- /dev/null +++ b/src/parse.h @@ -0,0 +1,40 @@ +#ifndef PARSE +#define PARSE + +/* keyword hashes */ +#define VAR_H 2317739966u +#define DEFINE_H 1788839250 + +typedef enum SymbolProvince { + NO_PROVINCE, + KEY_REF, + LITERAL +} prov_t; +typedef enum LiteralType { + NO_TYPE, + INT, + FLOAT, + STRING +} litType_t; +typedef struct Symbol { + prov_t province; + litType_t litType; + void* name; + struct Symbol** args; + int argCount; +} sym_t; +typedef struct SymbolSet { + sym_t** symbols; + int count; +} symset_t; + +int symtoi(sym_t* symbol); +float symtof(sym_t* symbol); +char* symtos(sym_t* symbol); +void symbol_add_arg(sym_t* symbol, sym_t* arg); +void symset_add_symbol(symset_t* symbolSet, sym_t* symbol); +symset_t* parse_symbols(char** str); +sym_t* parse_symbol_final(char* str); +void write_symbol_visual(sym_t* symbol, int offset); + +#endif diff --git a/src/precedent.c b/src/precedent.c new file mode 100644 index 0000000..81555b9 --- /dev/null +++ b/src/precedent.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include "precedent.h" +#include "hashtable.h" +#include "parse.h" +#include "eval.h" + +int main(int argc, char** argv) { + int visual = 0; + if (argc > 1) { + for (int i = 1; i < argc; i++) { + if (strcmp("--version", argv[i]) == 0) { + printf("precedent, version 0.1\n"); + printf("Copyright 2023 Kai Stevenson\n"); + printf("All rights reserved. No part of the software may be sold\nor used in derivative works without explicit consent\n"); + return 0; + } + else if (strcmp("--help", argv[i]) == 0) { + printf("usage: precedent [--visualize] [--version] [--help]\n"); + return 0; + } + else if (strcmp("--visualize", argv[i]) == 0) { + visual = 1; + } + } + } + else { + printf("usage: precedent [--visualize] [--version] [--help]\n"); + return 0; + } + /* dirname may modify path, copy first */ + char* path = argv[1]; + char* pathCpy = malloc((strlen(path) + 1) * sizeof(char)); + strcpy(pathCpy, path); + char* dirName = dirname(pathCpy); + char* baseDir = malloc((strlen(dirName) + 2) * sizeof(char)); + strcpy(baseDir, dirName); + strcat(baseDir, "/"); + sym_t* finalSymbol = parse_symbol_final(read_file(path)); + if (visual) { + printf("--BEGIN VISUALIZATION--\n"); + write_symbol_visual(finalSymbol, 0); + printf("--END VISUALIZATION--\n"); + } + init_eval(); + eval(finalSymbol); + free(dirName); + free(pathCpy); + free(baseDir); + return 0; +} +char* read_file(char* path) { + FILE* file = fopen(path, "r"); + fseek(file, 0, SEEK_END); + unsigned long int length = ftell(file); + fseek(file, 0, SEEK_SET); + char* out = malloc((length + 1) * sizeof(char)); + fread(out, length, 1, file); + fclose(file); + out[length] = '\0'; + return out; +} +/* wtf */ +char* preprocess(char* str, char* baseDir) { + char* final = str; + while (1) { + int i = 0; + while (str[i] != '@') { + i++; + if (str[i] == '\0') { + printf("%s\n", final); + return final; + } + } + i++; + char* includeName = malloc(20 * sizeof(char)); + int f = 0; + while (isalnum(str[i]) || str[i] == '/' || str[i] == '.' || str[i] == '_') { + includeName[f] = str[i]; + str[i] = ' '; + i++; + f++; + } + final = str; + includeName[f] = '\0'; + char* path = malloc((strlen(baseDir) + strlen(includeName) + 1) * sizeof(char)); + strcpy(path, baseDir); + strcat(path, includeName); + char* toInclude = preprocess(read_file(path), baseDir); + char* newStr = malloc((strlen(toInclude) + strlen(final) + 1) * sizeof(char)); + strcpy(newStr, toInclude); + strcat(newStr, final); + /* + free(includeName); + free(path); + free(str); + free(toInclude); + */ + final = newStr; + } +} diff --git a/src/precedent.h b/src/precedent.h new file mode 100644 index 0000000..8a5110e --- /dev/null +++ b/src/precedent.h @@ -0,0 +1,7 @@ +#include "parse.h" +#include "hashtable.h" +#ifndef PRECEDENT +char* read_file(char* path); +char* preprocess(char* str, char* baseDir); +#define PRECEDENT +#endif diff --git a/src/scope.c b/src/scope.c new file mode 100644 index 0000000..afb9d5c --- /dev/null +++ b/src/scope.c @@ -0,0 +1,20 @@ +#include +#include "scope.h" +#include "hashtable.h" + +scope_t* init_scope(scope_t parent) { + scope_t* scope = malloc(sizeof(scope_t)); + scope->hashtable = init_hashtable(1000); + *(scope->parent) = parent; + return scope; +} +pair_t* get_pair_global(scope_t* scope, char* key) { + while (scope->parent != NULL) { + pair_t* pair = hashtable_get_pair(scope->hashtable, key); + if (pair != NULL) { + return pair; + } + scope = scope->parent; + } + return NULL; +} diff --git a/src/scope.h b/src/scope.h new file mode 100644 index 0000000..d1cda0d --- /dev/null +++ b/src/scope.h @@ -0,0 +1,13 @@ +#include "hashtable.h" +#ifndef SCOPE +#define SCOPE + +typedef struct Scope { + hashtable_t* hashtable; + struct Scope* parent; +} scope_t; +scope_t* init_scope(scope_t parent); +pair_t* get_pair_global(scope_t* scope, char* key); +pair_t* get_pair_local(scope_t* scope, char* key); + +#endif -- cgit v1.3.1