summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--README.md3
-rw-r--r--src/hash_table.c121
-rw-r--r--src/include/ast.h42
-rw-r--r--src/include/hash_table.h47
-rw-r--r--src/include/lexer.h39
-rw-r--r--src/include/macros.h85
-rw-r--r--src/include/parser.h49
-rw-r--r--src/include/print.h16
-rw-r--r--src/include/sl_list.h23
-rw-r--r--src/include/stack.h16
-rw-r--r--src/include/token.h22
-rw-r--r--src/include/visitor.h26
-rw-r--r--src/lexer.c150
-rw-r--r--src/macros.c10
-rw-r--r--src/main.c39
-rw-r--r--src/parser.c125
-rw-r--r--src/stack.c34
-rw-r--r--src/token.c15
-rw-r--r--src/visitor.c25
20 files changed, 888 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b5c13cc
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+src/a.out
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..14e5737
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# NoExcess
+This is basically a scheme-like language that is aimed to
+be scheme with no additional fluff. Currently does not work.
diff --git a/src/hash_table.c b/src/hash_table.c
new file mode 100644
index 0000000..9384945
--- /dev/null
+++ b/src/hash_table.c
@@ -0,0 +1,121 @@
+#include "./include/hash_table.h"
+#include "./include/ast.h"
+#include "./include/macros.h"
+#include <stdbool.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;
+}
+
+void sl_list_add(sl_list_t *l, char *key, ast_t *value) {
+ sl_node_t *cur = l->head;
+ bool modified = false;
+ if (l->head == NULL) {
+ l->head = init_sl_node(key, value);
+ l->size++;
+ }
+
+ for (int i = 0; i < l->size - 1; i++) {
+ if (strcmp(cur->value->key, key) == 0) {
+ cur->value->value = value;
+ modified = true;
+ break;
+ }
+ cur = cur->next;
+ }
+ if (strcmp(cur->value->key, key) == 0) {
+ cur->value->value = value;
+ modified = true;
+ }
+
+ if (!modified) {
+ 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;
+ for (int i = 0; i < l->size; i++) {
+ if (strcmp(cur->value->key, key) == 0)
+ return cur->value->value;
+ cur = cur->next;
+ }
+ return NULL;
+}
+
+void sl_list_free(sl_list_t *l) {
+ sl_node_t *cur = l->head;
+ sl_node_t *tmp;
+ for (int i = 0; i < l->size; i++) {
+ tmp = cur;
+ cur = cur->next;
+ free(tmp);
+ }
+ 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) {
+ 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);
+}
+
+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/include/ast.h b/src/include/ast.h
new file mode 100644
index 0000000..f7be3d5
--- /dev/null
+++ b/src/include/ast.h
@@ -0,0 +1,42 @@
+#ifndef AST_H
+#define AST_H
+#include <stdbool.h>
+
+typedef struct AST_STRUCT {
+ enum {
+ /* complex types */
+ AST_PAIR,
+ AST_SYMBOL,
+ /* self evaluating types */
+ AST_STRING,
+ AST_BOOL,
+ AST_INT,
+ AST_FLOAT,
+ AST_FUNCTION,
+ } type;
+
+ /* For functions, the car will be a list of variables, and the cdr will be the
+ * expression */
+ struct AST_STRUCT *car;
+ struct AST_STRUCT *cdr;
+
+ char *string_value;
+ int int_value;
+ double float_value;
+ bool bool_value;
+} ast_t;
+
+ast_t *init_ast_string(char *value);
+
+ast_t *init_ast_int(int value);
+
+ast_t *init_ast_float(double value);
+
+ast_t *init_ast_pair(ast_t *car, ast_t *cdr);
+
+ast_t *init_ast_bool(bool value);
+
+ast_t *init_ast_symbol(char *value);
+
+ast_t *init_ast_function(ast_t *car, ast_t *cdr);
+#endif
diff --git a/src/include/hash_table.h b/src/include/hash_table.h
new file mode 100644
index 0000000..df2d368
--- /dev/null
+++ b/src/include/hash_table.h
@@ -0,0 +1,47 @@
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
+#include "./ast.h"
+
+typedef struct {
+ char *key;
+ ast_t *value;
+} pair_t;
+
+typedef struct SL_NODE_STRUCT {
+ pair_t *value;
+ struct SL_NODE_STRUCT *next;
+} sl_node_t;
+
+typedef struct {
+ sl_node_t *head;
+ int size;
+} sl_list_t;
+
+typedef struct {
+ int size;
+ sl_list_t **buckets;
+} hash_table_t;
+
+pair_t *init_pair(char *key, ast_t *value);
+
+sl_node_t *init_sl_node(char *key, ast_t *value);
+
+sl_list_t *init_sl_list();
+
+void sl_list_add(sl_list_t *l, char *key, ast_t *value);
+
+ast_t *sl_list_get(sl_list_t *l, char *key);
+
+void sl_list_free(sl_list_t *l);
+
+hash_table_t *init_hash_table(int size);
+
+void hash_table_add(hash_table_t *h, char *key, ast_t *value);
+
+ast_t *hash_table_get(hash_table_t *h, char *key);
+
+unsigned long hash(char *key, int size);
+
+void hash_table_free(hash_table_t *h);
+
+#endif
diff --git a/src/include/lexer.h b/src/include/lexer.h
new file mode 100644
index 0000000..36c5db8
--- /dev/null
+++ b/src/include/lexer.h
@@ -0,0 +1,39 @@
+#ifndef LEXER_H
+#define LEXER_H
+
+#include "./token.h"
+
+#include <stdbool.h>
+
+typedef struct {
+ char *source;
+ int i;
+ char c;
+
+ int row;
+ int col;
+ bool finished;
+} lexer_t;
+
+void lexer_reset(lexer_t *lexer, char *source);
+
+lexer_t *init_lexer(char *source);
+
+void lexer_move(lexer_t *lexer);
+
+void lexer_skip_whitespace(lexer_t *lexer);
+
+void lexer_skip_comment(lexer_t *lexer);
+
+token_t *lexer_collect_bool(lexer_t *lexer);
+
+token_t *lexer_collect_id(lexer_t *lexer);
+
+token_t *lexer_collect_num(lexer_t *lexer);
+
+token_t *lexer_collect_string(lexer_t *lexer);
+
+token_t *lexer_collect_next(lexer_t *lexer);
+
+void lexer_error(lexer_t *lexer);
+#endif
diff --git a/src/include/macros.h b/src/include/macros.h
new file mode 100644
index 0000000..ee89597
--- /dev/null
+++ b/src/include/macros.h
@@ -0,0 +1,85 @@
+#ifndef MACROS_H
+#define MACROS_H
+/*
+ * This is free and unencumbered software released into the public domain.
+ * For more information, please refer to <https://unlicense.org>. Code snippet
+ * taken from
+ * https://gist.github.com/RabaDabaDoba/145049536f815903c79944599c6f952a.
+ */
+
+/* Regular text */
+#define BLK "\e[0;30m"
+#define RED "\e[0;31m"
+#define GRN "\e[0;32m"
+#define YEL "\e[0;33m"
+#define BLU "\e[0;34m"
+#define MAG "\e[0;35m"
+#define CYN "\e[0;36m"
+#define WHT "\e[0;37m"
+
+/* Regular bold text */
+#define BBLK "\e[1;30m"
+#define BRED "\e[1;31m"
+#define BGRN "\e[1;32m"
+#define BYEL "\e[1;33m"
+#define BBLU "\e[1;34m"
+#define BMAG "\e[1;35m"
+#define BCYN "\e[1;36m"
+#define BWHT "\e[1;37m"
+
+/* Regular underline text */
+#define UBLK "\e[4;30m"
+#define URED "\e[4;31m"
+#define UGRN "\e[4;32m"
+#define UYEL "\e[4;33m"
+#define UBLU "\e[4;34m"
+#define UMAG "\e[4;35m"
+#define UCYN "\e[4;36m"
+#define UWHT "\e[4;37m"
+
+/* Regular background */
+#define BLKB "\e[40m"
+#define REDB "\e[41m"
+#define GRNB "\e[42m"
+#define YELB "\e[43m"
+#define BLUB "\e[44m"
+#define MAGB "\e[45m"
+#define CYNB "\e[46m"
+#define WHTB "\e[47m"
+
+/* High intensty background */
+#define BLKHB "\e[0;100m"
+#define REDHB "\e[0;101m"
+#define GRNHB "\e[0;102m"
+#define YELHB "\e[0;103m"
+#define BLUHB "\e[0;104m"
+#define MAGHB "\e[0;105m"
+#define CYNHB "\e[0;106m"
+#define WHTHB "\e[0;107m"
+
+/* High intensty text */
+#define HBLK "\e[0;90m"
+#define HRED "\e[0;91m"
+#define HGRN "\e[0;92m"
+#define HYEL "\e[0;93m"
+#define HBLU "\e[0;94m"
+#define HMAG "\e[0;95m"
+#define HCYN "\e[0;96m"
+#define HWHT "\e[0;97m"
+
+/* Bold high intensity text */
+#define BHBLK "\e[1;90m"
+#define BHRED "\e[1;91m"
+#define BHGRN "\e[1;92m"
+#define BHYEL "\e[1;93m"
+#define BHBLU "\e[1;94m"
+#define BHMAG "\e[1;95m"
+#define BHCYN "\e[1;96m"
+#define BHWHT "\e[1;97m"
+
+#define reset "\e[0m"
+#define CRESET "\e[0m"
+#define COLOR_RESET "\e[0m"
+
+void die(char *message);
+#endif
diff --git a/src/include/parser.h b/src/include/parser.h
new file mode 100644
index 0000000..97a7fd9
--- /dev/null
+++ b/src/include/parser.h
@@ -0,0 +1,49 @@
+#ifndef PARSER_H
+#define PARSER_H
+#include "./ast.h"
+#include "./hash_table.h"
+#include "./lexer.h"
+#include "./token.h"
+#include <stdbool.h>
+#include <stdio.h>
+
+typedef struct {
+ token_t **tokens;
+ hash_table_t *symbol_table;
+ int i;
+ int size;
+ bool finished;
+} parser_t;
+
+parser_t *init_parser(lexer_t *lexer);
+
+void parser_error(parser_t *parser);
+
+void parser_move(parser_t *parser);
+
+void parser_eat(parser_t *parser, token_t *token);
+
+ast_t *parse_string(parser_t *parser);
+
+ast_t *parse_int(parser_t *parser);
+
+ast_t *parse_float(parser_t *parser);
+
+ast_t *parse_bool(parser_t *parser);
+
+ast_t *parse_list(parser_t *parser);
+
+ast_t *parse_quote(parser_t *parser);
+
+ast_t *parse_symbol(parser_t *parser);
+
+ast_t *parse_function(parser_t *parser);
+
+ast_t *parse_list(parser_t *parser);
+
+ast_t *parse_bind(parser_t *parser);
+
+ast_t *parse_expr(parser_t *parser);
+
+ast_t *read_in(char *s);
+#endif
diff --git a/src/include/print.h b/src/include/print.h
new file mode 100644
index 0000000..9dbecbd
--- /dev/null
+++ b/src/include/print.h
@@ -0,0 +1,16 @@
+#ifndef PRINT_H
+#define PRINT_H
+#include "./ast.h"
+
+void print_string(ast_t *str);
+
+void print_int(ast_t *i);
+
+void print_bool(ast_t *b);
+
+void print_float(ast_t *f);
+
+void print_func(ast_t *f);
+
+void print(ast_t *res);
+#endif
diff --git a/src/include/sl_list.h b/src/include/sl_list.h
new file mode 100644
index 0000000..5a7c130
--- /dev/null
+++ b/src/include/sl_list.h
@@ -0,0 +1,23 @@
+#ifndef SL_LIST_H
+#define SL_LIST_H
+
+typedef struct SL_NODE_STRUCT {
+ void *p1;
+ void *p2;
+} sl_node_t;
+
+typedef struct {
+ sl_node_t *head;
+ int size;
+} sl_list_t;
+
+sl_node_t *init_sl_node(void *value);
+
+sl_list_t *init_sl_list();
+
+void sl_list_add(sl_list_t *l, void *value, int i);
+
+void sl_list_del(sl_list_t *l, int i);
+
+void *sl_list_get(sl_list_t *l, int i);
+#endif
diff --git a/src/include/stack.h b/src/include/stack.h
new file mode 100644
index 0000000..e8047c8
--- /dev/null
+++ b/src/include/stack.h
@@ -0,0 +1,16 @@
+#ifndef STACK_H
+#define STACK_H
+#include "./hash_table.h"
+typedef struct {
+ hash_table_t **stack;
+ int cur;
+} stack_t;
+
+stack_t *init_stack(int ht_size);
+
+void stack_push(stack_t *s, hash_table_t *h);
+
+hash_table_t *stack_peek(stack_t *s);
+
+hash_table_t *stack_pop(stack_t *s);
+#endif
diff --git a/src/include/token.h b/src/include/token.h
new file mode 100644
index 0000000..83c595b
--- /dev/null
+++ b/src/include/token.h
@@ -0,0 +1,22 @@
+#ifndef TOKEN_H
+#define TOKEN_H
+
+typedef struct {
+ enum {
+ TOKEN_ID,
+ TOKEN_LPAREN,
+ TOKEN_RPAREN,
+ TOKEN_BOOL,
+ TOKEN_INT,
+ TOKEN_FLOAT,
+ TOKEN_STRING,
+ TOKEN_QUOTE,
+ TOKEN_PERIOD,
+ } type;
+ char *value;
+ int row;
+ int col;
+} token_t;
+
+token_t *init_token(int type, char *value, int row, int col);
+#endif
diff --git a/src/include/visitor.h b/src/include/visitor.h
new file mode 100644
index 0000000..87f2853
--- /dev/null
+++ b/src/include/visitor.h
@@ -0,0 +1,26 @@
+#ifndef VISITOR_H
+#define VISITOR_H
+#include "./ast.h"
+#include "./hash_table.h"
+#include "./stack.h"
+
+typedef struct {
+ hash_table_t *symbol_table;
+ stack_t *stack_frame;
+ ast_t *root;
+} visitor_t;
+
+void eval_error(visitor_t *v);
+
+visitor_t *init_visitor(ast_t *root);
+
+bool is_self_evaluating(ast_t *e);
+
+ast_t *eval_symbol(visitor_t *v, ast_t *e);
+
+ast_t *eval_list(visitor_t *v, ast_t *e);
+
+ast_t *eval_expr(visitor_t *v, ast_t *e);
+
+ast_t *eval(visitor_t *v);
+#endif
diff --git a/src/lexer.c b/src/lexer.c
new file mode 100644
index 0000000..02417a1
--- /dev/null
+++ b/src/lexer.c
@@ -0,0 +1,150 @@
+#include "./include/lexer.h"
+#include "./include/macros.h"
+#include "./include/token.h"
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void lexer_reset(lexer_t *lexer, char *source) {
+ lexer->source = source;
+ lexer->c = source[0];
+ lexer->i = 0;
+ lexer->row = 1;
+ lexer->col = 1;
+ lexer->finished = false;
+}
+
+lexer_t *init_lexer(char *source) {
+ lexer_t *l = (lexer_t *)malloc(sizeof(lexer_t));
+ if (l == NULL)
+ die("malloc on lexer");
+ lexer_reset(l, source);
+ return l;
+}
+
+void lexer_move(lexer_t *lexer) {
+ if (lexer->c != '\0') {
+ lexer->i++;
+ lexer->c = lexer->source[lexer->i];
+ if (lexer->c == '\n') {
+ lexer->row++;
+ lexer->col = 0;
+ }
+ } else
+ lexer->finished = true;
+}
+
+void lexer_ignore_whitespace(lexer_t *lexer) {
+ while (isspace(lexer->c))
+ lexer_move(lexer);
+}
+
+void lexer_skip_comment(lexer_t *lexer) {
+ while (lexer->c != '\n' && lexer->c != '\0')
+ lexer_move(lexer);
+}
+
+static bool is_valid_id_char(char c) {
+ if (c == '(' || c == ')' || isdigit(c) || c == '"' || c == '\'' || c == '#' ||
+ c == '.')
+ return false;
+ return true;
+}
+
+static char *char_to_string(char c) {
+ char *s = (char *)malloc(2 * sizeof(char));
+ s[0] = c;
+ s[1] = '\0';
+ return s;
+}
+
+token_t *lexer_collect_bool(lexer_t *lexer) {
+ lexer_move(lexer);
+ if (lexer->c == 't')
+ return init_token(TOKEN_BOOL, "T", lexer->row, lexer->col);
+ else if (lexer->c == 'f')
+ return init_token(TOKEN_BOOL, "F", lexer->row, lexer->col);
+ else
+ return NULL;
+}
+
+token_t *lexer_collect_id(lexer_t *lexer) {
+ char *ret = (char *)malloc(1);
+ ret[0] = '\0';
+
+ while (is_valid_id_char(lexer->c)) {
+ ret = realloc(ret, (strlen(ret) + 2));
+ strcat(ret, char_to_string(lexer->c));
+ lexer_move(lexer);
+ }
+ return init_token(TOKEN_ID, ret, lexer->row, lexer->col);
+}
+
+token_t *lexer_collect_num(lexer_t *lexer) {
+ char *ret = (char *)malloc(1);
+ ret[0] = '\0';
+ bool is_float = false;
+ while (isdigit(lexer->c) || (lexer->c == '.' && !is_float)) {
+ if (lexer->c == '.')
+ is_float = true;
+ ret = realloc(ret, (strlen(ret) + 2));
+ strcat(ret, char_to_string(lexer->c));
+ lexer_move(lexer);
+ }
+ if (is_float)
+ return init_token(TOKEN_FLOAT, ret, lexer->row, lexer->col);
+ return init_token(TOKEN_INT, ret, lexer->row, lexer->col);
+}
+
+token_t *lexer_collect_string(lexer_t *lexer) {
+ char *ret = (char *)malloc(1);
+ ret[0] = '\0';
+ lexer_move(lexer);
+ while (lexer->c != '"') {
+ ret = realloc(ret, (strlen(ret) + 2));
+ strcat(ret, char_to_string(lexer->c));
+ lexer_move(lexer);
+ }
+ lexer_move(lexer);
+ return init_token(TOKEN_STRING, ret, lexer->row, lexer->col);
+}
+
+static token_t *lexer_move_with(lexer_t *lexer, token_t *token) {
+ lexer_move(lexer);
+ return token;
+}
+
+token_t *lexer_collect_next(lexer_t *lexer) {
+ if (lexer->c == '\0') {
+ lexer->finished = true;
+ return NULL;
+ }
+ if (isspace(lexer->c))
+ lexer_ignore_whitespace(lexer);
+
+ if (isdigit(lexer->c))
+ return lexer_collect_num(lexer);
+ else if (is_valid_id_char(lexer->c))
+ return lexer_collect_id(lexer);
+ else if (lexer->c == '"')
+ return lexer_collect_string(lexer);
+ else if (lexer->c == '#')
+ return lexer_collect_bool(lexer);
+ else if (lexer->c == '(')
+ return lexer_move_with(
+ lexer, init_token(TOKEN_LPAREN, "(", lexer->row, lexer->col));
+ else if (lexer->c == ')')
+ return lexer_move_with(
+ lexer, init_token(TOKEN_RPAREN, ")", lexer->row, lexer->col));
+ else if (lexer->c == '\'')
+ return lexer_move_with(
+ lexer, init_token(TOKEN_QUOTE, "'", lexer->row, lexer->col));
+ else if (lexer->c == '.')
+ return lexer_move_with(
+ lexer, init_token(TOKEN_PERIOD, ".", lexer->row, lexer->col));
+ else
+ return NULL;
+}
diff --git a/src/macros.c b/src/macros.c
new file mode 100644
index 0000000..1effefe
--- /dev/null
+++ b/src/macros.c
@@ -0,0 +1,10 @@
+#include "./include/macros.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void die(char *message) {
+ fprintf(stderr, "%sFATAL ERROR: %s%s\n", RED, message, reset);
+ exit(EXIT_FAILURE);
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..08cadbc
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,39 @@
+#define _GNU_SOURCE
+#include "./include/lexer.h"
+#include "./include/token.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char **argv) {
+ /* Test Lexer */
+ lexer_t *lexer = init_lexer("'(fasd \"aaaaaaaa\" 4)");
+ token_t *t = lexer_collect_next(lexer);
+ while (t != NULL) {
+ printf("%d: %s\n", t->type, t->value);
+ t = lexer_collect_next(lexer);
+ }
+ /* printf("Welcome to the NXS REPL.\n"); */
+
+ /* char *buf = malloc(2); */
+ /* size_t size = 2; */
+ /* lexer_t *lexer; */
+ /* lexer = init_lexer("a"); */
+ /* token_t *t; */
+ /* while (true) { */
+ /* printf("> "); */
+ /* fflush(stdout); */
+ /* getline(&buf, &size, stdin); */
+ /* strcat(buf, "\0"); */
+ /* lexer_reset(lexer, buf); */
+ /* t = lexer_collect_next(lexer); */
+ /* while (!lexer->finished) { */
+ /* printf("%d\t%s\n", t->type, t->value); */
+ /* t = lexer_collect_next(lexer); */
+ /* printf("lmao\n"); */
+ /* } */
+ /* } */
+
+ return 0;
+}
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..f28fcc2
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,125 @@
+#include "./include/parser.h"
+#include "./include/hash_table.h"
+#include "./include/lexer.h"
+#include "./include/macros.h"
+#include "./include/token.h"
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+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();
+ 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);
+ if (t == NULL)
+ break;
+ size++;
+ p->tokens = realloc(p->tokens, size * sizeof(token_t *));
+ p->tokens[size - 1] = t;
+ }
+
+ p->size = size;
+ return p;
+}
+
+void parser_move(parser_t *parser) {
+ if (parser->i != parser->size - 1)
+ parser->i++;
+ else
+ parser->finished = true;
+}
+
+void parser_eat(parser_t *parser, token_t *token) { parser_move(parser); }
+
+ast_t *parse_bool(parser_t *parser) {
+ token_t *t = parser->tokens[parser->i];
+ parser_move(parser);
+ if (strcmp("T", t->value) == 0) {
+ return init_ast_bool(true);
+ } else
+ return init_ast_bool(false);
+}
+
+static char *escape_string(char *str) { return str; }
+
+ast_t *parse_string(parser_t *parser) {
+ char *str = parser->tokens[parser->i]->value;
+ parser_move(parser);
+ return init_ast_string(escape_string(str));
+}
+
+ast_t *parse_int(parser_t *parser) {
+ int ret = atoi(parser->tokens[parser->i]->value);
+ parser_move(parser);
+ return init_ast_int(ret);
+}
+
+ast_t *parse_float(parser_t *parser) {
+ double ret = atof(parser->tokens[parser->i]->value);
+ parser_move(parser);
+ return init_ast_float(ret);
+}
+
+ast_t *parse_function(parser_t *parser) {
+ parser_move(parser);
+ parser_eat(parser, init_token(TOKEN_LPAREN, "(", 0, 0));
+ ast_t *car = parse_list(parser); /* gets list of symbols; does not check that
+ they are symbols :skull: */
+ ast_t *cdr =
+ parse_expr(parser); /* a function can contain a single expression */
+ return init_ast_function(car, cdr);
+}
+
+ast_t *parse_list(parser_t *parser) {
+ parser_move(parser);
+ token_t *cur = parser->tokens[parser->i];
+ bool first_entry = true;
+ while (cur->type != TOKEN_RPAREN) {
+ if (cur->type == TOKEN_ID) {
+ if (strcmp(cur->value, "lambda") == 0 && first_entry)
+ return parse_function(parser);
+ else if (strcmp(cur->value, "bind") == 0 && first_entry)
+ return parse_bind(parser);
+ } else if (cur->type == TOKEN_LPAREN)
+ parse_list(parser);
+ first_entry = false;
+ }
+}
+ast_t *parse_expr(parser_t *parser) {
+ token_t *t = parser->tokens[parser->i];
+ if (t->type == TOKEN_STRING)
+ return parse_string(parser);
+ else if (t->type == TOKEN_INT)
+ return parse_int(parser);
+ else if (t->type == TOKEN_FLOAT)
+ return parse_float(parser);
+ else if (t->type == TOKEN_BOOL)
+ return parse_bool(parser);
+ else if (t->type == TOKEN_LPAREN)
+ return parse_list(parser);
+ else if (t->type == TOKEN_QUOTE)
+ return parse_quote(parser);
+ else if (t->type == TOKEN_ID)
+ return parse_symbol(parser);
+ else if (t->type == TOKEN_LPAREN)
+ return parse_list(parser);
+ else {
+ parser_error(parser);
+ }
+ return NULL;
+}
diff --git a/src/stack.c b/src/stack.c
new file mode 100644
index 0000000..4898d83
--- /dev/null
+++ b/src/stack.c
@@ -0,0 +1,34 @@
+#include "./include/stack.h"
+#include "./include/hash_table.h"
+#include "./include/macros.h"
+#include <stdlib.h>
+
+stack_t *init_stack(int ht_size) {
+ stack_t *s = (stack_t *)malloc(sizeof(stack_t));
+ if (s == NULL)
+ die("malloc on stack");
+ s->stack = NULL;
+ s->cur = -1;
+ return s;
+}
+
+void stack_push(stack_t *s, hash_table_t *h) {
+ if (s->stack == NULL) {
+ s->stack = malloc(sizeof(hash_table_t *));
+ if (s->stack == NULL)
+ die("malloc on stack within stack");
+ } else {
+ s->stack = realloc(s->stack, 2 + s->cur);
+ }
+ s->cur++;
+ s->stack[s->cur] = h;
+}
+
+hash_table_t *stack_peek(stack_t *s) { return s->stack[s->cur]; }
+
+hash_table_t *stack_pop(stack_t *s) {
+ hash_table_t *h = s->stack[s->cur];
+ s->stack[s->cur] = NULL;
+ s->cur--;
+ return h;
+}
diff --git a/src/token.c b/src/token.c
new file mode 100644
index 0000000..1cd0d91
--- /dev/null
+++ b/src/token.c
@@ -0,0 +1,15 @@
+#include "./include/token.h"
+#include "./include/macros.h"
+
+#include <stdlib.h>
+
+token_t *init_token(int type, char *value, int row, int col) {
+ token_t *t = (token_t *)malloc(sizeof(token_t));
+ if (t == NULL)
+ die("malloc on token struct");
+ t->type = type;
+ t->value = value;
+ t->row = row;
+ t->col = col;
+ return t;
+}
diff --git a/src/visitor.c b/src/visitor.c
new file mode 100644
index 0000000..25296c1
--- /dev/null
+++ b/src/visitor.c
@@ -0,0 +1,25 @@
+#include "./include/visitor.h"
+#include "./include/hash_table.h"
+#include "./include/macros.h"
+#include "./include/stack.h"
+#include <stdlib.h>
+
+visitor_t *init_visitor(ast_t *root) {
+ visitor_t *v = (visitor_t *)malloc(sizeof(visitor_t));
+ if (v == NULL)
+ die("malloc on visitor");
+ v->stack_frame = init_stack(512);
+ v->symbol_table = init_hash_table(10000);
+ v->root = root;
+ return v;
+}
+
+bool is_self_evaluating(ast_t *e) {
+ if (e->type == AST_STRING || e->type == AST_INT || e->type == AST_FLOAT ||
+ e->type == AST_BOOL || e->type == AST_FUNCTION)
+ return true;
+
+ if (e->type == AST_PAIR && e->car == NULL && e->cdr == NULL)
+ return true;
+ return false;
+}