added parsing of if-else statements and cleaned up the parser

This commit is contained in:
cozis
2021-10-31 05:42:26 +00:00
parent b56e28f36b
commit 58f4c423cb
6 changed files with 162 additions and 39 deletions
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+8
View File
@@ -6,6 +6,7 @@
typedef enum { typedef enum {
NODE_EXPR, NODE_EXPR,
NODE_IFELSE,
} NodeKind; } NodeKind;
typedef enum { typedef enum {
@@ -70,4 +71,11 @@ typedef struct {
int count; int count;
} OperExprNode; } OperExprNode;
typedef struct {
Node base;
Node *condition;
Node *true_branch;
Node *false_branch;
} IfElseNode;
#endif #endif
+152 -37
View File
@@ -3,15 +3,10 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include "../utils/defs.h"
#include "parse.h" #include "parse.h"
#include "ASTi.h" #include "ASTi.h"
#define UNREACHABLE assert(0)
#ifndef NULL
#define NULL ((void*) 0)
#endif
typedef enum { typedef enum {
TPOS = '+', TPOS = '+',
@@ -28,6 +23,9 @@ typedef enum {
TFLOAT, TFLOAT,
TSTRING, TSTRING,
TIDENT, TIDENT,
TKWIF,
TKWELSE,
} TokenKind; } TokenKind;
typedef struct Token Token; typedef struct Token Token;
@@ -47,6 +45,7 @@ typedef struct {
static Node *parse_statement(Context *ctx); static Node *parse_statement(Context *ctx);
static Node *parse_expression(Context *ctx); static Node *parse_expression(Context *ctx);
static Node *parse_expression_statement(Context *ctx); static Node *parse_expression_statement(Context *ctx);
static Node *parse_ifelse_statement(Context *ctx);
static inline _Bool isoper(char c) static inline _Bool isoper(char c)
{ {
@@ -113,6 +112,20 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
i += 1; i += 1;
tok->length = i - tok->offset; tok->length = i - tok->offset;
#define matchstr(str, len, const_str) \
(len == sizeof(const_str)-1 && !strncmp(str, const_str, sizeof(const_str)-1))
if(matchstr(str + tok->offset, tok->length, "if"))
{
tok->kind = TKWIF;
}
else if(matchstr(str + tok->offset, tok->length, "else"))
{
tok->kind = TKWELSE;
}
#undef matchstr
} }
else if(isdigit(str[i])) else if(isdigit(str[i]))
{ {
@@ -261,11 +274,47 @@ AST *parse(Source *src, BPAlloc *alloc, Error *error)
return ast; return ast;
} }
static inline Token *current_token(Context *ctx)
{
assert(ctx != NULL);
assert(ctx->token != NULL);
return ctx->token;
}
static inline TokenKind current(Context *ctx)
{
assert(ctx != NULL);
return current_token(ctx)->kind;
}
static inline TokenKind next(Context *ctx)
{
assert(ctx != NULL);
assert(ctx->token != NULL);
assert(ctx->token->kind != TDONE);
ctx->token = ctx->token->next;
return current(ctx);
}
static inline TokenKind prev(Context *ctx)
{
assert(ctx != NULL);
assert(ctx->token != NULL);
assert(ctx->token->prev != NULL);
ctx->token = ctx->token->prev;
return current(ctx);
}
static inline _Bool done(Context *ctx)
{
return current(ctx) == TDONE;
}
static Node *parse_statement(Context *ctx) static Node *parse_statement(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
switch(ctx->token->kind) switch(current(ctx))
{ {
case '*': case '*':
case '/': case '/':
@@ -282,6 +331,9 @@ static Node *parse_statement(Context *ctx)
case TSTRING: case TSTRING:
case TIDENT: case TIDENT:
return parse_expression_statement(ctx); return parse_expression_statement(ctx);
case TKWIF:
return parse_ifelse_statement(ctx);
} }
Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected", Error_Report(ctx->error, 0, "Got token \"%.*s\" where the start of a statement was expected",
@@ -294,28 +346,21 @@ static Node *parse_expression_statement(Context *ctx)
assert(ctx != NULL); assert(ctx != NULL);
Node *expr = parse_expression(ctx); Node *expr = parse_expression(ctx);
if(expr == NULL) return NULL;
if(expr == NULL) // The final statement doesn't need a ';'.
return NULL; if(done(ctx)) return expr;
assert(ctx->token != NULL); if(current(ctx) != ';')
if(ctx->token->kind == TDONE)
// If the source ended before
// the final ";", it's ok.
return expr;
if(ctx->token->kind != ';')
{ {
// ERROR: Got something other than // ERROR: Got something other than a semicolon at the end
// a semicolon at the end of statement. // of statement.
Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset); Error_Report(ctx->error, 0, "Got token \"%.*s\" where \";\" was expected", ctx->token->length, ctx->src + ctx->token->offset);
return NULL; return NULL;
} }
ctx->token = ctx->token->next; next(ctx);
assert(ctx->token != NULL);
return expr; return expr;
} }
@@ -324,6 +369,18 @@ static Node *parse_string_primary_expression(Context *ctx)
assert(ctx != NULL); assert(ctx != NULL);
assert(ctx->token->kind == TSTRING); assert(ctx->token->kind == TSTRING);
if(current(ctx) == TDONE)
{
Error_Report(ctx->error, 0, "Source ended where a string literal was expected");
return NULL;
}
if(current(ctx) != TSTRING)
{
Error_Report(ctx->error, 0, "Got token \"%.*s\" where a string literal was expected", ctx->token->length, ctx->src + ctx->token->offset);
return NULL;
}
const char *src = ctx->src; const char *src = ctx->src;
int len = ctx->token->offset + ctx->token->length - 1; int len = ctx->token->offset + ctx->token->length - 1;
int i = ctx->token->offset + 1; int i = ctx->token->offset + 1;
@@ -428,9 +485,7 @@ static Node *parse_string_primary_expression(Context *ctx)
node->len = copyl; node->len = copyl;
} }
ctx->token = ctx->token->next; next(ctx);
assert(ctx->token != NULL);
return (Node*) node; return (Node*) node;
} }
@@ -438,15 +493,14 @@ static Node *parse_primary_expresion(Context *ctx)
{ {
assert(ctx != NULL); assert(ctx != NULL);
switch(ctx->token->kind) switch(current(ctx))
{ {
case '+': case '+':
case '-': case '-':
{ {
Token *operator = ctx->token; Token *unary_operator = current_token(ctx);
ctx->token = ctx->token->next; next(ctx);
assert(ctx->token != NULL);
Node *operand = parse_primary_expresion(ctx); Node *operand = parse_primary_expresion(ctx);
@@ -460,9 +514,9 @@ static Node *parse_primary_expresion(Context *ctx)
temp->base.base.kind = NODE_EXPR; temp->base.base.kind = NODE_EXPR;
temp->base.base.next = NULL; temp->base.base.next = NULL;
temp->base.base.offset = operator->offset; temp->base.base.offset = unary_operator->offset;
temp->base.base.length = operand->offset + operand->length - operator->offset; temp->base.base.length = operand->offset + operand->length - unary_operator->offset;
temp->base.kind = operator->kind == '+' ? EXPR_POS : EXPR_NEG; temp->base.kind = unary_operator->kind == '+' ? EXPR_POS : EXPR_NEG;
temp->head = operand; temp->head = operand;
temp->count = 1; temp->count = 1;
} }
@@ -471,22 +525,26 @@ static Node *parse_primary_expresion(Context *ctx)
case '(': case '(':
{ {
ctx->token = ctx->token->next; next(ctx); // Consume the '('.
Node *node = parse_expression(ctx); Node *node = parse_expression(ctx);
if(node == NULL) if(node == NULL)
return NULL; return NULL;
if(ctx->token->kind != ')') if(current(ctx) == TDONE)
{
Error_Report(ctx->error, 0, "Source ended before \")\", after sub-expression");
return NULL;
}
if(current(ctx) != ')')
{ {
Error_Report(ctx->error, 0, "Missing \")\", after sub-expression"); Error_Report(ctx->error, 0, "Missing \")\", after sub-expression");
return NULL; return NULL;
} }
ctx->token = ctx->token->next; next(ctx); // Consume the ')'.
assert(ctx->token != NULL);
return node; return node;
} }
@@ -760,3 +818,60 @@ static Node *parse_expression(Context *ctx)
return parse_expression_2(ctx, left_expr, -1000000000); return parse_expression_2(ctx, left_expr, -1000000000);
} }
static Node *parse_ifelse_statement(Context *ctx)
{
assert(ctx != NULL);
assert(ctx->token != NULL);
assert(ctx->token->kind == TKWIF);
ctx->token = ctx->token->next;
if(ctx->token->kind == TDONE)
{
// ERROR: Source ended after if keyword.
// An expression was expected.
Error_Report(ctx->error, 0, "Source ended after if keyword. An expression was expected");
return NULL;
}
Token *if_token = current_token(ctx);
Node *condition = parse_expression(ctx);
if(condition == NULL) return NULL;
Node *true_branch = parse_statement(ctx);
if(condition == NULL) return NULL;
Node *false_branch = NULL;
if(ctx->token->kind == TKWELSE)
{
// Consume the "else" token.
ctx->token = ctx->token->next;
false_branch = parse_statement(ctx);
if(false_branch == NULL) return NULL;
}
IfElseNode *ifelse;
{
ifelse = BPAlloc_Malloc(ctx->alloc, sizeof(IfElseNode));
if(ifelse == NULL)
{
// ERROR: No memory.
Error_Report(ctx->error, 1, "No memory");
return NULL;
}
ifelse->base.kind = NODE_IFELSE;
ifelse->base.next = NULL;
ifelse->base.offset = if_token->offset;
ifelse->base.length = ctx->token->offset + ctx->token->length - if_token->offset;
ifelse->condition = condition;
ifelse->true_branch = true_branch;
ifelse->false_branch = false_branch;
}
return (Node*) ifelse;
}