aboutsummaryrefslogtreecommitdiff
path: root/parse.c
diff options
context:
space:
mode:
authorOskari Timperi <oskari.timperi@iki.fi>2014-05-17 12:37:09 +0300
committerOskari Timperi <oskari.timperi@iki.fi>2014-05-17 12:37:09 +0300
commit2836fa60045bcdd8c1c8c5ed775d711cc7f385a9 (patch)
tree7892216d6ae7f0c51bd6c147dadc0bb88f06070c /parse.c
parent6814f6b99562620e70538787b6f8d66c80f7b990 (diff)
downloadlispish-2836fa60045bcdd8c1c8c5ed775d711cc7f385a9.tar.gz
lispish-2836fa60045bcdd8c1c8c5ed775d711cc7f385a9.zip
refactor code to use LIST from sys/queue.h
It's now easier and more natural to work with the code. :-P
Diffstat (limited to 'parse.c')
-rw-r--r--parse.c232
1 files changed, 125 insertions, 107 deletions
diff --git a/parse.c b/parse.c
index b5101e1..a34063c 100644
--- a/parse.c
+++ b/parse.c
@@ -1,6 +1,5 @@
#include "parse.h"
#include "tokens.h"
-#include "list.h"
#include "atom.h"
#include <stdio.h>
@@ -8,134 +7,136 @@
#include <string.h>
#include <ctype.h>
-void print_list(struct list *list, int level)
+struct atom *parse_token(struct token *token)
{
- while (list)
+ switch (token->type)
{
- struct atom *atom = LIST_GET_ATOM(list);
+ case TOKEN_INT:
+ return atom_new_int(strtol(token->s, NULL, 10));
- if (IS_TRUE(list))
- {
- printf("#t");
- }
- else if (IS_FALSE(list))
- {
- printf("#f");
- }
- else if (IS_NIL(list))
- {
- printf("nil");
- }
- else
- {
- switch (atom->type)
- {
- case ATOM_SYMBOL:
- printf("%.*s", atom->str.len, atom->str.str);
- break;
-
- case ATOM_LIST:
- printf("(");
- print_list(atom->list, level+1);
- printf(")");
- break;
-
- case ATOM_STR:
- printf("\"%.*s\"", atom->str.len, atom->str.str);
- break;
-
- case ATOM_INT:
- printf("%ld", atom->l);
- }
- }
+ case TOKEN_STR:
+ return atom_new_str(token->s, token->len);
- if (list->next)
- printf(" ");
+ case TOKEN_SYMBOL:
+ if (strncmp(token->s, "#t", 2) == 0)
+ return &true_atom;
+ else if (strncmp(token->s, "#f", 2) == 0)
+ return &false_atom;
+ else
+ return atom_new_sym(token->s, token->len);
- list = list->next;
+ default:
+ return NULL;
}
- if (level == 0)
- printf("\n");
+ return NULL;
+}
+
+void parse_quote(const char *src, int *pos, struct atom **result)
+{
+ struct atom *value = parse(src, pos);
+ struct atom *q = atom_new_sym("quote", 5);
+ struct atom *form = atom_new_list_empty();
+
+ LIST_INSERT_HEAD(form->list, q, entries);
+ LIST_INSERT_AFTER(q, value, entries);
+
+ *result = form;
}
-int parse_next(const char *src, int *pos, struct atom **result)
+int parse_list(const char *src, int *pos, struct atom **result)
{
struct token token;
int rc;
+ struct list *list;
+ struct atom *last = NULL;
- if ((rc = get_next_token(src, pos, &token)) > 0)
+ list = calloc(1, sizeof(*list));
+ LIST_INIT(list);
+
+ while ((rc = get_next_token(src, pos, &token)))
{
- switch (token.type)
- {
- case TOKEN_INT:
- *result = atom_new_int(strtol(token.s, NULL, 10));
- break;
+ struct atom *atom;
- case TOKEN_STR:
- *result = atom_new_str(token.s, token.len);
- break;
+ if (rc < 0)
+ break;
- case TOKEN_SYMBOL:
- if (strncmp(token.s, "#t", 2) == 0)
- *result = &true_atom;
- else if (strncmp(token.s, "#f", 2) == 0)
- *result = &false_atom;
- else
- *result = atom_new_sym(token.s, token.len);
- break;
+ switch (token.type)
+ {
+ case TOKEN_LPAREN:
+ if (parse_list(src, pos, &atom) < 0)
+ return -1;
+ break;
- case TOKEN_LPAREN:
- {
- struct list *l = parse(src, pos);
- *result = atom_new_list(l);
- break;
- }
+ case TOKEN_RPAREN:
+ goto out;
+ break;
- case TOKEN_RPAREN:
- return -2;
+ case TOKEN_QUOTE:
+ parse_quote(src, pos, &atom);
+ break;
- case TOKEN_QUOTE:
- {
- struct atom *quoted = NULL;
+ default:
+ atom = parse_token(&token);
+ break;
+ }
- parse_next(src, pos, &quoted);
+ if (!last)
+ LIST_INSERT_HEAD(list, atom, entries);
+ else
+ LIST_INSERT_AFTER(last, atom, entries);
- struct list *qlist = list_append(NULL,
- atom_new_sym("quote", 5));
+ last = atom;
+ }
- list_append(qlist, quoted);
+out:
- *result = atom_new_list(qlist);
+ if (rc < 0)
+ return rc;
- break;
- }
- }
+ if (LIST_EMPTY(list))
+ {
+ free(list);
+ *result = &nil_atom;
+ return 1;
}
- return rc;
+ *result = atom_new_list(list);
+ return 1;
}
-struct list *parse(const char *src, int *pos)
+struct atom *parse(const char *src, int *pos)
{
+ struct token token;
+ struct atom *atom = NULL;
int rc;
- struct atom *atom;
- struct list root, *last = &root;
- list_init(last);
+ rc = get_next_token(src, pos, &token);
- while ((rc = parse_next(src, pos, &atom)))
- {
- if (rc < 0)
- break;
+ if (rc < 0)
+ return NULL;
- last = list_append(last, atom);
+ switch (token.type)
+ {
+ case TOKEN_LPAREN:
+ if (parse_list(src, pos, &atom) < 0)
+ atom = NULL;
+ break;
+
+ case TOKEN_RPAREN:
+ printf("syntax error: unexpected ')'\n");
+ break;
+
+ case TOKEN_QUOTE:
+ parse_quote(src, pos, &atom);
+ break;
+
+ default:
+ atom = parse_token(&token);
+ break;
}
- if (rc < 0 && rc != -2)
- return NULL;
-
- return root.next;
+ return atom;
}
#ifdef BUILD_TEST
@@ -151,34 +152,51 @@ static const char *test_src_fact =
" (* n (fact (- n 1))))))\n"
"(fact 5) ;; this should evaluate to 120\n";
-#define ASSERT_SYM(LIST, SYM) \
- ASSERT_TRUE(IS_SYM(LIST)); \
- ASSERT_STREQ(SYM, LIST_GET_ATOM(LIST)->str.str)
+#define ASSERT_SYM(ATOM, SYM) \
+ ASSERT_TRUE(IS_SYM(ATOM)); \
+ ASSERT_STREQ(SYM, (ATOM)->str.str)
TEST(test_parse)
{
int pos = 0;
- struct list *list;
+ struct atom *list;
list = parse(test_src_fact, &pos);
ASSERT_TRUE(list != NULL);
-
ASSERT_TRUE(IS_LIST(list));
- list = LIST_GET_ATOM(list)->list;
+ struct atom *a = CAR(list->list);
+ ASSERT_TRUE(a != NULL);
+ ASSERT_SYM(a, "define");
- ASSERT_TRUE(list != NULL);
- ASSERT_SYM(list, "define");
+ a = CDR(a);
- list = list->next;
+ ASSERT_TRUE(a != NULL);
+ ASSERT_SYM(a, "fact");
- ASSERT_TRUE(list != NULL);
- ASSERT_SYM(list, "fact");
+ a = CDR(a);
- list = list->next;
+ ASSERT_TRUE(a != NULL);
+}
- ASSERT_TRUE(list != NULL);
+TEST(parse_quote)
+{
+ int pos = 0;
+
+ struct atom *result = parse("'foobar", &pos);
+ ASSERT_TRUE(result != NULL);
+ ASSERT_EQ(ATOM_LIST, result->type);
+
+ struct atom *op = CAR(result->list);
+ ASSERT_TRUE(op != NULL);
+ ASSERT_EQ(ATOM_SYMBOL, op->type);
+ ASSERT_STREQ("quote", op->str.str);
+
+ struct atom *a = CDR(op);
+ ASSERT_TRUE(a != NULL);
+ ASSERT_EQ(ATOM_SYMBOL, a->type);
+ ASSERT_STREQ("foobar", a->str.str);
}
#endif