391 lines
9.6 KiB
C
391 lines
9.6 KiB
C
#include "parser.h"
|
|
#include "emit.h"
|
|
|
|
Parser parser;
|
|
|
|
/****************************************************
|
|
* Scope
|
|
***************************************************/
|
|
|
|
void
|
|
scope_push(Arena *arena)
|
|
{
|
|
Scope *child = aalloc(arena, sizeof(Scope));
|
|
child->symbols = new_list(arena);
|
|
child->parent = parser.current_scope;
|
|
|
|
parser.current_scope = child;
|
|
}
|
|
|
|
void
|
|
scope_pop()
|
|
{
|
|
Scope *prev = parser.current_scope->parent;
|
|
parser.current_scope = prev;
|
|
}
|
|
|
|
Symbol *
|
|
scope_get_symbol(Scope *scope, const char *name, u32 name_length)
|
|
{
|
|
u32 count, i;
|
|
if(!scope) return nil;
|
|
|
|
count = scope->symbols->count;
|
|
for(i = 0; i < count; i++) {
|
|
Symbol *sym = list_get(scope->symbols, i);
|
|
if(sleq(sym->name, name, name_length)) return sym;
|
|
}
|
|
|
|
return scope_get_symbol(scope->parent, name, name_length);
|
|
}
|
|
|
|
Symbol *
|
|
scope_add_symbol(Arena *arena, const char *name, u32 name_length,
|
|
SymbolType type, u32 size)
|
|
{
|
|
Symbol *sym = scope_get_symbol(parser.current_scope, name, name_length);
|
|
if(sym != nil) return sym;
|
|
|
|
sym = aalloc(arena, sizeof(Symbol));
|
|
scpy(sym->name, name, slen(name));
|
|
sym->name_length = slen(name);
|
|
sym->type = type;
|
|
sym->secondary_type = VOID;
|
|
sym->size = size;
|
|
sym->ref = 0;
|
|
if(type == PLEX || type == METHOD || type == TRAIT) {
|
|
sym->args = new_list(arena);
|
|
sym->fields = new_list(arena);
|
|
}
|
|
|
|
list_push(arena, parser.current_scope->symbols, sym, sizeof(Symbol));
|
|
|
|
return sym;
|
|
}
|
|
|
|
/****************************************************
|
|
* Parser
|
|
***************************************************/
|
|
|
|
bool
|
|
advance()
|
|
{
|
|
parser.previous = parser.current;
|
|
|
|
for(;;) {
|
|
parser.current = next_token();
|
|
if(parser.current.type != TOKEN_ERROR) return true;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
static bool
|
|
check(TokenType type)
|
|
{
|
|
return parser.current.type == type;
|
|
}
|
|
|
|
bool
|
|
consume(TokenType type)
|
|
{
|
|
if(check(type)) {
|
|
advance();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
match(TokenType type)
|
|
{
|
|
if(!check(type)) return false;
|
|
advance();
|
|
return true;
|
|
}
|
|
|
|
static void expression();
|
|
static void statement();
|
|
static void declaration();
|
|
static ParseRule *get_rule(TokenType type);
|
|
static void parse_precedence(Precedence precedence);
|
|
|
|
static void
|
|
binary()
|
|
{
|
|
TokenType operatorType = parser.previous.type;
|
|
ParseRule *rule = get_rule(operatorType);
|
|
|
|
switch(operatorType) {
|
|
case TOKEN_BANG_EQ:
|
|
emit_ne();
|
|
break;
|
|
case TOKEN_EQ_EQ:
|
|
emit_eq();
|
|
break;
|
|
case TOKEN_GT:
|
|
emit_ge();
|
|
break;
|
|
case TOKEN_GTE:
|
|
emit_ge();
|
|
break;
|
|
case TOKEN_LT:
|
|
emit_lt();
|
|
break;
|
|
case TOKEN_LTE:
|
|
emit_le();
|
|
break;
|
|
case TOKEN_PLUS:
|
|
emit_add();
|
|
break;
|
|
case TOKEN_MINUS:
|
|
emit_sub();
|
|
break;
|
|
case TOKEN_STAR:
|
|
emit_mul();
|
|
break;
|
|
case TOKEN_SLASH:
|
|
emit_div();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* Move to above switch statement for postfix */
|
|
parse_precedence((Precedence)(rule->precedence + 1));
|
|
}
|
|
|
|
static void
|
|
literal()
|
|
{
|
|
switch(parser.previous.type) {
|
|
case TOKEN_KEYWORD_FALSE:
|
|
emit_false();
|
|
break;
|
|
case TOKEN_KEYWORD_TRUE:
|
|
emit_true();
|
|
break;
|
|
case TOKEN_KEYWORD_NIL:
|
|
emit_nil();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void
|
|
expression()
|
|
{
|
|
parse_precedence(PREC_ASSIGNMENT);
|
|
}
|
|
|
|
static void
|
|
declaration()
|
|
{
|
|
if(match(TOKEN_TYPE_INT)) {
|
|
emit_int_type();
|
|
} else if(match(TOKEN_TYPE_NAT)) {
|
|
emit_nat_type();
|
|
} else if(match(TOKEN_TYPE_REAL)) {
|
|
emit_real_type();
|
|
} else if(match(TOKEN_TYPE_STR)) {
|
|
emit_str_type();
|
|
} else if(match(TOKEN_TYPE_BOOL)) {
|
|
emit_bool_type();
|
|
} else if(match(TOKEN_TYPE_BYTE)) {
|
|
emit_byte_type();
|
|
} else if(match(TOKEN_TYPE_U8)) {
|
|
emit_u8_type();
|
|
} else if(match(TOKEN_TYPE_I8)) {
|
|
emit_i8_type();
|
|
} else if(match(TOKEN_TYPE_U16)) {
|
|
emit_u16_type();
|
|
} else if(match(TOKEN_TYPE_I16)) {
|
|
emit_i16_type();
|
|
} else if(match(TOKEN_IDENTIFIER)) {
|
|
/**
|
|
* maybe a Plex?
|
|
* lookup plex defs
|
|
* if not then
|
|
*/
|
|
}
|
|
|
|
statement();
|
|
}
|
|
|
|
static void
|
|
statement()
|
|
{
|
|
if(match(TOKEN_KEYWORD_PRINT))
|
|
emit_print();
|
|
else
|
|
expression();
|
|
}
|
|
|
|
static void
|
|
grouping()
|
|
{
|
|
emit_open_paren();
|
|
|
|
expression();
|
|
|
|
emit_close_paren();
|
|
consume(TOKEN_RPAREN);
|
|
}
|
|
|
|
static void
|
|
number()
|
|
{
|
|
emit_int(parser.previous.start, parser.previous.length);
|
|
}
|
|
|
|
static void
|
|
string()
|
|
{
|
|
emit_str(parser.previous.start, parser.previous.length);
|
|
}
|
|
|
|
static void
|
|
unary()
|
|
{
|
|
TokenType operatorType = parser.previous.type;
|
|
|
|
switch(operatorType) {
|
|
case TOKEN_MINUS:
|
|
emit_neg();
|
|
break;
|
|
case TOKEN_BANG:
|
|
emit_not();
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
/* Move to above switch statement for postfix */
|
|
parse_precedence(PREC_UNARY);
|
|
}
|
|
|
|
ParseRule rules[] = {
|
|
/* 0 */ {NULL, NULL, PREC_NONE},
|
|
/* 1 */ {NULL, NULL, PREC_NONE},
|
|
/* 2 */ {NULL, NULL, PREC_NONE},
|
|
/* 3 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_INT */
|
|
/* 4 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_NAT */
|
|
/* 5 */ {number, NULL, PREC_NONE}, /* TOKEN_LITERAL_REAL */
|
|
/* 6 */ {string, NULL, PREC_NONE}, /* TOKEN_LITERAL_STR */
|
|
/* 7 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_I8 */
|
|
/* 8 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_I16 */
|
|
/* 9 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_INT */
|
|
/*10 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_U8 */
|
|
/*11 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_U16 */
|
|
/*12 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_NAT */
|
|
/*13 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_REAL */
|
|
/*14 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_STR */
|
|
/*15 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_BOOL */
|
|
/*16 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_BYTE */
|
|
/*17 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_VOID */
|
|
/*18 */ {NULL, NULL, PREC_NONE}, /* TOKEN_TYPE_PTR */
|
|
/*19 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_PLEX */
|
|
/*20 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FN */
|
|
/*21 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_CONST */
|
|
/*22 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_IF */
|
|
/*23 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_IS */
|
|
/*24 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_AS */
|
|
/*25 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_ELSE */
|
|
/*26 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_WHILE */
|
|
/*27 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FOR */
|
|
/*28 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_RETURN */
|
|
/*29 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_USE */
|
|
/*30 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_INIT */
|
|
/*31 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_THIS */
|
|
/*32 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_GLOBAL */
|
|
/*33 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_OPEN */
|
|
/*34 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_READ */
|
|
/*35 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_WRITE */
|
|
/*36 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_STAT */
|
|
/*37 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_CLOSE */
|
|
/*38 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_LOOP */
|
|
/*39 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_DO */
|
|
/*40 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_NIL */
|
|
/*41 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_TRUE */
|
|
/*42 */ {literal, NULL, PREC_NONE}, /* TOKEN_KEYWORD_FALSE */
|
|
/*43 */ {NULL, NULL, PREC_NONE}, /* TOKEN_KEYWORD_PRINT */
|
|
/*44 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_NOT */
|
|
/*45 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_AND */
|
|
/*46 */ {NULL, NULL, PREC_NONE}, /* TOKEN_OPERATOR_OR */
|
|
/*47 */ {unary, NULL, PREC_NONE}, /* TOKEN_BANG */
|
|
/*48 */ {NULL, binary, PREC_EQUALITY}, /* TOKEN_BANG_EQ */
|
|
/*49 */ {NULL, NULL, PREC_NONE}, /* TOKEN_EQ */
|
|
/*50 */ {NULL, binary, PREC_EQUALITY}, /* TOKEN_EQ_EQ */
|
|
/*51 */ {NULL, NULL, PREC_NONE}, /* TOKEN_AND */
|
|
/*52 */ {NULL, NULL, PREC_NONE}, /* TOKEN_AND_AND */
|
|
/*53 */ {NULL, NULL, PREC_NONE}, /* TOKEN_PIPE */
|
|
/*54 */ {NULL, NULL, PREC_NONE}, /* TOKEN_PIPE_PIPE */
|
|
/*55 */ {NULL, NULL, PREC_NONE}, /* TOKEN_QUESTION */
|
|
/*56 */ {NULL, NULL, PREC_NONE}, /* TOKEN_QUESTION_DOT */
|
|
/*57 */ {NULL, binary, PREC_TERM}, /* TOKEN_PLUS */
|
|
/*58 */ {unary, binary, PREC_TERM}, /* TOKEN_MINUS */
|
|
/*59 */ {NULL, binary, PREC_FACTOR}, /* TOKEN_STAR */
|
|
/*60 */ {NULL, binary, PREC_FACTOR}, /* TOKEN_SLASH */
|
|
/*61 */ {NULL, NULL, PREC_NONE}, /* TOKEN_MESH */
|
|
/*62 */ {NULL, NULL, PREC_NONE}, /* TOKEN_BIG_MONEY */
|
|
/*63 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_GT */
|
|
/*64 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_LT */
|
|
/*65 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_GTE */
|
|
/*66 */ {NULL, binary, PREC_COMPARISON}, /* TOKEN_LTE */
|
|
/*67 */ {NULL, NULL, PREC_NONE}, /* TOKEN_DOT */
|
|
/*68 */ {NULL, NULL, PREC_NONE}, /* TOKEN_COMMA */
|
|
/*69 */ {NULL, NULL, PREC_NONE}, /* TOKEN_COLON */
|
|
/*70 */ {NULL, NULL, PREC_NONE}, /* TOKEN_CARET */
|
|
/*71 */ {NULL, NULL, PREC_NONE}, /* TOKEN_SEMICOLON */
|
|
/*72 */ {grouping, NULL, PREC_NONE}, /* TOKEN_LPAREN */
|
|
/*73 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RPAREN */
|
|
/*74 */ {NULL, NULL, PREC_NONE}, /* TOKEN_LBRACE */
|
|
/*75 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RBRACE */
|
|
/*76 */ {NULL, NULL, PREC_NONE}, /* TOKEN_LBRACKET */
|
|
/*77 */ {NULL, NULL, PREC_NONE}, /* TOKEN_RBRACKET */
|
|
/*78 */ {NULL, NULL, PREC_NONE} /* TOKEN_ARROW_RIGHT */
|
|
};
|
|
|
|
static void
|
|
parse_precedence(Precedence precedence)
|
|
{
|
|
ParseFn prefixRule;
|
|
ParseFn infixRule;
|
|
|
|
advance();
|
|
prefixRule = get_rule(parser.previous.type)->prefix;
|
|
if(prefixRule == NULL) {
|
|
return;
|
|
}
|
|
|
|
prefixRule();
|
|
|
|
while(precedence <= get_rule(parser.current.type)->precedence) {
|
|
advance();
|
|
infixRule = get_rule(parser.previous.type)->infix;
|
|
infixRule();
|
|
}
|
|
}
|
|
|
|
static ParseRule *
|
|
get_rule(TokenType type)
|
|
{
|
|
return &rules[type];
|
|
}
|
|
|
|
bool
|
|
compile(char *source)
|
|
{
|
|
init_lexer(source);
|
|
advance();
|
|
|
|
prolog();
|
|
|
|
while(!match(TOKEN_EOF)) declaration();
|
|
|
|
epilogue();
|
|
|
|
return true;
|
|
}
|