summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPreston Pan <preston@nullring.xyz>2023-01-07 09:54:40 -0800
committerPreston Pan <preston@nullring.xyz>2023-01-07 09:54:40 -0800
commit4581329cde6cfb64399be48f58d67310ab19ee1b (patch)
treec76893896ae4375c618ecffad71fa9ffb3717be2
parentc620d528fb9d9efbac559002d23857623e71df05 (diff)
include working
-rw-r--r--README.md60
-rw-r--r--doc/fib.nxs5
-rw-r--r--doc/main.nxs5
-rw-r--r--hash_table_new.c130
-rw-r--r--src/hash_table.c1
-rw-r--r--src/main.c4
-rw-r--r--src/parser.c80
7 files changed, 139 insertions, 146 deletions
diff --git a/README.md b/README.md
index a05b2c1..25e5db9 100644
--- a/README.md
+++ b/README.md
@@ -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++) {
diff --git a/src/main.c b/src/main.c
index bbe725c..5315549 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 *));