diff options
-rw-r--r-- | base_cgen.c | 7 | ||||
-rw-r--r-- | cgen.c | 12 | ||||
-rw-r--r-- | eval.c | 25 | ||||
-rw-r--r-- | out.c | 12 | ||||
-rw-r--r-- | parse.c | 328 | ||||
-rw-r--r-- | test.toc | 12 | ||||
-rw-r--r-- | toc.c | 1 | ||||
-rw-r--r-- | tokenizer.c | 7 | ||||
-rw-r--r-- | types.c | 75 |
9 files changed, 298 insertions, 181 deletions
diff --git a/base_cgen.c b/base_cgen.c index 0e1f7f9..537f1c5 100644 --- a/base_cgen.c +++ b/base_cgen.c @@ -149,6 +149,9 @@ static bool cgen_type_pre(CGenerator *g, Type *t) { if (!cgen_type_pre(g, ret_type)) return false; cgen_write(g, "(*"); } break; + case TYPE_ARR: + cgen_type_pre(g, t->arr.of); + break; } return true; } @@ -181,6 +184,10 @@ static bool cgen_type_post(CGenerator *g, Type *t) { cgen_write_space(g); if (!cgen_type_post(g, ret_type)) return false; } break; + case TYPE_ARR: + cgen_write(g, "[%lu]", t->arr.n); + cgen_type_post(g, t->arr.of); + break; } return true; } @@ -70,11 +70,13 @@ static bool cgen_decl(CGenerator *g, Declaration *d) { cgen_type_pre(g, &d->type); cgen_ident(g, *ident, NULL); cgen_type_post(g, &d->type); - cgen_write_space(g); - cgen_write(g, "="); - cgen_write_space(g); - if (!cgen_expr(g, &d->expr)) { - return false; + if (d->flags & DECL_FLAG_HAS_EXPR) { + cgen_write_space(g); + cgen_write(g, "="); + cgen_write_space(g); + if (!cgen_expr(g, &d->expr)) { + return false; + } } cgen_write(g, "; "); } @@ -0,0 +1,25 @@ +static bool eval_expr_as_float(Expression *e, FloatLiteral *f) { + switch (e->kind) { + case EXPR_FLOAT_LITERAL: + *f = e->floatl; + return true; + case EXPR_INT_LITERAL: + *f = (FloatLiteral)e->intl; + return true; + } + err_print(e->where, "Not implemented yet"); + return false; +} + +static bool eval_expr_as_int(Expression *e, IntLiteral *i) { + switch (e->kind) { + case EXPR_FLOAT_LITERAL: + err_print(e->where, "Expected integer, but found floating-point literal."); + return false; + case EXPR_INT_LITERAL: + *i = e->intl; + return true; + } + err_print(e->where, "Not implemented yet"); + return false; +} @@ -1,18 +1,8 @@ #include "out.h" /* toc */ -static void a___(void); -static void a___1(void); void main__(void) { - void (*foo)(void) = a___; - void (*bar)(void) = a___1; -} -static void a___(void) { - a___1(); - float x = ((-3)-(-3.200000)); -} -static void a___1(void) { - a___(); + void (*(*foo[3])(void) )(void (*[3])(void) ) ; } int main(void) { @@ -2,7 +2,8 @@ typedef enum { TYPE_VOID, TYPE_BUILTIN, - TYPE_FN + TYPE_FN, + TYPE_ARR /* e.g. [5]int */ } TypeKind; typedef enum { @@ -20,7 +21,7 @@ typedef enum { } BuiltinType; #define TYPE_FLAG_FLEXIBLE 0x01 - +#define TYPE_FLAG_RESOLVED 0x02 typedef struct Type { Location where; @@ -31,6 +32,13 @@ typedef struct Type { struct { Array types; /* [0] = ret_type, [1..] = param_types */ } fn; + struct { + struct Type *of; + union { + IntLiteral n; /* this is NOT set by parse_type; it will be handled by types.c */ + struct Expression *n_expr; + }; + } arr; }; } Type; @@ -181,6 +189,119 @@ static Keyword builtin_type_to_kw(BuiltinType t) { return KW_COUNT; } + + +#define NOT_AN_OP -1 +static int op_precedence(Keyword op) { + switch (op) { + case KW_PLUS: + return 10; + case KW_MINUS: + return 20; + default: + return NOT_AN_OP; + } +} + + +/* + ends_with = which keyword does this expression end with? + if it's KW_RPAREN, this will match parentheses properly. +*/ +typedef enum { + EXPR_END_RPAREN_OR_COMMA, + EXPR_END_RSQUARE, + EXPR_END_SEMICOLON +} ExprEndKind; +static Token *expr_find_end(Parser *p, ExprEndKind ends_with) { + Tokenizer *t = p->tokr; + int bracket_level = 0; /* if ends_with = EXPR_END_RSQUARE, used for square brackets, + if ends_with = EXPR_END_RPAREN_OR_COMMA, used for parens */ + int brace_level = 0; + Token *token = t->token; + while (1) { + switch (ends_with) { + case EXPR_END_RPAREN_OR_COMMA: + if (token->kind == TOKEN_KW) { + switch (token->kw) { + case KW_COMMA: + if (bracket_level == 0) + return token; + break; + case KW_LPAREN: + bracket_level++; + break; + case KW_RPAREN: + bracket_level--; + if (bracket_level < 0) + return token; + break; + default: break; + } + } + break; + case EXPR_END_RSQUARE: + if (token->kind == TOKEN_KW) { + switch (token->kw) { + case KW_LSQUARE: + bracket_level++; + break; + case KW_RSQUARE: + bracket_level--; + if (bracket_level < 0) + return token; + break; + default: break; + } + } + break; + case EXPR_END_SEMICOLON: + if (token->kind == TOKEN_KW) { + switch (token->kw) { + case KW_SEMICOLON: + /* ignore semicolons inside braces {} */ + if (brace_level == 0) + return token; + break; + case KW_LBRACE: + brace_level++; + break; + case KW_RBRACE: + brace_level--; + if (brace_level < 0) { + t->token = token; + tokr_err(t, "Closing '}' without matching opening '{'."); + return NULL; + } + break; + default: break; + } + } + break; + } + if (token->kind == TOKEN_EOF) { + switch (ends_with) { + case EXPR_END_SEMICOLON: + if (brace_level > 0) { + tokr_err(t, "Opening brace was never closed."); /* FEATURE: Find out where this is */ + return NULL; + } else { + tokr_err(t, "Could not find ';' at end of expression."); + return NULL; + } + case EXPR_END_RPAREN_OR_COMMA: + tokr_err(t, "Opening ( was never closed."); + return NULL; + case EXPR_END_RSQUARE: + tokr_err(t, "Opening [ was never closed."); + return NULL; + } + } + token++; + } +} + +static bool parse_expr(Parser *p, Expression *e, Token *end); static bool parse_type(Parser *p, Type *type) { Tokenizer *t = p->tokr; type->where = t->token->where; @@ -189,51 +310,67 @@ static bool parse_type(Parser *p, Type *type) { case TOKEN_KW: type->kind = TYPE_BUILTIN; type->builtin = kw_to_builtin_type(t->token->kw); - if (type->builtin == BUILTIN_TYPE_COUNT) { - /* Not a builtin */ - if (t->token->kw == KW_FN) { - /* function type */ - type->kind = TYPE_FN; - arr_create(&type->fn.types, sizeof(Type)); - t->token++; - if (!token_is_kw(t->token, KW_LPAREN)) { - tokr_err(t, "Expected ( for function type."); - return false; - } - arr_add(&type->fn.types); /* add return type */ - t->token++; - if (!token_is_kw(t->token, KW_RPAREN)) { - while (1) { - Type *param_type = arr_add(&type->fn.types); - if (!parse_type(p, param_type)) return false; - if (token_is_kw(t->token, KW_RPAREN)) - break; - if (!token_is_kw(t->token, KW_COMMA)) { - tokr_err(t, "Expected , to continue function type parameter list."); - return false; - } - t->token++; /* move past , */ - } - } - t->token++; /* move past ) */ - Type *ret_type = type->fn.types.data; - /* if there's a symbol, that can't be the start of a type */ - if (t->token->kind == TOKEN_KW - && t->token->kw <= KW_LAST_SYMBOL) { - ret_type->kind = TYPE_VOID; - ret_type->flags = 0; - } else { - if (!parse_type(p, ret_type)) + if (type->builtin != BUILTIN_TYPE_COUNT) { + t->token++; + return true; + } + /* Not a builtin */ + switch (t->token->kw) { + case KW_FN: { + /* function type */ + type->kind = TYPE_FN; + arr_create(&type->fn.types, sizeof(Type)); + t->token++; + if (!token_is_kw(t->token, KW_LPAREN)) { + tokr_err(t, "Expected ( for function type."); + return false; + } + arr_add(&type->fn.types); /* add return type */ + t->token++; + if (!token_is_kw(t->token, KW_RPAREN)) { + while (1) { + Type *param_type = arr_add(&type->fn.types); + if (!parse_type(p, param_type)) return false; + if (token_is_kw(t->token, KW_RPAREN)) + break; + if (!token_is_kw(t->token, KW_COMMA)) { + tokr_err(t, "Expected , to continue function type parameter list."); return false; + } + t->token++; /* move past , */ } - return true; } - - break; - } else { - t->token++; + t->token++; /* move past ) */ + Type *ret_type = type->fn.types.data; + /* if there's a symbol that isn't [, that can't be the start of a type */ + if (t->token->kind == TOKEN_KW + && t->token->kw <= KW_LAST_SYMBOL + && t->token->kw != KW_LSQUARE) { + ret_type->kind = TYPE_VOID; + ret_type->flags = 0; + } else { + if (!parse_type(p, ret_type)) + return false; + } return true; } + case KW_LSQUARE: { + /* array type */ + Token *start = t->token; + type->kind = TYPE_ARR; + t->token++; /* move past [ */ + Token *end = expr_find_end(p, EXPR_END_RSQUARE); + type->arr.n_expr = parser_new_expr(p); + if (!parse_expr(p, type->arr.n_expr, end)) return false; + t->token = end + 1; /* go past ] */ + type->arr.of = err_malloc(sizeof *type->arr.of); /* OPTIM */ + if (!parse_type(p, type->arr.of)) return false; + type->flags = 0; + type->where = start->where; + return true; + } + default: break; + } break; default: break; } @@ -335,101 +472,6 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { return parse_block(p, &f->body); } -#define NOT_AN_OP -1 -static int op_precedence(Keyword op) { - switch (op) { - case KW_PLUS: - return 10; - case KW_MINUS: - return 20; - default: - return NOT_AN_OP; - } -} - - -/* - ends_with = which keyword does this expression end with? - if it's KW_RPAREN, this will match parentheses properly. -*/ -typedef enum { - EXPR_END_RPAREN_OR_COMMA, - EXPR_END_SEMICOLON -} ExprEndKind; -static Token *expr_find_end(Parser *p, ExprEndKind ends_with) { - Tokenizer *t = p->tokr; - int bracket_level = 0; - int brace_level = 0; - Token *token = t->token; - while (1) { - switch (ends_with) { - case EXPR_END_RPAREN_OR_COMMA: - if (token->kind == TOKEN_KW) { - switch (token->kw) { - case KW_COMMA: - if (bracket_level == 0) - return token; - break; - case KW_LPAREN: - bracket_level++; - break; - case KW_RPAREN: - bracket_level--; - if (bracket_level < 0) - return token; - break; - default: break; - } - } - break; - case EXPR_END_SEMICOLON: - if (token->kind == TOKEN_KW) { - switch (token->kw) { - case KW_SEMICOLON: - /* ignore semicolons inside braces {} */ - if (brace_level == 0) - return token; - break; - case KW_LBRACE: - brace_level++; - break; - case KW_RBRACE: - brace_level--; - if (brace_level < 0) { - t->token = token; - tokr_err(t, "Closing '}' without matching opening '{'."); - return NULL; - } - break; - default: break; - } - } - break; - } - if (token->kind == TOKEN_EOF) { - switch (ends_with) { - case EXPR_END_SEMICOLON: - if (brace_level > 0) { - tokr_err(t, "Opening brace was never closed."); /* FEATURE: Find out where this is */ - return NULL; - } else { - tokr_err(t, "Could not find ';' at end of expression."); - return NULL; - } - case EXPR_END_RPAREN_OR_COMMA: - if (bracket_level > 0) { - tokr_err(t, "Opening parenthesis was never closed."); /* FEATURE: Find out where this is */ - return NULL; - } else { - tokr_err(t, "Could not find ')' or ',' at end of expression."); - return NULL; - } - } - } - token++; - } -} - static bool parse_expr(Parser *p, Expression *e, Token *end) { Tokenizer *t = p->tokr; if (end == NULL) return false; @@ -840,7 +882,7 @@ static bool parse_file(Parser *p, ParsedFile *f) { #define PARSE_PRINT_LOCATION(l) //fprintf(out, "[l%lu]", (unsigned long)(l).line); - +static void fprint_expr(FILE *out, Expression *e); static void fprint_type(FILE *out, Type *t) { PARSE_PRINT_LOCATION(t->where); switch (t->kind) { @@ -860,6 +902,16 @@ static void fprint_type(FILE *out, Type *t) { fprintf(out, ") "); fprint_type(out, &types[0]); } break; + case TYPE_ARR: + fprintf(out, "["); + if (t->flags & TYPE_FLAG_RESOLVED) { + fprintf(out, INT_LITERAL_FMT, t->arr.n); + } else { + fprint_expr(out, t->arr.n_expr); + } + fprintf(out, "]"); + fprint_type(out, t->arr.of); + break; } } @@ -1,11 +1,5 @@ main @= fn() { - - foo := fn() { - bar(); - x := -3--3.2; - }; - - bar := fn() { - foo(); - }; + foo : [3]fn()fn([42]fn()); + bar : [3]fn([37]fn(int)int); + foo + bar; }; @@ -15,6 +15,7 @@ #include "identifiers.c" #include "tokenizer.c" #include "parse.c" +#include "eval.c" #include "types.c" #include "base_cgen.c" #include "decls_cgen.c" diff --git a/tokenizer.c b/tokenizer.c index 7333db8..369f234 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -17,6 +17,8 @@ typedef enum { KW_RPAREN, KW_LBRACE, KW_RBRACE, + KW_LSQUARE, + KW_RSQUARE, KW_EQEQ, KW_LT, KW_LE, @@ -39,7 +41,7 @@ typedef enum { } Keyword; static const char *keywords[KW_COUNT] = - {";", "=", ":", "@", ",", "(", ")", "{", "}", "==", "<", "<=", "-", "+", "fn", + {";", "=", ":", "@", ",", "(", ")", "{", "}", "[", "]", "==", "<", "<=", "-", "+", "fn", "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "double"}; /* Returns KW_COUNT if it's not a keyword */ @@ -65,6 +67,7 @@ static Keyword tokenize_kw(char **s) { typedef unsigned long long IntLiteral; typedef long double FloatLiteral; /* OPTIM: Switch to double */ +#define INT_LITERAL_FMT "%llu" typedef enum { NUM_LITERAL_INT, @@ -124,7 +127,7 @@ static void token_fprint(FILE *out, Token *t) { fprintf(out, "number: "); switch (t->num.kind) { case NUM_LITERAL_INT: - fprintf(out, "%llu", t->num.intval); + fprintf(out, INT_LITERAL_FMT, t->num.intval); break; case NUM_LITERAL_FLOAT: fprintf(out, "%g", (double)t->num.floatval); @@ -50,20 +50,20 @@ static bool block_exit(Block *b) { /* returns the number of characters written, not including the null character */ -static size_t type_to_str(Type *a, char *buffer, size_t bufsize) { - switch (a->kind) { +static size_t type_to_str(Type *t, char *buffer, size_t bufsize) { + switch (t->kind) { case TYPE_VOID: return str_copy(buffer, bufsize, "void"); case TYPE_BUILTIN: { - const char *s = keywords[builtin_type_to_kw(a->builtin)]; + const char *s = keywords[builtin_type_to_kw(t->builtin)]; return str_copy(buffer, bufsize, s); } case TYPE_FN: { /* number of chars written */ size_t written = str_copy(buffer, bufsize, "fn ("); - Type *ret_type = a->fn.types.data; + Type *ret_type = t->fn.types.data; Type *param_types = ret_type + 1; - size_t nparams = a->fn.types.len - 1; + size_t nparams = t->fn.types.len - 1; for (size_t i = 0; i < nparams; i++) { if (i > 0) written += str_copy(buffer + written, bufsize - written, ", "); @@ -76,6 +76,18 @@ static size_t type_to_str(Type *a, char *buffer, size_t bufsize) { } return written; } break; + case TYPE_ARR: { + size_t written = str_copy(buffer, bufsize, "["); + if (t->flags & TYPE_FLAG_RESOLVED) { + snprintf(buffer + written, bufsize - written, INT_LITERAL_FMT, t->arr.n); + written += strlen(buffer + written); + } else { + written += str_copy(buffer + written, bufsize - written, "N"); + } + written += str_copy(buffer + written, bufsize - written, "]"); + written += type_to_str(t->arr.of, buffer + written, bufsize - written); + return written; + } break; } assert(0); @@ -138,6 +150,9 @@ static bool type_eq(Type *a, Type *b) { } return true; } + case TYPE_ARR: + if (a->arr.n != b->arr.n) return false; + return type_eq(a->arr.of, b->arr.of); } assert(0); return false; @@ -274,13 +289,14 @@ static bool type_of_expr(Expression *e, Type *t) { if (!match) { char s1[128], s2[128]; type_to_str(lhs_type, s1, sizeof s1); - type_to_str(lhs_type, s2, sizeof s2); + type_to_str(rhs_type, s2, sizeof s2); const char *op; switch (e->binary.op) { case BINARY_PLUS: op = "+"; break; case BINARY_MINUS: op = "-"; break; } err_print(e->where, "Mismatched types to operator %s: %s and %s", op, s1, s2); + return false; } return true; } @@ -290,6 +306,27 @@ static bool type_of_expr(Expression *e, Type *t) { return true; } +/* fixes the type (replaces [5+3]int with [8]int, etc.) */ +static bool type_resolve(Type *t) { + if (t->flags & TYPE_FLAG_RESOLVED) return true; + switch (t->kind) { + case TYPE_ARR: + /* it's an array */ + if (!type_resolve(t->arr.of)) return false; /* resolve inner type */ + if (!eval_expr_as_int(t->arr.n_expr, &t->arr.n)) return false; /* resolve N */ + break; + case TYPE_FN: + arr_foreach(&t->fn.types, Type, child_type) { + if (!type_resolve(child_type)) + return false; + } + break; + default: break; + } + t->flags |= TYPE_FLAG_RESOLVED; + return true; +} + static bool types_stmt(Statement *s); static bool types_block(Block *b) { @@ -304,11 +341,10 @@ static bool types_block(Block *b) { static bool types_expr(Expression *e) { Type *t = &e->type; - type_of_expr(e, t); + if (!type_of_expr(e, t)) return false; switch (e->kind) { - case EXPR_FN: { - types_block(&e->fn.body); - } break; + case EXPR_FN: + return types_block(&e->fn.body); case EXPR_CALL: { bool ret = true; arr_foreach(&e->call.args, Expression, arg) { @@ -323,13 +359,19 @@ static bool types_expr(Expression *e) { static bool types_decl(Declaration *d) { - if (!types_expr(&d->expr)) return false; if (d->flags & DECL_FLAG_FOUND_TYPE) return true; - if (d->flags & DECL_FLAG_INFER_TYPE) { - d->type = d->expr.type; - } else { - if (!type_must_eq(d->expr.where, &d->type, &d->expr.type)) { + if (!(d->flags & DECL_FLAG_INFER_TYPE)) { + /* type supplied */ + if (!type_resolve(&d->type)) return false; + } + if (d->flags & DECL_FLAG_HAS_EXPR) { + if (!types_expr(&d->expr)) return false; + if (d->flags & DECL_FLAG_INFER_TYPE) { + d->type = d->expr.type; + } else { + if (!type_must_eq(d->expr.where, &d->type, &d->expr.type)) + return false; } } d->flags |= DECL_FLAG_FOUND_TYPE; @@ -339,8 +381,9 @@ static bool types_decl(Declaration *d) { static bool types_stmt(Statement *s) { switch (s->kind) { case STMT_EXPR: - if (!types_expr(&s->expr)) + if (!types_expr(&s->expr)) { return false; + } break; case STMT_DECL: if (!types_decl(&s->decl)) |