diff options
author | Preston Pan <preston@nullring.xyz> | 2023-01-07 09:54:40 -0800 |
---|---|---|
committer | Preston Pan <preston@nullring.xyz> | 2023-01-07 09:54:40 -0800 |
commit | 4581329cde6cfb64399be48f58d67310ab19ee1b (patch) | |
tree | c76893896ae4375c618ecffad71fa9ffb3717be2 | |
parent | c620d528fb9d9efbac559002d23857623e71df05 (diff) |
include working
-rw-r--r-- | README.md | 60 | ||||
-rw-r--r-- | doc/fib.nxs | 5 | ||||
-rw-r--r-- | doc/main.nxs | 5 | ||||
-rw-r--r-- | hash_table_new.c | 130 | ||||
-rw-r--r-- | src/hash_table.c | 1 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/parser.c | 80 |
7 files changed, 139 insertions, 146 deletions
@@ -8,8 +8,58 @@ I plan to add support for macros and other stuff. This is a functional programming language so functions are first-class. ## TODO -- [X] Write the lexer -- [X] Write the parser -- [X] Write hash table -- [X] Write the visitor -- [ ] Write the print functions +Each todo here represents one task that I have not done. +Note that all the tasks that I finished are bigger than +the ones that I have not, and that is simply because I +made this checklist after I did everything in the first +checklist. + +Estimate: 90% done. + +### DONE +- [X] Write the lexer (easy) +- [X] Write the parser (medium-hard) +- [X] Write hash table (medium) +- [X] Write the visitor (hard) +- [X] Write a few print functions (trivial) + +### NOT DONE +- [ ] Write the print function for lists (trivial) +- [ ] Implement macros (medium) +- [ ] Implement a primitive include system (easy-medium) +- [ ] Finish type conversion builtins (easy) +- [ ] Finish read and write builtins (easy) + +### Wishlist +- [ ] Maybe a garbage collector? +- [ ] Write a standard library for math and other utilities + +## BUILDING +To build and install this program on unix-likes, run: +`make && sudo make install` + +## SYNTAX +Programming in this language, you may find some differences from scheme. Here are the basics: +1. You can define anonymous functions with `lambda`. All functions are first class and also self evaluating expressions. +2. Each anonymous function can contain exactly one expression. +3. Each function may have an arbitrary amount of parameters (at least, as many as possible before memory problems occur). +4. String, integer, float, boolean, function, list, and symbol types are supported. +5. You may bind a symbol to an expression in order to create a global variable with `bind`. +6. There are several primitive functions from which you may build more complicated functions. +7. Each final evaluated value will be printed. + +You may find actual code examples in `doc/`. Also, there will be more functionality than +the above, but I have not implemented it yet. Some future ones are: + +8. The only side effects are printing evaluated expressions and writing to files with the `write` builtin. +9. You may define macros. +10. Let's all have fun and play together! + +Wait a second, that last one isn't one of the rules... + +## CONTRIBUTING +If you send diffs to me that improve this code, chances are I will accept the diffs and +try to merge them in. + +## LICENSE +See `./LICENSE`. diff --git a/doc/fib.nxs b/doc/fib.nxs index e09e7a4..59755c8 100644 --- a/doc/fib.nxs +++ b/doc/fib.nxs @@ -1,8 +1,3 @@ ;; Author: Andrei S (bind fib (lambda (x) ;; xth fib number (if (< x 2) x (+ (fib (- x 1)) (fib (- x 2)))))) - -(fib 7) - -(bind fibseq (lambda (n) -(if (= 0 n) 0 (begin (+ n 1) (fib n))))) diff --git a/doc/main.nxs b/doc/main.nxs index 212f098..76fc95f 100644 --- a/doc/main.nxs +++ b/doc/main.nxs @@ -1,6 +1,5 @@ - +(include "fib.nxs") (bind factorial (lambda (n) (if (= n 0) 1 (* n (factorial (- n 1)))))) - +(fib 7) (+ (factorial 5) 10) -"hello world!" diff --git a/hash_table_new.c b/hash_table_new.c deleted file mode 100644 index 8722a60..0000000 --- a/hash_table_new.c +++ /dev/null @@ -1,130 +0,0 @@ -#include "./include/hash_table.h" -#include "./include/ast.h" -#include "./include/macros.h" -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -pair_t *init_pair(char *key, ast_t *value) { - pair_t *p = (pair_t *)malloc(sizeof(pair_t)); - if (p == NULL) - die("malloc on pair"); - p->key = key; - p->value = value; - return p; -} - -sl_node_t *init_sl_node(char *key, ast_t *value) { - sl_node_t *n = (sl_node_t *)malloc(sizeof(sl_node_t)); - if (n == NULL) - die("malloc on node"); - n->value = init_pair(key, value); - n->next = NULL; - return n; -} - -/*** SINGLY LINKED LIST FUNCTIONS ***/ -sl_list_t *init_sl_list() { - sl_list_t *l = (sl_list_t *)malloc(sizeof(sl_list_t)); - if (l == NULL) - die("malloc on list"); - l->size = 0; - l->head = NULL; - return l; -} - -/* TODO: fix segfault bug */ -void sl_list_add(sl_list_t *l, char *key, ast_t *value) { - if (l->head == NULL) { - l->head = init_sl_node(key, value); - l->size++; - return; - } else { - sl_node_t *cur = l->head; - while (cur->next != NULL) - cur = cur->next; - cur->next = init_sl_node(key, value); - l->size++; - } -} - -ast_t *sl_list_get(sl_list_t *l, char *key) { - sl_node_t *cur = l->head; - printf("in hash table get\n"); - while (cur != NULL) { - if (cur->value == NULL) { - printf("unlucky\n"); - } - if (strcmp(cur->value->key, key) == 0) - return cur->value->value; - cur = cur->next; - } - return NULL; -} - -bool sl_list_exists(sl_list_t *l, char *key) { - if (sl_list_get(l, key) != NULL) - return true; - return false; -} - -void sl_list_free(sl_list_t *l) { - sl_node_t *cur = l->head; - sl_node_t *tmp; - while (cur != NULL) { - tmp = cur; - cur = cur->next; - free(cur); - } - free(l); -} - -/*** HASH TABLE FUNCTIONS ***/ -hash_table_t *init_hash_table(int size) { - hash_table_t *h = (hash_table_t *)malloc(sizeof(hash_table_t)); - if (h == NULL) - die("malloc on hash table"); - h->size = size; - h->buckets = malloc(sizeof(sl_list_t *)); - if (h->buckets == NULL) - die("malloc on buckets"); - for (int i = 0; i < h->size; i++) - h->buckets[i] = init_sl_list(); - return h; -} - -void hash_table_add(hash_table_t *h, char *key, ast_t *value) { - if (hash_table_exists(h, key)) { - printf("BUG!\n"); - return; - } - sl_list_t *l = h->buckets[hash(key, h->size)]; - sl_list_add(l, key, value); -} - -ast_t *hash_table_get(hash_table_t *h, char *key) { - sl_list_t *l = h->buckets[hash(key, h->size)]; - return sl_list_get(l, key); -} - -bool hash_table_exists(hash_table_t *h, char *key) { - printf("in hash table\n"); - sl_list_t *l = h->buckets[hash(key, h->size)]; - return sl_list_exists(l, key); -} - -void hash_table_free(hash_table_t *h) { - for (int i = 0; i < h->size; i++) - sl_list_free(h->buckets[i]); - free(h); -} - -/* DJB2 HASH FUNCTION */ -unsigned long hash(char *key, int size) { - unsigned long hash = 5381; - int c; - while ((c = *key++)) - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - return hash % size; -} diff --git a/src/hash_table.c b/src/hash_table.c index bd947c0..6648bd1 100644 --- a/src/hash_table.c +++ b/src/hash_table.c @@ -77,6 +77,7 @@ void sl_list_add(sl_list_t *l, char *key, ast_t *value) { l->size++; } } + ast_t *sl_list_get(sl_list_t *l, char *key) { sl_node_t *cur = l->head; for (int i = 0; i < l->size; i++) { @@ -131,6 +131,10 @@ int main(int argc, char **argv) { printf("TOO FEW ARGUMENTS.\n"); exit(1); } + if (strcmp(argv[1], "-v") == 0 || strcmp(argv[1], "--version") == 0) { + printf("nxs, version 1.0.0 alpha\n"); + exit(0); + } char *filename = argv[1]; char *buffer = 0; diff --git a/src/parser.c b/src/parser.c index 0a2b213..157bc4d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -7,14 +7,14 @@ #include <stdlib.h> #include <string.h> -parser_t *init_parser(lexer_t *lexer) { +parser_t *init_parser_copy_hash(lexer_t *lexer, hash_table_t *h) { parser_t *p = (parser_t *)malloc(sizeof(parser_t)); if (p == NULL) die("malloc on parser"); p->i = 0; p->tokens = malloc(sizeof(token_t *)); - p->symbol_table = init_hash_table(100); + p->symbol_table = h; p->finished = false; if (p->tokens == NULL) die("malloc on p->tokens"); @@ -34,6 +34,36 @@ parser_t *init_parser(lexer_t *lexer) { p->size = size; return p; } +parser_t *init_parser(lexer_t *lexer) { + return init_parser_copy_hash(lexer, init_hash_table(100)); +} +/* parser_t *init_parser(lexer_t *lexer) { */ +/* parser_t *p = (parser_t *)malloc(sizeof(parser_t)); */ +/* if (p == NULL) */ +/* die("malloc on parser"); */ + +/* p->i = 0; */ +/* p->tokens = malloc(sizeof(token_t *)); */ +/* p->symbol_table = init_hash_table(100); */ +/* p->finished = false; */ +/* if (p->tokens == NULL) */ +/* die("malloc on p->tokens"); */ + +/* int size = 1; */ +/* token_t *t = lexer_collect_next(lexer); */ +/* p->tokens[size - 1] = t; */ + +/* while (true) { */ +/* t = lexer_collect_next(lexer); */ +/* size++; */ +/* p->tokens = realloc(p->tokens, size * sizeof(token_t *)); */ +/* p->tokens[size - 1] = t; */ +/* if (t == NULL) */ +/* break; */ +/* } */ +/* p->size = size; */ +/* return p; */ +/* } */ void parser_move(parser_t *parser) { if (parser->i != parser->size - 1) @@ -142,7 +172,41 @@ void parse_bind(parser_t *parser) { parser_move(parser); } -ast_t *parse_include(parser_t *parser) { parser_eat(parser, TOKEN_STRING); } +ast_t *parse_include(parser_t *parser) { + parser_move(parser); + if (parser->tokens[parser->i]->type != TOKEN_STRING) + parser_error(parser); + char *filename = parser->tokens[parser->i]->value; + char *buffer = 0; + long length; + FILE *f = fopen(filename, "rb"); + + if (f) { + fseek(f, 0, SEEK_END); + length = ftell(f); + fseek(f, 0, SEEK_SET); + buffer = malloc(length); + if (buffer) { + fread(buffer, 1, length, f); + } + fclose(f); + } else { + parser_error(parser); + } + if (buffer) { + lexer_t *lexer = init_lexer(buffer); + parser_t *p = init_parser_copy_hash(lexer, parser->symbol_table); + ast_t *root = parse_all(p); + parser_move(parser); + if (parser->tokens[parser->i]->type != TOKEN_RPAREN) + parser_error(parser); + parser_move(parser); + return root; + } else { + parser_error(parser); + } + return NULL; +} ast_t *parse_list(parser_t *parser) { ast_t *car; @@ -159,6 +223,8 @@ ast_t *parse_list(parser_t *parser) { } else if (strcmp(current_token->value, "bind") == 0 && first_entry) { parse_bind(parser); return NULL; + } else if (strcmp(current_token->value, "include") == 0 && first_entry) { + return parse_include(parser); } else { car = parse_symbol(parser); } @@ -228,6 +294,14 @@ ast_t *parse_all(parser_t *parser) { if (cur == NULL) { t = parser->tokens[parser->i]; continue; + } else if (cur->type == AST_ROOT) { + for (int j = 0; j < cur->root_size; j++) { + i++; + asts = realloc(asts, i * sizeof(ast_t *)); + asts[i - 1] = cur->subnodes[j]; + } + t = parser->tokens[parser->i]; + continue; } i++; asts = realloc(asts, i * sizeof(ast_t *)); |