summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c5
-rw-r--r--eval.c94
-rw-r--r--out.c6
-rw-r--r--parse.c92
-rw-r--r--test.toc8
-rw-r--r--toc.c8
-rw-r--r--tokenizer.c26
-rw-r--r--types.c82
-rw-r--r--util/err.c8
9 files changed, 209 insertions, 120 deletions
diff --git a/cgen.c b/cgen.c
index 2509611..2802886 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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) {
diff --git a/eval.c b/eval.c
index 8cb3303..d8402c6 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
diff --git a/out.c b/out.c
index 9b84632..19ee285 100644
--- a/out.c
+++ b/out.c
@@ -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) {
diff --git a/parse.c b/parse.c
index 694c9b2..afb36ef 100644
--- a/parse.c
+++ b/parse.c
@@ -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(&param_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);
}
diff --git a/test.toc b/test.toc
index 5db00b7..6dc6678 100644
--- a/test.toc
+++ b/test.toc
@@ -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;
};
diff --git a/toc.c b/toc.c
index 3309563..fb9864c 100644
--- a/toc.c
+++ b/toc.c
@@ -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;
}
diff --git a/types.c b/types.c
index 2bfbb6f..50815ac 100644
--- a/types.c
+++ b/types.c
@@ -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(&param_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))
diff --git a/util/err.c b/util/err.c
index 0bd6424..5ff28ad 100644
--- a/util/err.c
+++ b/util/err.c
@@ -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);