279 lines
5 KiB
C
279 lines
5 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
|
|
#include "ast.h"
|
|
#include "lexer.h"
|
|
#include "parser.h"
|
|
|
|
int current = 0;
|
|
token_t *tokens;
|
|
expr_t *expression(void);
|
|
|
|
void error(token_t *token, char *message)
|
|
{
|
|
if (token->type == TOKEN_EOF) {
|
|
fprintf(stderr, "[line %d] at end: %s\n", token->line, message);
|
|
} else {
|
|
fprintf(stderr, "[line %d] at '%s': %s\n", token->line, token->value, message);
|
|
}
|
|
errno = 65;
|
|
}
|
|
|
|
void free_expr(expr_t *expr)
|
|
{
|
|
if (!expr)
|
|
return;
|
|
switch (expr->type) {
|
|
case EXPR_BINARY:
|
|
free(expr->as.binary.operator.value);
|
|
free_expr(expr->as.binary.left);
|
|
free_expr(expr->as.binary.right);
|
|
free(expr);
|
|
break;
|
|
|
|
case EXPR_GROUPING:
|
|
free_expr(expr->as.grouping.expression);
|
|
free(expr);
|
|
break;
|
|
|
|
case EXPR_UNARY:
|
|
free(expr->as.unary.operator.value);
|
|
free_expr(expr->as.unary.right);
|
|
free(expr);
|
|
break;
|
|
|
|
case EXPR_LITERAL:
|
|
if (expr->as.literal.value.type == VAL_STRING) {
|
|
free(expr->as.literal.value.as.string);
|
|
}
|
|
free(expr);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
token_t *peek(void)
|
|
{
|
|
return &tokens[current];
|
|
}
|
|
|
|
int end(void)
|
|
{
|
|
return tokens[current].type == TOKEN_EOF;
|
|
}
|
|
|
|
token_t *previous(void)
|
|
{
|
|
return &tokens[current - 1];
|
|
}
|
|
|
|
void advance(void)
|
|
{
|
|
if (!end())
|
|
current++;
|
|
}
|
|
|
|
int check(token_type_t type)
|
|
{
|
|
if (tokens[current].type == type) {
|
|
advance();
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void consume(token_type_t type, char *message) {
|
|
if (!check(type)) {
|
|
error(peek(), message);
|
|
}
|
|
}
|
|
|
|
expr_t *primary(void)
|
|
{
|
|
if (check(TOKEN_FALSE) || check(TOKEN_TRUE) || check(TOKEN_NIL) ||
|
|
check(TOKEN_NUMBER) || check(TOKEN_STRING)) {
|
|
return create_literal_expr(previous());
|
|
}
|
|
if (check(TOKEN_LEFT_PAREN)) {
|
|
expr_t *expr = expression();
|
|
consume(TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
|
|
return create_grouping_expr(expr);
|
|
}
|
|
error(peek(), "Expect expression.");
|
|
return NULL;
|
|
}
|
|
|
|
expr_t *unary(void)
|
|
{
|
|
if (check(TOKEN_BANG) || check(TOKEN_MINUS)) {
|
|
token_t *operator = previous();
|
|
expr_t *right = unary();
|
|
return create_unary_expr(operator, right);
|
|
}
|
|
|
|
return primary();
|
|
}
|
|
|
|
expr_t *factor(void)
|
|
{
|
|
expr_t *expr = unary();
|
|
|
|
while (check(TOKEN_SLASH) || check(TOKEN_STAR)) {
|
|
token_t *operator = previous();
|
|
expr_t *right = unary();
|
|
expr = create_binary_expr(operator, expr, right);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
expr_t *term(void)
|
|
{
|
|
expr_t *expr = factor();
|
|
|
|
while (check(TOKEN_MINUS) || check(TOKEN_PLUS)) {
|
|
token_t *operator = previous();
|
|
expr_t *right = factor();
|
|
expr = create_binary_expr(operator, expr, right);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
expr_t *comparison(void)
|
|
{
|
|
expr_t *expr = term();
|
|
|
|
while (check(TOKEN_GREATER) || check(TOKEN_GREATER_EQUAL) || check(TOKEN_LESS)
|
|
|| check(TOKEN_LESS_EQUAL)) {
|
|
token_t *operator = previous();
|
|
expr_t *right = term();
|
|
expr = create_binary_expr(operator, expr, right);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
expr_t *equality(void)
|
|
{
|
|
expr_t *expr = comparison();
|
|
|
|
while (check(TOKEN_BANG_EQUAL) || check(TOKEN_EQUAL_EQUAL)) {
|
|
token_t *operator = previous();
|
|
expr_t *right = comparison();
|
|
expr = create_binary_expr(operator, expr, right);
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
expr_t *expression(void)
|
|
{
|
|
return equality();
|
|
}
|
|
|
|
stmt_t print_stmt(void)
|
|
{
|
|
expr_t *value = expression();
|
|
consume(TOKEN_SEMICOLON, "Expect ; after value.");
|
|
return (stmt_t) {
|
|
.type = STMT_PRINT,
|
|
.as.print.expression = value,
|
|
};
|
|
}
|
|
|
|
stmt_t expression_stmt(void)
|
|
{
|
|
expr_t *expr = expression();
|
|
consume(TOKEN_SEMICOLON, "Expect ; after expression.");
|
|
return (stmt_t) {
|
|
.type = STMT_EXPR,
|
|
.as.expr.expression = expr,
|
|
};
|
|
}
|
|
|
|
stmt_t statement(void)
|
|
{
|
|
if (check(TOKEN_PRINT))
|
|
return print_stmt();
|
|
return expression_stmt();
|
|
}
|
|
|
|
void stmt_add(stmt_array_t *array, stmt_t stmt)
|
|
{
|
|
if (array->length == array->capacity) {
|
|
array->capacity *= 2;
|
|
array->statements = realloc(array->statements, array->capacity * sizeof(stmt_t));
|
|
}
|
|
array->statements[array->length++] = stmt;
|
|
}
|
|
|
|
void free_statements(stmt_array_t *array)
|
|
{
|
|
for (int i = 0; i < array->length; i++) {
|
|
if (array->statements[i].type == STMT_PRINT) {
|
|
free_expr(array->statements[i].as.print.expression);
|
|
}
|
|
if (array->statements[i].type == STMT_EXPR) {
|
|
free_expr(array->statements[i].as.expr.expression);
|
|
}
|
|
}
|
|
free(array->statements);
|
|
free(array);
|
|
}
|
|
|
|
stmt_array_t *parse(token_t *tks)
|
|
{
|
|
tokens = tks;
|
|
if (errno == 65) {
|
|
return NULL;
|
|
} else {
|
|
stmt_array_t *statements = malloc(sizeof(stmt_array_t));
|
|
statements->statements = malloc(DEFAULT_STMTS_SIZE * sizeof(stmt_t));
|
|
statements->length = 0;
|
|
statements->capacity = DEFAULT_STMTS_SIZE;
|
|
while (!end()) {
|
|
stmt_add(statements, statement());
|
|
}
|
|
return statements;
|
|
}
|
|
}
|
|
|
|
expr_t *parse_expr(token_t *tks)
|
|
{
|
|
tokens = tks;
|
|
if (errno == 65) {
|
|
return NULL;
|
|
} else {
|
|
return expression();
|
|
}
|
|
}
|
|
|
|
void synchronize(void)
|
|
{
|
|
advance();
|
|
|
|
while (!end()) {
|
|
if (previous()->type == TOKEN_SEMICOLON) return;
|
|
|
|
switch (peek()->type) {
|
|
case TOKEN_CLASS:
|
|
case TOKEN_FUN:
|
|
case TOKEN_VAR:
|
|
case TOKEN_FOR:
|
|
case TOKEN_IF:
|
|
case TOKEN_WHILE:
|
|
case TOKEN_PRINT:
|
|
case TOKEN_RETURN:
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
advance();
|
|
}
|
|
}
|