diff options
-rw-r--r-- | cgen.c | 5 | ||||
-rw-r--r-- | eval.c | 94 | ||||
-rw-r--r-- | out.c | 6 | ||||
-rw-r--r-- | parse.c | 92 | ||||
-rw-r--r-- | test.toc | 8 | ||||
-rw-r--r-- | toc.c | 8 | ||||
-rw-r--r-- | tokenizer.c | 26 | ||||
-rw-r--r-- | types.c | 82 | ||||
-rw-r--r-- | util/err.c | 8 |
9 files changed, 209 insertions, 120 deletions
@@ -68,6 +68,11 @@ static bool cgen_stmt(CGenerator *g, Statement *s); static bool cgen_decl(CGenerator *g, Declaration *d) { arr_foreach(&d->idents, Identifier, ident) { cgen_type_pre(g, &d->type); + if (d->flags & DECL_FLAG_CONST) { + cgen_write_space(g); + cgen_write(g, "const"); + cgen_write_space(g); + } cgen_ident(g, *ident, NULL); cgen_type_post(g, &d->type); if (d->flags & DECL_FLAG_HAS_EXPR) { @@ -1,24 +1,90 @@ -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_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) { +static bool eval_expr_as_int(Expression *e, Integer *i) { + /* OPTIM: cache eval'd expression values? (probably only for declarations) */ 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; + if (e->intl > (UInteger)INTEGER_MAX) { /* TODO: FIXME */ + err_print(e->where, "Overflow when evaluating integer."); + return false; + } + *i = (Integer)e->intl; return true; + case EXPR_STR_LITERAL: + err_print(e->where, "Expected integer, but found string literal."); + return false; + case EXPR_UNARY_OP: + switch (e->unary.op) { + case UNARY_MINUS: { + Integer of; + if (!eval_expr_as_int(e->unary.of, &of)) return false; + *i = -of; + return true; + } + } + break; + case EXPR_BINARY_OP: { + + switch (e->binary.op) { + case BINARY_PLUS: + case BINARY_MINUS: { + Integer lhs, rhs; + if (!eval_expr_as_int(e->binary.lhs, &lhs)) return false; + if (!eval_expr_as_int(e->binary.rhs, &rhs)) return false; + switch (e->binary.op) { + case BINARY_PLUS: + *i = lhs + rhs; + return true; + case BINARY_MINUS: + *i = lhs - rhs; + return true; + } + } + } + } break; + case EXPR_IDENT: { + Identifier id = e->ident; + IdentDecl *id_decl = ident_decl(id); + if (!id_decl) { + char *id_str = ident_to_str(id); + err_print(e->where, "Undeclared identifier: %s", id_str); + free(id_str); + return false; + } + Declaration *d = id_decl->decl; + if (!(d->flags & DECL_FLAG_CONST)) { + err_print(e->where, "Use of non-constant identifier in a constant expression."); + info_print(d->where, "Declaration was here."); + return false; + } + if (d->type.kind != TYPE_BUILTIN || !type_builtin_is_integer(d->type.builtin)) { + char type_str[128]; + type_to_str(&d->type, type_str, sizeof type_str); + err_print(e->where, "Expected integer, but identifier has type %s.", type_str); + info_print(d->where, "Declaration was here."); + return false; + } + eval_expr_as_int(&d->expr, i); + + return true; + } break; + case EXPR_FN: + err_print(e->where, "Expected integer, but found function."); + return false; } err_print(e->where, "Not implemented yet"); return false; @@ -2,7 +2,11 @@ /* toc */ void main__(void) { - void (*(*foo[3])(void) )(void (*[3])(void) ) ; + int64_t const N = 5; + int64_t const FOO = 1928; + int64_t const BAR = 5; + int64_t foo[1935]; + int64_t bar[11]; } int main(void) { @@ -35,7 +35,7 @@ typedef struct Type { struct { struct Type *of; union { - IntLiteral n; /* this is NOT set by parse_type; it will be handled by types.c */ + UInteger n; /* this is NOT set by parse_type; it will be handled by types.c */ struct Expression *n_expr; }; } arr; @@ -86,8 +86,8 @@ typedef struct Expression { ExprKind kind; Type type; union { - FloatLiteral floatl; - IntLiteral intl; + Floating floatl; + UInteger intl; StrLiteral strl; struct { UnaryOp op; @@ -145,14 +145,35 @@ typedef struct { Block *block; /* which block are we in? NULL = file scope */ } Parser; -/* - allocate a new expression. - IMPORTANT: This invalidates all other parser-allocated Expression pointers. -*/ -static Expression *parser_new_expr(Parser *p) { - return block_arr_add(&p->exprs); +static bool type_builtin_is_integer(BuiltinType b) { + switch (b) { + case BUILTIN_I8: + case BUILTIN_I16: + case BUILTIN_I32: + case BUILTIN_I64: + case BUILTIN_U8: + case BUILTIN_U16: + case BUILTIN_U32: + case BUILTIN_U64: + return true; + default: return false; + } } +static bool type_builtin_is_floating(BuiltinType b) { + switch (b) { + case BUILTIN_FLOAT: + case BUILTIN_DOUBLE: + return true; + default: return false; + } +} + +static bool type_builtin_is_numerical(BuiltinType b) { + return type_builtin_is_integer(b) || type_builtin_is_floating(b); +} + + /* returns BUILTIN_TYPE_COUNT on failure */ static BuiltinType kw_to_builtin_type(Keyword kw) { switch (kw) { @@ -189,7 +210,58 @@ static Keyword builtin_type_to_kw(BuiltinType t) { return KW_COUNT; } +/* returns the number of characters written, not including the null character */ +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(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 = t->fn.types.data; + Type *param_types = ret_type + 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, ", "); + written += type_to_str(¶m_types[i], buffer + written, bufsize - written); + } + written += str_copy(buffer + written, bufsize - written, ")"); + if (ret_type->kind != TYPE_VOID) { + written += str_copy(buffer + written, bufsize - written, " "); + written += type_to_str(ret_type, buffer + written, bufsize - written); + } + return written; + } break; + case TYPE_ARR: { + size_t written = str_copy(buffer, bufsize, "["); + if (t->flags & TYPE_FLAG_RESOLVED) { + snprintf(buffer + written, bufsize - written, UINTEGER_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); + return 0; +} +/* + allocate a new expression. + IMPORTANT: This invalidates all other parser-allocated Expression pointers. +*/ +static Expression *parser_new_expr(Parser *p) { + return block_arr_add(&p->exprs); +} #define NOT_AN_OP -1 static int op_precedence(Keyword op) { @@ -905,7 +977,7 @@ static void fprint_type(FILE *out, Type *t) { case TYPE_ARR: fprintf(out, "["); if (t->flags & TYPE_FLAG_RESOLVED) { - fprintf(out, INT_LITERAL_FMT, t->arr.n); + fprintf(out, INTEGER_FMT, t->arr.n); } else { fprint_expr(out, t->arr.n_expr); } @@ -1,5 +1,7 @@ main @= fn() { - foo : [3]fn()fn([42]fn()); - bar : [3]fn([37]fn(int)int); - foo + bar; + N @= 5; + FOO @= 1928; + BAR @= 5; + foo : [N+FOO-3--BAR]int; + bar : [fn(){}]int; }; @@ -8,6 +8,14 @@ #include <limits.h> #include <stdint.h> #include <stdbool.h> + +typedef unsigned long long UInteger; +typedef long long Integer; +typedef long double Floating; /* OPTIM: Switch to double */ +#define INTEGER_MAX INT64_MAX +#define UINTEGER_FMT "%llu" +#define INTEGER_FMT "%lld" + #include "util/err.c" #include "util/arr.c" #include "util/blockarr.c" diff --git a/tokenizer.c b/tokenizer.c index 369f234..a66129d 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -65,10 +65,6 @@ static Keyword tokenize_kw(char **s) { return KW_COUNT; } -typedef unsigned long long IntLiteral; -typedef long double FloatLiteral; /* OPTIM: Switch to double */ -#define INT_LITERAL_FMT "%llu" - typedef enum { NUM_LITERAL_INT, NUM_LITERAL_FLOAT @@ -77,8 +73,8 @@ typedef enum { typedef struct { NumLiteralKind kind; union { - IntLiteral intval; - FloatLiteral floatval; + UInteger intval; + Floating floatval; }; } NumLiteral; @@ -127,7 +123,7 @@ static void token_fprint(FILE *out, Token *t) { fprintf(out, "number: "); switch (t->num.kind) { case NUM_LITERAL_INT: - fprintf(out, INT_LITERAL_FMT, t->num.intval); + fprintf(out, INTEGER_FMT, t->num.intval); break; case NUM_LITERAL_FLOAT: fprintf(out, "%g", (double)t->num.floatval); @@ -289,7 +285,7 @@ static bool tokenize_string(Tokenizer *tokr, char *str) { if (isdigit(*t.s)) { /* it's a numeric literal */ int base = 10; - FloatLiteral decimal_pow10; + Floating decimal_pow10; NumLiteral n; n.kind = NUM_LITERAL_INT; n.intval = 0; @@ -330,14 +326,14 @@ static bool tokenize_string(Tokenizer *tokr, char *str) { } n.kind = NUM_LITERAL_FLOAT; decimal_pow10 = 0.1; - n.floatval = (FloatLiteral)n.intval; + n.floatval = (Floating)n.intval; tokr_nextchar(&t); continue; } else if (*t.s == 'e') { tokr_nextchar(&t); if (n.kind == NUM_LITERAL_INT) { n.kind = NUM_LITERAL_FLOAT; - n.floatval = (FloatLiteral)n.intval; + n.floatval = (Floating)n.intval; } /* TODO: check if exceeding maximum exponent */ int exponent = 0; @@ -385,17 +381,17 @@ static bool tokenize_string(Tokenizer *tokr, char *str) { } switch (n.kind) { case NUM_LITERAL_INT: - if (n.intval > ULLONG_MAX / (IntLiteral)base || - n.intval * (IntLiteral)base > ULLONG_MAX - (IntLiteral)digit) { + if (n.intval > ULLONG_MAX / (UInteger)base || + n.intval * (UInteger)base > ULLONG_MAX - (UInteger)digit) { /* too big! */ tokenization_err(&t, "Number too big to fit in a numeric literal."); goto err; } - n.intval *= (IntLiteral)base; - n.intval += (IntLiteral)digit; + n.intval *= (UInteger)base; + n.intval += (UInteger)digit; break; case NUM_LITERAL_FLOAT: - n.floatval += decimal_pow10 * (FloatLiteral)digit; + n.floatval += decimal_pow10 * (Floating)digit; decimal_pow10 /= 10; break; } @@ -48,78 +48,6 @@ static bool block_exit(Block *b) { return ret; } - -/* returns the number of characters written, not including the null character */ -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(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 = t->fn.types.data; - Type *param_types = ret_type + 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, ", "); - written += type_to_str(¶m_types[i], buffer + written, bufsize - written); - } - written += str_copy(buffer + written, bufsize - written, ")"); - if (ret_type->kind != TYPE_VOID) { - written += str_copy(buffer + written, bufsize - written, " "); - written += type_to_str(ret_type, buffer + written, bufsize - written); - } - 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); - return 0; -} - -static bool type_builtin_is_floating(BuiltinType b) { - switch (b) { - case BUILTIN_FLOAT: - case BUILTIN_DOUBLE: - return true; - default: return false; - } -} - -static bool type_builtin_is_numerical(BuiltinType b) { - switch (b) { - case BUILTIN_FLOAT: - case BUILTIN_DOUBLE: - case BUILTIN_I8: - case BUILTIN_I16: - case BUILTIN_I32: - case BUILTIN_I64: - case BUILTIN_U8: - case BUILTIN_U16: - case BUILTIN_U32: - case BUILTIN_U64: - return true; - default: return false; - } -} - static bool type_eq(Type *a, Type *b) { if (a->kind != b->kind) return false; if (a->flags & TYPE_FLAG_FLEXIBLE) { @@ -310,11 +238,15 @@ static bool type_of_expr(Expression *e, Type *t) { static bool type_resolve(Type *t) { if (t->flags & TYPE_FLAG_RESOLVED) return true; switch (t->kind) { - case TYPE_ARR: + 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; + Integer size; + if (!eval_expr_as_int(t->arr.n_expr, &size)) return false; /* resolve N */ + if (size < 0) + err_print(t->arr.n_expr->where, "Negative array length (" INTEGER_FMT ")", size); + t->arr.n = (UInteger)size; + } break; case TYPE_FN: arr_foreach(&t->fn.types, Type, child_type) { if (!type_resolve(child_type)) @@ -72,13 +72,17 @@ static void err_vprint(Location where, const char *fmt, va_list args) { err_print_footer_(where.code); } -static void err_print(Location where, const char *fmt, ...) { - va_list args; +static void err_print_(int line, const char *file, Location where, const char *fmt, ...) { + va_list args; + if (file) + err_fprint("Generated by line %d of %s:\n", line, file); va_start(args, fmt); err_vprint(where, fmt, args); va_end(args); } +#define err_print(...) err_print_(__LINE__, __FILE__, __VA_ARGS__) + static void info_print(Location where, const char *fmt, ...) { va_list args; va_start(args, fmt); |