136 lines
3.5 KiB
C
136 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;
|
|
}
|