Added preliminary loop parsing
Signed-off-by: luccie-cmd <hoedje201@gmail.com> Signed-off-by: Lorenzo Torres <lorenzo@sagittarius-a.org>
This commit is contained in:
parent
eaebcd7bdd
commit
0015c2b81d
4 changed files with 428 additions and 118 deletions
37
lc.c
37
lc.c
|
|
@ -88,6 +88,11 @@ void print_ast(ast_node *node, int depth) {
|
||||||
print_ast(node->expr.binary.left, depth + 1);
|
print_ast(node->expr.binary.left, depth + 1);
|
||||||
print_ast(node->expr.binary.right, depth + 1);
|
print_ast(node->expr.binary.right, depth + 1);
|
||||||
break;
|
break;
|
||||||
|
case NODE_EQUAL:
|
||||||
|
printf("EqualOp (%s)\n", get_op_str(node->expr.binary.operator));
|
||||||
|
print_ast(node->expr.binary.left, depth + 1);
|
||||||
|
print_ast(node->expr.binary.right, depth + 1);
|
||||||
|
break;
|
||||||
case NODE_ARRAY_SUBSCRIPT:
|
case NODE_ARRAY_SUBSCRIPT:
|
||||||
printf("Array subscript\n");
|
printf("Array subscript\n");
|
||||||
print_ast(node->expr.subscript.expr, depth + 1);
|
print_ast(node->expr.subscript.expr, depth + 1);
|
||||||
|
|
@ -114,14 +119,18 @@ void print_ast(ast_node *node, int depth) {
|
||||||
print_ast(node->expr.ternary.otherwise, depth + 2);
|
print_ast(node->expr.ternary.otherwise, depth + 2);
|
||||||
break;
|
break;
|
||||||
case NODE_UNIT:
|
case NODE_UNIT:
|
||||||
case NODE_COMPOUND:
|
printf("Unit\n");
|
||||||
printf("Unit/Block:\n");
|
|
||||||
ast_node *current = node;
|
ast_node *current = node;
|
||||||
while (current && (current->type == NODE_UNIT || current->type == NODE_COMPOUND)) {
|
while (current && current->type == NODE_UNIT) {
|
||||||
print_ast(current->expr.unit_node.expr, depth + 1);
|
print_ast(current->expr.unit_node.expr, depth + 1);
|
||||||
current = current->expr.unit_node.next;
|
current = current->expr.unit_node.next;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case NODE_COMPOUND:
|
||||||
|
printf("Block\n");
|
||||||
|
for (usize i = 0; i < node->expr.compound.stmt_len; ++i) {
|
||||||
|
print_ast(node->expr.compound.statements[i], depth + 1);
|
||||||
|
}
|
||||||
case NODE_CALL:
|
case NODE_CALL:
|
||||||
printf("Call: %.*s\n", (int)node->expr.call.name_len, node->expr.call.name);
|
printf("Call: %.*s\n", (int)node->expr.call.name_len, node->expr.call.name);
|
||||||
current = node->expr.call.parameters;
|
current = node->expr.call.parameters;
|
||||||
|
|
@ -147,6 +156,28 @@ void print_ast(ast_node *node, int depth) {
|
||||||
printf("Import:\n");
|
printf("Import:\n");
|
||||||
print_ast(node->expr.import.path, depth + 1);
|
print_ast(node->expr.import.path, depth + 1);
|
||||||
break;
|
break;
|
||||||
|
case NODE_WHILE:
|
||||||
|
printf("While:\n");
|
||||||
|
print_ast(node->expr.whle.condition, depth + 1);
|
||||||
|
print_ast(node->expr.whle.body, depth + 1);
|
||||||
|
break;
|
||||||
|
case NODE_FOR:
|
||||||
|
printf("For:\n");
|
||||||
|
print_ast(node->expr.fr.range, depth + 1);
|
||||||
|
print_ast(node->expr.fr.array, depth + 1);
|
||||||
|
print_indent(depth + 1);
|
||||||
|
printf("Range capture: %.*s\n", node->expr.fr.rangeCaptureLen, node->expr.fr.rangeCapture);
|
||||||
|
if (node->expr.fr.arrayCapture) {
|
||||||
|
print_indent(depth + 1);
|
||||||
|
printf("Array capture: %.*s\n", node->expr.fr.arrayCaptureLen, node->expr.fr.arrayCapture);
|
||||||
|
}
|
||||||
|
print_ast(node->expr.fr.body, depth + 1);
|
||||||
|
break;
|
||||||
|
case NODE_RANGE:
|
||||||
|
printf("Range:\n");
|
||||||
|
print_ast(node->expr.binary.left, depth + 1);
|
||||||
|
print_ast(node->expr.binary.right, depth + 1);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Unknown Node Type: %d\n", node->type);
|
printf("Unknown Node Type: %d\n", node->type);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
373
parser.c
373
parser.c
|
|
@ -2,10 +2,12 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
bool has_errors = false;
|
bool has_errors = false;
|
||||||
|
|
||||||
ast_node *parse_expression(parser *p);
|
ast_node *parse_expression(parser *p);
|
||||||
|
static ast_node *parse_statement(parser *p);
|
||||||
|
|
||||||
/* Consume a token in the list. */
|
/* Consume a token in the list. */
|
||||||
static void advance(parser *p)
|
static void advance(parser *p)
|
||||||
|
|
@ -27,9 +29,12 @@ static token *peek(parser *p)
|
||||||
*/
|
*/
|
||||||
static bool match_peek(parser *p, token_type type)
|
static bool match_peek(parser *p, token_type type)
|
||||||
{
|
{
|
||||||
if (p->tokens) {
|
if (p->tokens)
|
||||||
|
{
|
||||||
return p->tokens->type == type;
|
return p->tokens->type == type;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -37,8 +42,10 @@ static bool match_peek(parser *p, token_type type)
|
||||||
/* Same as `match_peek()` but it consumes the token. */
|
/* Same as `match_peek()` but it consumes the token. */
|
||||||
static bool match(parser *p, token_type type)
|
static bool match(parser *p, token_type type)
|
||||||
{
|
{
|
||||||
if (p->tokens) {
|
if (p->tokens)
|
||||||
if (p->tokens->type == type) {
|
{
|
||||||
|
if (p->tokens->type == type)
|
||||||
|
{
|
||||||
advance(p);
|
advance(p);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -57,12 +64,15 @@ static void parser_sync(parser *p)
|
||||||
{
|
{
|
||||||
advance(p);
|
advance(p);
|
||||||
|
|
||||||
while (p->tokens) {
|
while (p->tokens)
|
||||||
if (p->previous->type == TOKEN_SEMICOLON || p->previous->type == TOKEN_RCURLY) {
|
{
|
||||||
|
if (p->previous->type == TOKEN_SEMICOLON || p->previous->type == TOKEN_RCURLY)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (p->tokens->type) {
|
switch (p->tokens->type)
|
||||||
|
{
|
||||||
case TOKEN_STRUCT:
|
case TOKEN_STRUCT:
|
||||||
case TOKEN_ENUM:
|
case TOKEN_ENUM:
|
||||||
case TOKEN_IF:
|
case TOKEN_IF:
|
||||||
|
|
@ -85,7 +95,6 @@ static void error(parser *p, char *msg)
|
||||||
parser_sync(p);
|
parser_sync(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ast_node *parse_call(parser *p)
|
static ast_node *parse_call(parser *p)
|
||||||
{
|
{
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
|
@ -96,7 +105,8 @@ static ast_node *parse_call(parser *p)
|
||||||
/* Skip also the opening `(` */
|
/* Skip also the opening `(` */
|
||||||
advance(p);
|
advance(p);
|
||||||
/* Call without parameters */
|
/* Call without parameters */
|
||||||
if (match(p, TOKEN_RPAREN)) {
|
if (match(p, TOKEN_RPAREN))
|
||||||
|
{
|
||||||
node->expr.call.parameters = NULL;
|
node->expr.call.parameters = NULL;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
@ -109,15 +119,20 @@ static ast_node *parse_call(parser *p)
|
||||||
node->expr.call.param_len = 1;
|
node->expr.call.param_len = 1;
|
||||||
|
|
||||||
/* In this case, there is only one parameter */
|
/* In this case, there is only one parameter */
|
||||||
if (match(p, TOKEN_RPAREN)) {
|
if (match(p, TOKEN_RPAREN))
|
||||||
|
{
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match(p, TOKEN_COMMA)) {
|
if (match(p, TOKEN_COMMA))
|
||||||
|
{
|
||||||
ast_node *expr = parse_expression(p);
|
ast_node *expr = parse_expression(p);
|
||||||
if (expr) {
|
if (expr)
|
||||||
while (!match(p, TOKEN_RPAREN)) {
|
{
|
||||||
if (!match(p, TOKEN_COMMA)) {
|
while (!match(p, TOKEN_RPAREN))
|
||||||
|
{
|
||||||
|
if (!match(p, TOKEN_COMMA))
|
||||||
|
{
|
||||||
error(p, "expected `)`.");
|
error(p, "expected `)`.");
|
||||||
arena_reset_to_snapshot(p->allocator, arena_start);
|
arena_reset_to_snapshot(p->allocator, arena_start);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -127,7 +142,8 @@ static ast_node *parse_call(parser *p)
|
||||||
tail = tail->expr.unit_node.next;
|
tail = tail->expr.unit_node.next;
|
||||||
tail->type = NODE_UNIT;
|
tail->type = NODE_UNIT;
|
||||||
expr = parse_expression(p);
|
expr = parse_expression(p);
|
||||||
if (!expr) {
|
if (!expr)
|
||||||
|
{
|
||||||
error(p, "expected `)`.");
|
error(p, "expected `)`.");
|
||||||
arena_reset_to_snapshot(p->allocator, arena_start);
|
arena_reset_to_snapshot(p->allocator, arena_start);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -139,12 +155,16 @@ static ast_node *parse_call(parser *p)
|
||||||
tail->expr.unit_node.next->expr.unit_node.expr = expr;
|
tail->expr.unit_node.next->expr.unit_node.expr = expr;
|
||||||
tail = tail->expr.unit_node.next;
|
tail = tail->expr.unit_node.next;
|
||||||
tail->type = NODE_UNIT;
|
tail->type = NODE_UNIT;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
error(p, "expected expression.");
|
error(p, "expected expression.");
|
||||||
arena_reset_to_snapshot(p->allocator, arena_start);
|
arena_reset_to_snapshot(p->allocator, arena_start);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
error(p, "expected `)`.");
|
error(p, "expected `)`.");
|
||||||
arena_reset_to_snapshot(p->allocator, arena_start);
|
arena_reset_to_snapshot(p->allocator, arena_start);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -157,19 +177,25 @@ static ast_node *parse_call(parser *p)
|
||||||
static ast_node *parse_factor(parser *p)
|
static ast_node *parse_factor(parser *p)
|
||||||
{
|
{
|
||||||
token *t = peek(p);
|
token *t = peek(p);
|
||||||
if (match(p, TOKEN_INTEGER)) {
|
if (match(p, TOKEN_INTEGER))
|
||||||
|
{
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_INTEGER;
|
node->type = NODE_INTEGER;
|
||||||
node->expr.integer = parse_int(t->lexeme, t->lexeme_len);
|
node->expr.integer = parse_int(t->lexeme, t->lexeme_len);
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_FLOAT)) {
|
}
|
||||||
|
else if (match(p, TOKEN_FLOAT))
|
||||||
|
{
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_FLOAT;
|
node->type = NODE_FLOAT;
|
||||||
node->expr.flt = parse_float(t->lexeme, t->lexeme_len);
|
node->expr.flt = parse_float(t->lexeme, t->lexeme_len);
|
||||||
return node;
|
return node;
|
||||||
} else if (match_peek(p, TOKEN_IDENTIFIER)) {
|
}
|
||||||
|
else if (match_peek(p, TOKEN_IDENTIFIER))
|
||||||
|
{
|
||||||
/* If a `(` is found after an identifier, it should be a call. */
|
/* If a `(` is found after an identifier, it should be a call. */
|
||||||
if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN) {
|
if (p->tokens->next && p->tokens->next->type == TOKEN_LPAREN)
|
||||||
|
{
|
||||||
return parse_call(p);
|
return parse_call(p);
|
||||||
}
|
}
|
||||||
advance(p);
|
advance(p);
|
||||||
|
|
@ -179,36 +205,59 @@ static ast_node *parse_factor(parser *p)
|
||||||
node->expr.string.start = t->lexeme;
|
node->expr.string.start = t->lexeme;
|
||||||
node->expr.string.len = t->lexeme_len;
|
node->expr.string.len = t->lexeme_len;
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_STRING)) {
|
}
|
||||||
|
else if (match(p, TOKEN_STRING))
|
||||||
|
{
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_STRING;
|
node->type = NODE_STRING;
|
||||||
node->expr.string.start = t->lexeme;
|
node->expr.string.start = t->lexeme;
|
||||||
node->expr.string.len = t->lexeme_len;
|
node->expr.string.len = t->lexeme_len;
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_CHAR)) {
|
}
|
||||||
|
else if (match(p, TOKEN_CHAR))
|
||||||
|
{
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_CHAR;
|
node->type = NODE_CHAR;
|
||||||
if (t->lexeme_len == 2) {
|
if (t->lexeme_len == 2)
|
||||||
|
{
|
||||||
char c;
|
char c;
|
||||||
switch (t->lexeme[1]) {
|
switch (t->lexeme[1])
|
||||||
case 'n': c = '\n'; break;
|
{
|
||||||
case 't': c = '\t'; break;
|
case 'n':
|
||||||
case 'r': c = '\r'; break;
|
c = '\n';
|
||||||
case '0': c = '\0'; break;
|
break;
|
||||||
case '\\': c = '\\'; break;
|
case 't':
|
||||||
case '\'': c = '\''; break;
|
c = '\t';
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
c = '\r';
|
||||||
|
break;
|
||||||
|
case '0':
|
||||||
|
c = '\0';
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
c = '\\';
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
c = '\'';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error(p, "invalid escape code.");
|
error(p, "invalid escape code.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
node->expr.ch = c;
|
node->expr.ch = c;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
node->expr.ch = *(t->lexeme);
|
node->expr.ch = *(t->lexeme);
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_LPAREN)) {
|
}
|
||||||
|
else if (match(p, TOKEN_LPAREN))
|
||||||
|
{
|
||||||
ast_node *node = parse_expression(p);
|
ast_node *node = parse_expression(p);
|
||||||
if (!match(p, TOKEN_RPAREN)) {
|
if (!match(p, TOKEN_RPAREN))
|
||||||
|
{
|
||||||
error(p, "unclosed parenthesis");
|
error(p, "unclosed parenthesis");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -221,9 +270,11 @@ static ast_node *parse_factor(parser *p)
|
||||||
|
|
||||||
ast_node *parse_unary(parser *p)
|
ast_node *parse_unary(parser *p)
|
||||||
{
|
{
|
||||||
if (match(p, TOKEN_PLUS_PLUS) || match(p, TOKEN_MINUS) || match(p, TOKEN_MINUS_MINUS) || match(p, TOKEN_STAR) || match(p, TOKEN_AND) || match(p, TOKEN_BANG)) {
|
if (match(p, TOKEN_PLUS_PLUS) || match(p, TOKEN_MINUS) || match(p, TOKEN_MINUS_MINUS) || match(p, TOKEN_STAR) || match(p, TOKEN_AND) || match(p, TOKEN_BANG))
|
||||||
|
{
|
||||||
unary_op op;
|
unary_op op;
|
||||||
switch (p->previous->type) {
|
switch (p->previous->type)
|
||||||
|
{
|
||||||
case TOKEN_PLUS_PLUS:
|
case TOKEN_PLUS_PLUS:
|
||||||
op = UOP_INCR;
|
op = UOP_INCR;
|
||||||
break;
|
break;
|
||||||
|
|
@ -255,7 +306,8 @@ ast_node *parse_unary(parser *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Type cast. */
|
/* Type cast. */
|
||||||
if (match_peek(p, TOKEN_LPAREN) && p->tokens->next && p->tokens->next->type == TOKEN_IDENTIFIER && p->tokens->next->next && p->tokens->next->next->type == TOKEN_RPAREN) {
|
if (match_peek(p, TOKEN_LPAREN) && p->tokens->next && p->tokens->next->type == TOKEN_IDENTIFIER && p->tokens->next->next && p->tokens->next->next->type == TOKEN_RPAREN)
|
||||||
|
{
|
||||||
advance(p);
|
advance(p);
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_CAST;
|
node->type = NODE_CAST;
|
||||||
|
|
@ -275,7 +327,8 @@ ast_node *parse_term(parser *p)
|
||||||
{
|
{
|
||||||
ast_node *left = parse_unary(p);
|
ast_node *left = parse_unary(p);
|
||||||
|
|
||||||
while (match_peek(p, TOKEN_STAR) || match_peek(p, TOKEN_SLASH)) {
|
while (match_peek(p, TOKEN_STAR) || match_peek(p, TOKEN_SLASH))
|
||||||
|
{
|
||||||
binary_op op = peek(p)->type == TOKEN_STAR ? OP_MUL : OP_DIV;
|
binary_op op = peek(p)->type == TOKEN_STAR ? OP_MUL : OP_DIV;
|
||||||
advance(p);
|
advance(p);
|
||||||
ast_node *right = parse_factor(p);
|
ast_node *right = parse_factor(p);
|
||||||
|
|
@ -298,7 +351,8 @@ ast_node *parse_expression(parser *p)
|
||||||
{
|
{
|
||||||
ast_node *left = parse_term(p);
|
ast_node *left = parse_term(p);
|
||||||
|
|
||||||
while (match_peek(p, TOKEN_PLUS) || match_peek(p, TOKEN_MINUS)) {
|
while (match_peek(p, TOKEN_PLUS) || match_peek(p, TOKEN_MINUS))
|
||||||
|
{
|
||||||
binary_op op = peek(p)->type == TOKEN_PLUS ? OP_PLUS : OP_MINUS;
|
binary_op op = peek(p)->type == TOKEN_PLUS ? OP_PLUS : OP_MINUS;
|
||||||
advance(p);
|
advance(p);
|
||||||
ast_node *right = parse_term(p);
|
ast_node *right = parse_term(p);
|
||||||
|
|
@ -314,14 +368,16 @@ ast_node *parse_expression(parser *p)
|
||||||
* If after parsing an expression a `[` character
|
* If after parsing an expression a `[` character
|
||||||
* is found, it should be an array subscript expression.
|
* is found, it should be an array subscript expression.
|
||||||
*/
|
*/
|
||||||
if (match(p, TOKEN_LSQUARE)) {
|
if (match(p, TOKEN_LSQUARE))
|
||||||
|
{
|
||||||
ast_node *index = parse_expression(p);
|
ast_node *index = parse_expression(p);
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_ARRAY_SUBSCRIPT;
|
node->type = NODE_ARRAY_SUBSCRIPT;
|
||||||
node->expr.subscript.expr = left;
|
node->expr.subscript.expr = left;
|
||||||
node->expr.subscript.index = index;
|
node->expr.subscript.index = index;
|
||||||
|
|
||||||
if (!match(p, TOKEN_RSQUARE)) {
|
if (!match(p, TOKEN_RSQUARE))
|
||||||
|
{
|
||||||
error(p, "expected `]`.");
|
error(p, "expected `]`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -332,8 +388,10 @@ ast_node *parse_expression(parser *p)
|
||||||
* If after parsing an expression a `.` character
|
* If after parsing an expression a `.` character
|
||||||
* is found, it should be a member access expression.
|
* is found, it should be a member access expression.
|
||||||
*/
|
*/
|
||||||
if (match(p, TOKEN_DOT)) {
|
if (match(p, TOKEN_DOT))
|
||||||
if (!match_peek(p, TOKEN_IDENTIFIER)) {
|
{
|
||||||
|
if (!match_peek(p, TOKEN_IDENTIFIER))
|
||||||
|
{
|
||||||
error(p, "expected identifier after member access.");
|
error(p, "expected identifier after member access.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -349,9 +407,11 @@ ast_node *parse_expression(parser *p)
|
||||||
* If after parsing an expression a `++` or a `--`
|
* If after parsing an expression a `++` or a `--`
|
||||||
* token is found, it should be a postfix expression.
|
* token is found, it should be a postfix expression.
|
||||||
*/
|
*/
|
||||||
if (match(p, TOKEN_PLUS_PLUS) | match(p, TOKEN_MINUS_MINUS)) {
|
if (match(p, TOKEN_PLUS_PLUS) || match(p, TOKEN_MINUS_MINUS))
|
||||||
|
{
|
||||||
unary_op op;
|
unary_op op;
|
||||||
switch (p->previous->type) {
|
switch (p->previous->type)
|
||||||
|
{
|
||||||
case TOKEN_PLUS_PLUS:
|
case TOKEN_PLUS_PLUS:
|
||||||
op = UOP_INCR;
|
op = UOP_INCR;
|
||||||
break;
|
break;
|
||||||
|
|
@ -370,32 +430,197 @@ ast_node *parse_expression(parser *p)
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((p->tokens->type >= TOKEN_DOUBLE_EQ && p->tokens->type <= TOKEN_NOT_EQ) || (p->tokens->type >= TOKEN_LSHIFT_EQ && p->tokens->type <= TOKEN_DOUBLE_AND))
|
||||||
|
{
|
||||||
|
binary_op op;
|
||||||
|
switch (p->tokens->type)
|
||||||
|
{
|
||||||
|
case TOKEN_DOUBLE_EQ:
|
||||||
|
op = OP_EQ;
|
||||||
|
break;
|
||||||
|
case TOKEN_LESS_THAN:
|
||||||
|
op = OP_LT;
|
||||||
|
break;
|
||||||
|
case TOKEN_GREATER_THAN:
|
||||||
|
op = OP_GT;
|
||||||
|
break;
|
||||||
|
case TOKEN_LESS_EQ:
|
||||||
|
op = OP_LE;
|
||||||
|
break;
|
||||||
|
case TOKEN_GREATER_EQ:
|
||||||
|
op = OP_GE;
|
||||||
|
break;
|
||||||
|
case TOKEN_NOT_EQ:
|
||||||
|
op = OP_NEQ;
|
||||||
|
break;
|
||||||
|
case TOKEN_LSHIFT_EQ:
|
||||||
|
op = OP_LSHIFT_EQ;
|
||||||
|
break;
|
||||||
|
case TOKEN_RSHIFT_EQ:
|
||||||
|
op = OP_RSHIFT_EQ;
|
||||||
|
break;
|
||||||
|
case TOKEN_OR:
|
||||||
|
op = OP_OR;
|
||||||
|
break;
|
||||||
|
case TOKEN_DOUBLE_AND:
|
||||||
|
op = OP_AND;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
advance(p);
|
||||||
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
node->type = NODE_EQUAL;
|
||||||
|
node->expr.binary.left = left;
|
||||||
|
node->expr.binary.operator = op;
|
||||||
|
node->expr.binary.right = parse_expression(p);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ast_node *parse_compound(parser *p)
|
||||||
|
{
|
||||||
|
if (!match(p, TOKEN_LCURLY))
|
||||||
|
{
|
||||||
|
error(p, "expected `{` for beginning of a block.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ast_node *compound = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
compound->type = NODE_UNIT;
|
||||||
|
compound->expr.unit_node.expr = NULL;
|
||||||
|
compound->expr.unit_node.next = NULL;
|
||||||
|
ast_node* tail = compound;
|
||||||
|
// FIXME: This only works with correct blocks, incorrect blocks segfault
|
||||||
|
while (p->tokens->type != TOKEN_RCURLY &&
|
||||||
|
p->tokens->type != TOKEN_END)
|
||||||
|
{
|
||||||
|
ast_node* stmt = parse_statement(p);
|
||||||
|
tail->expr.unit_node.next = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
tail->expr.unit_node.next->expr.unit_node.expr = stmt;
|
||||||
|
tail = tail->expr.unit_node.next;
|
||||||
|
tail->type = NODE_UNIT;
|
||||||
|
}
|
||||||
|
if (p->tokens->type != TOKEN_RCURLY) {
|
||||||
|
error(p, "Unterminated block.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return compound;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_node *parse_double_dot(parser* p) {
|
||||||
|
ast_node* begin = parse_expression(p);
|
||||||
|
if (!begin || (begin->type != NODE_INTEGER && begin->type != NODE_BINARY && begin->type != NODE_UNARY)) {
|
||||||
|
error(p, "Invalid begin range operator.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!match(p, TOKEN_DOUBLE_DOT)) {
|
||||||
|
error(p, "Expected `..`.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ast_node* node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
node->type = NODE_RANGE;
|
||||||
|
node->expr.binary.left = begin;
|
||||||
|
node->expr.binary.operator = OP_PLUS; // Always adding 1
|
||||||
|
if (p->tokens->type != TOKEN_INTEGER) {
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
ast_node* end = parse_expression(p);
|
||||||
|
if (!end || (end->type != NODE_INTEGER && end->type != NODE_BINARY && end->type != NODE_UNARY)) {
|
||||||
|
error(p, "Invalid end range operator.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
node->expr.binary.right = end;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static ast_node *parse_for(parser *p)
|
static ast_node *parse_for(parser *p)
|
||||||
{
|
{
|
||||||
|
advance(p);
|
||||||
|
ast_node* node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
node->type = NODE_FOR;
|
||||||
|
ast_node* range = parse_double_dot(p);
|
||||||
|
node->expr.fr.range = range;
|
||||||
|
if (p->tokens->type != TOKEN_RPAREN) {
|
||||||
|
if (!match(p, TOKEN_COMMA)) {
|
||||||
|
error(p, "Expected `,` seperating for parameters\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
ast_node* array = parse_expression(p);
|
||||||
|
node->expr.fr.array = array;
|
||||||
|
}
|
||||||
|
if (!match(p, TOKEN_RPAREN)) {
|
||||||
|
error(p, "Expected `)` to close for range\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (p->tokens->type != TOKEN_PIPE) {
|
||||||
|
goto parseBody;
|
||||||
|
}
|
||||||
|
advance(p);
|
||||||
|
const char* rangeCapture = p->tokens->lexeme;
|
||||||
|
node->expr.fr.rangeCapture = rangeCapture;
|
||||||
|
node->expr.fr.rangeCaptureLen = p->tokens->lexeme_len;
|
||||||
|
if (!match(p, TOKEN_IDENTIFIER)) {
|
||||||
|
error(p, "Expected range capture to be an identifier\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (p->tokens->type == TOKEN_COMMA) {
|
||||||
|
advance(p);
|
||||||
|
const char* arrayCapture = p->tokens->lexeme;
|
||||||
|
node->expr.fr.arrayCapture = arrayCapture;
|
||||||
|
node->expr.fr.arrayCaptureLen = p->tokens->lexeme_len;
|
||||||
|
if (!match(p, TOKEN_IDENTIFIER)) {
|
||||||
|
error(p, "Expected array capture to be an identifier\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!match(p, TOKEN_PIPE)) {
|
||||||
|
error(p, "Expected `|` to close captures\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
parseBody:;
|
||||||
|
ast_node* body = parse_compound(p);
|
||||||
|
node->expr.fr.body = body;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ast_node *parse_while(parser *p)
|
||||||
|
{
|
||||||
|
ast_node *condition = parse_expression(p);
|
||||||
|
ast_node *body = parse_compound(p);
|
||||||
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
|
node->type = NODE_WHILE;
|
||||||
|
node->expr.whle.body = body;
|
||||||
|
node->expr.whle.condition = condition;
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
static ast_node *parse_statement(parser *p)
|
static ast_node *parse_statement(parser *p)
|
||||||
{
|
{
|
||||||
if (match(p, TOKEN_BREAK)) {
|
if (match(p, TOKEN_BREAK))
|
||||||
if (!match(p, TOKEN_SEMICOLON)) {
|
{
|
||||||
|
if (!match(p, TOKEN_SEMICOLON))
|
||||||
|
{
|
||||||
error(p, "expected `;` after `break`.");
|
error(p, "expected `;` after `break`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_BREAK;
|
node->type = NODE_BREAK;
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_RETURN)) {
|
}
|
||||||
|
else if (match(p, TOKEN_RETURN))
|
||||||
|
{
|
||||||
ast_node *expr = parse_expression(p);
|
ast_node *expr = parse_expression(p);
|
||||||
|
|
||||||
if (!expr) {
|
if (!expr)
|
||||||
|
{
|
||||||
error(p, "expected expression after `return`.");
|
error(p, "expected expression after `return`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!match(p, TOKEN_SEMICOLON)) {
|
if (!match(p, TOKEN_SEMICOLON))
|
||||||
|
{
|
||||||
error(p, "expected `;`.");
|
error(p, "expected `;`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -404,7 +629,9 @@ static ast_node *parse_statement(parser *p)
|
||||||
node->type = NODE_RETURN;
|
node->type = NODE_RETURN;
|
||||||
node->expr.ret.value = expr;
|
node->expr.ret.value = expr;
|
||||||
return node;
|
return node;
|
||||||
} else if (match_peek(p, TOKEN_IDENTIFIER) && p->tokens->next && p->tokens->next->type == TOKEN_COLON) {
|
}
|
||||||
|
else if (match_peek(p, TOKEN_IDENTIFIER) && p->tokens->next && p->tokens->next->type == TOKEN_COLON)
|
||||||
|
{
|
||||||
/* In this case, this is a label. */
|
/* In this case, this is a label. */
|
||||||
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
ast_node *node = arena_alloc(p->allocator, sizeof(ast_node));
|
||||||
node->type = NODE_LABEL;
|
node->type = NODE_LABEL;
|
||||||
|
|
@ -414,8 +641,11 @@ static ast_node *parse_statement(parser *p)
|
||||||
/* Consume `:` */
|
/* Consume `:` */
|
||||||
advance(p);
|
advance(p);
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_GOTO)) {
|
}
|
||||||
if (!match_peek(p, TOKEN_IDENTIFIER)) {
|
else if (match(p, TOKEN_GOTO))
|
||||||
|
{
|
||||||
|
if (!match_peek(p, TOKEN_IDENTIFIER))
|
||||||
|
{
|
||||||
error(p, "expected label identifier after `goto`.");
|
error(p, "expected label identifier after `goto`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -424,18 +654,23 @@ static ast_node *parse_statement(parser *p)
|
||||||
node->expr.label.name = p->tokens->lexeme;
|
node->expr.label.name = p->tokens->lexeme;
|
||||||
node->expr.label.name_len = p->tokens->lexeme_len;
|
node->expr.label.name_len = p->tokens->lexeme_len;
|
||||||
advance(p);
|
advance(p);
|
||||||
if (!match(p, TOKEN_SEMICOLON)) {
|
if (!match(p, TOKEN_SEMICOLON))
|
||||||
|
{
|
||||||
error(p, "expected `;` after `goto`.");
|
error(p, "expected `;` after `goto`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return node;
|
return node;
|
||||||
} else if (match(p, TOKEN_IMPORT)) {
|
}
|
||||||
|
else if (match(p, TOKEN_IMPORT))
|
||||||
|
{
|
||||||
ast_node *expr = parse_expression(p);
|
ast_node *expr = parse_expression(p);
|
||||||
if (!expr) {
|
if (!expr)
|
||||||
|
{
|
||||||
error(p, "expected module path after `import`.");
|
error(p, "expected module path after `import`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (expr->type != NODE_ACCESS && expr->type != NODE_IDENTIFIER) {
|
if (expr->type != NODE_ACCESS && expr->type != NODE_IDENTIFIER)
|
||||||
|
{
|
||||||
error(p, "expected module path after `import`.");
|
error(p, "expected module path after `import`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -444,18 +679,34 @@ static ast_node *parse_statement(parser *p)
|
||||||
node->type = NODE_IMPORT;
|
node->type = NODE_IMPORT;
|
||||||
node->expr.import.path = expr;
|
node->expr.import.path = expr;
|
||||||
|
|
||||||
if (!match(p, TOKEN_SEMICOLON)) {
|
if (!match(p, TOKEN_SEMICOLON))
|
||||||
|
{
|
||||||
error(p, "expected `;` after `import`.");
|
error(p, "expected `;` after `import`.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
} else {
|
}
|
||||||
|
else if (match(p, TOKEN_LOOP))
|
||||||
|
{
|
||||||
|
if (p->tokens->type == TOKEN_LPAREN)
|
||||||
|
{
|
||||||
|
return parse_for(p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return parse_while(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ast_node *expr = parse_expression(p);
|
ast_node *expr = parse_expression(p);
|
||||||
if (!expr) {
|
if (!expr)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (!match(p, TOKEN_SEMICOLON)) {
|
if (!match(p, TOKEN_SEMICOLON))
|
||||||
|
{
|
||||||
error(p, "expected `;` after expression.");
|
error(p, "expected `;` after expression.");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
22
parser.h
22
parser.h
|
|
@ -18,6 +18,8 @@ typedef enum {
|
||||||
OP_LT, // <
|
OP_LT, // <
|
||||||
OP_GE, // >=
|
OP_GE, // >=
|
||||||
OP_LE, // <=
|
OP_LE, // <=
|
||||||
|
OP_RSHIFT_EQ, // >>=
|
||||||
|
OP_LSHIFT_EQ, // <<=
|
||||||
OP_BOR, // |
|
OP_BOR, // |
|
||||||
OP_BAND, // &
|
OP_BAND, // &
|
||||||
OP_BXOR, // ^
|
OP_BXOR, // ^
|
||||||
|
|
@ -69,6 +71,8 @@ typedef enum {
|
||||||
NODE_CAST,
|
NODE_CAST,
|
||||||
NODE_UNARY,
|
NODE_UNARY,
|
||||||
NODE_BINARY,
|
NODE_BINARY,
|
||||||
|
NODE_EQUAL,
|
||||||
|
NODE_RANGE,
|
||||||
NODE_ARRAY_SUBSCRIPT,
|
NODE_ARRAY_SUBSCRIPT,
|
||||||
NODE_ACCESS,
|
NODE_ACCESS,
|
||||||
NODE_CALL,
|
NODE_CALL,
|
||||||
|
|
@ -152,10 +156,22 @@ typedef struct _ast_node {
|
||||||
struct _ast_node *path;
|
struct _ast_node *path;
|
||||||
} import;
|
} import;
|
||||||
struct {
|
struct {
|
||||||
struct _ast_node *parameters;
|
struct _ast_node *range;
|
||||||
struct _ast_node *captures;
|
struct _ast_node *array;
|
||||||
usize param_len;
|
const char* rangeCapture;
|
||||||
|
const char* arrayCapture;
|
||||||
|
int rangeCaptureLen;
|
||||||
|
int arrayCaptureLen;
|
||||||
|
struct _ast_node* body;
|
||||||
} fr; // for
|
} fr; // for
|
||||||
|
struct {
|
||||||
|
struct _ast_node *condition;
|
||||||
|
struct _ast_node *body;
|
||||||
|
} whle; // while
|
||||||
|
struct {
|
||||||
|
struct _ast_node **statements;
|
||||||
|
usize stmt_len;
|
||||||
|
} compound;
|
||||||
} expr;
|
} expr;
|
||||||
} ast_node;
|
} ast_node;
|
||||||
|
|
||||||
|
|
|
||||||
20
test.c
20
test.c
|
|
@ -1,5 +1,17 @@
|
||||||
import example.test.idk.idk;
|
//import example.test.idk.idk;
|
||||||
|
|
||||||
hello:
|
//hello:
|
||||||
goto test;
|
//goto test;
|
||||||
return 5;
|
//return 5;
|
||||||
|
|
||||||
|
// loop(0..15) |i| {
|
||||||
|
// printf("%d\n", i);
|
||||||
|
// }
|
||||||
|
|
||||||
|
return 6;
|
||||||
|
|
||||||
|
loop (0.., list) |i, v| {
|
||||||
|
printf("%d\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 7;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue