206 lines
3.9 KiB
C
206 lines
3.9 KiB
C
#include "enums.h"
|
|
#include "lexer.h"
|
|
#include "object.h"
|
|
#include "tokens.h"
|
|
|
|
#include <assert.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static void error(const char *msg);
|
|
|
|
/**********
|
|
* Parser *
|
|
**********/
|
|
|
|
static void expect(enum TokenType token_type);
|
|
|
|
static struct Object *parse();
|
|
static struct Object *expr();
|
|
static struct Object *parens();
|
|
static struct Object *parens_part();
|
|
|
|
/********
|
|
* Eval *
|
|
********/
|
|
|
|
static struct Object *eval(struct Object *program);
|
|
|
|
static struct Object *func_sum(struct Object *numbers);
|
|
|
|
/*******************
|
|
* Implementations *
|
|
*******************/
|
|
|
|
int main()
|
|
{
|
|
char chr;
|
|
while ((chr = getchar()) != EOF) {
|
|
lex(chr);
|
|
}
|
|
|
|
printf("Tokens:\n");
|
|
|
|
for (
|
|
const struct Tokens *token = tokens_top();
|
|
token;
|
|
token = token->next
|
|
) {
|
|
printf("%s:%s;\n", TokenType_to_str(token->type), token->val);
|
|
}
|
|
|
|
struct Object *const program = parse();
|
|
|
|
printf("\nProgram:\n");
|
|
Object_print(program, 0);
|
|
|
|
struct Object *const result = eval(program);
|
|
|
|
printf("\nResult:\n");
|
|
Object_print(result, 0);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
void error(const char *msg)
|
|
{
|
|
printf("ERROR: %s\n", msg);
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
/**********
|
|
* Parser *
|
|
**********/
|
|
|
|
void expect(const enum TokenType token_type)
|
|
{
|
|
if (!tokens_expect(token_type)) error("expect");
|
|
}
|
|
|
|
struct Object *parse()
|
|
{
|
|
return expr();
|
|
}
|
|
|
|
struct Object *expr()
|
|
{
|
|
assert(tokens_top());
|
|
|
|
switch (tokens_top()->type) {
|
|
case TOKEN_OPEN: return parens();
|
|
case TOKEN_ATOM:
|
|
{
|
|
struct Object *const object = Object_new_atom(tokens_top()->val);
|
|
tokens_pop();
|
|
return object;
|
|
}
|
|
case TOKEN_NUM:
|
|
{
|
|
struct Object *const object =
|
|
Object_new_number(atoll(tokens_top()->val));
|
|
tokens_pop();
|
|
return object;
|
|
}
|
|
default:
|
|
error("invalid expr");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
struct Object *parens()
|
|
{
|
|
expect(STATE_OPEN);
|
|
struct Object *const object = parens_part();
|
|
expect(STATE_CLOSE);
|
|
return object;
|
|
}
|
|
|
|
struct Object *parens_part()
|
|
{
|
|
assert(tokens_top());
|
|
if (tokens_top()->type == TOKEN_CLOSE) return NULL;
|
|
|
|
struct Object *const a = expr();
|
|
assert(tokens_top());
|
|
|
|
struct Object *b = NULL;
|
|
if (tokens_top()->type != TOKEN_CLOSE) {
|
|
b = parens_part();
|
|
}
|
|
|
|
struct Object *object = Object_new_pair(a, b);
|
|
return object;
|
|
}
|
|
|
|
/********
|
|
* Eval *
|
|
********/
|
|
|
|
struct Object *eval(struct Object *const program)
|
|
{
|
|
// NULL is an empty list, can't eval
|
|
if (!program) {
|
|
error("can't eval null");
|
|
return NULL;
|
|
}
|
|
|
|
// Almost everything evaluates to itself
|
|
if (program->type != TYPE_PAIR && program->type != TYPE_ATOM) {
|
|
return program;
|
|
}
|
|
|
|
// Atoms are variable names, but we can't lookup
|
|
if (program->type == TYPE_ATOM) {
|
|
error("can't eval atoms");
|
|
return NULL;
|
|
}
|
|
|
|
// The first item of pair should be an atom - a function name
|
|
if (!program->pair.a || program->pair.a->type != TYPE_ATOM) {
|
|
error("eval expects atom");
|
|
return NULL;
|
|
}
|
|
|
|
// The func "sum"
|
|
if (strcmp(program->pair.a->s, "sum") == 0) {
|
|
return func_sum(program->pair.b);
|
|
}
|
|
|
|
error("unknown func");
|
|
return NULL;
|
|
}
|
|
|
|
struct Object *func_sum(struct Object *const numbers)
|
|
{
|
|
struct Object *const object = Object_new_number(0);
|
|
|
|
if (!numbers) return object;
|
|
|
|
if (numbers->type != TYPE_PAIR) {
|
|
error("sum expects pair");
|
|
return NULL;
|
|
}
|
|
|
|
if (!numbers->pair.a) {
|
|
error("type error");
|
|
return NULL;
|
|
}
|
|
|
|
if (numbers->pair.a->type != TYPE_NUMBER) {
|
|
error("type error");
|
|
return NULL;
|
|
}
|
|
|
|
object->i = numbers->pair.a->i;
|
|
|
|
if (!numbers->pair.b) return object;
|
|
|
|
struct Object *const b_sum = func_sum(numbers->pair.b);
|
|
|
|
object->i += b_sum->i;
|
|
|
|
return object;
|
|
}
|