1
0
Fork 0
lesson-lisp/src/parser.c

137 lines
3.5 KiB
C

#include "parser.h"
#include "object.h"
#include "tokens.h"
#include <assert.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
static void expect(Tokens tokens, enum TokenType token_type);
static struct Object *expr(Tokens tokens);
static struct Object *parens(Tokens tokens);
static struct Object *parens_part(Tokens tokens);
void expect(const Tokens tokens, const enum TokenType token_type)
{
assert(Tokens_expect(tokens, token_type));
}
struct Object *parse(const Tokens tokens)
{
return expr(tokens);
}
struct Object *expr(const Tokens tokens)
{
assert(Tokens_top(tokens));
switch (Tokens_top(tokens)->type) {
case TOKEN_ROUND_OPEN:
case TOKEN_SQUARE_OPEN:
case TOKEN_CURLY_OPEN:
return parens(tokens);
case TOKEN_QUOTE:
Tokens_pop(tokens);
return \
Object_build_list(2, Object_new_symbol("quote"), expr(tokens));
case TOKEN_QUASI_QUOTE:
Tokens_pop(tokens);
return \
Object_build_list(2, Object_new_symbol("quasiquote"), expr(tokens));
case TOKEN_QUASI_UNQUOTE:
Tokens_pop(tokens);
return \
Object_build_list(2, Object_new_symbol("unquote"), expr(tokens));
case TOKEN_TAG:
{
struct Object *object = NULL;
const char *const val = Tokens_top(tokens)->val;
assert(val);
if (strcmp(val, "f") == 0 || strcmp(val, "false") == 0) {
object = Object_new_boolean(false);
} else if (strcmp(val, "t") == 0 || strcmp(val, "true") == 0) {
object = Object_new_boolean(true);
} else {
assert(0);
}
Tokens_pop(tokens);
return object;
}
case TOKEN_IDENT:
{
struct Object *const object = Object_new_symbol(Tokens_top(tokens)->val);
Tokens_pop(tokens);
return object;
}
case TOKEN_NUM:
{
struct Object *const object =
Object_new_number(atoll(Tokens_top(tokens)->val));
Tokens_pop(tokens);
return object;
}
case TOKEN_STRING:
{
struct Object *const object =
Object_new_string(Tokens_top(tokens)->val);
Tokens_pop(tokens);
return object;
}
default:
abort();
return NULL;
}
}
struct Object *parens(const Tokens tokens)
{
assert(Tokens_top(tokens));
struct Object *object = NULL;
if (Tokens_top(tokens)->type == TOKEN_ROUND_OPEN) {
expect(tokens, TOKEN_ROUND_OPEN);
object = parens_part(tokens);
expect(tokens, TOKEN_ROUND_CLOSE);
} else if (Tokens_top(tokens)->type == TOKEN_SQUARE_OPEN) {
expect(tokens, TOKEN_SQUARE_OPEN);
object = parens_part(tokens);
expect(tokens, TOKEN_SQUARE_CLOSE);
} else {
expect(tokens, TOKEN_CURLY_OPEN);
object = parens_part(tokens);
expect(tokens, TOKEN_CURLY_CLOSE);
}
return object;
}
struct Object *parens_part(const Tokens tokens)
{
assert(Tokens_top(tokens));
if (Tokens_top(tokens)->type == TOKEN_ROUND_CLOSE ||
Tokens_top(tokens)->type == TOKEN_SQUARE_CLOSE ||
Tokens_top(tokens)->type == TOKEN_CURLY_CLOSE)
{
return NULL;
}
struct Object *const a = expr(tokens);
assert(Tokens_top(tokens));
struct Object *b = NULL;
if (Tokens_top(tokens)->type != TOKEN_ROUND_CLOSE &&
Tokens_top(tokens)->type != TOKEN_SQUARE_CLOSE &&
Tokens_top(tokens)->type != TOKEN_CURLY_CLOSE)
{
b = parens_part(tokens);
}
struct Object *object = Object_new_pair(a, b);
return object;
}