summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-08-27 14:38:15 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-08-27 14:38:15 -0400
commit126c496ad8a6e9a3b90ecd25c8ff3ead630f7f65 (patch)
treee4bccdc0652e1c72d756bdb03e2a7e30b6119b84
parentb40f9a3fe9f648f685649f65977ad595c998cbb7 (diff)
checked undeclared identifiers; not totally done yet
-rw-r--r--base_cgen.c58
-rwxr-xr-xbuild.sh3
-rw-r--r--cgen.c30
-rw-r--r--identifiers.c17
-rw-r--r--out.c9
-rw-r--r--out.h3
-rw-r--r--parse.c3
-rw-r--r--test.toc5
-rw-r--r--types_cgen.c4
9 files changed, 90 insertions, 42 deletions
diff --git a/base_cgen.c b/base_cgen.c
index e59e84c..a247e7c 100644
--- a/base_cgen.c
+++ b/base_cgen.c
@@ -25,12 +25,16 @@ static FILE *cgen_writing_to(CGenerator *g) {
return NULL;
}
-static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) {
+static void cgen_indent(CGenerator *g) {
if (g->indent_next) {
for (int i = 0; i < g->indent_level; i++)
fprintf(cgen_writing_to(g), "\t");
g->indent_next = false;
}
+}
+
+static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) {
+ cgen_indent(g);
vfprintf(cgen_writing_to(g), fmt, args);
}
@@ -91,8 +95,36 @@ static void cgen_create(CGenerator *g, FILE *c_out, FILE *h_out, const char *h_f
cgen_writeln(g, ""); /* extra newline between includes and code */
}
-static void cgen_ident(CGenerator *g, Identifier i) {
+
+/* Pass NULL for where if you don't want to check if it's declared */
+static bool cgen_fn_name(CGenerator *g, FnExpr *f, Location *where);
+static bool cgen_ident(CGenerator *g, Identifier i, Location *where) {
+ if (where) {
+ IdentDecl *id_decl = ident_decl(i);
+ if (!id_decl) {
+ err_print(*where, "Identifier undeclared: %s", ident_to_str(i));
+ return false;
+ }
+ Declaration *decl = id_decl->decl;
+ if (decl->expr.kind == EXPR_FN) {
+ cgen_fn_name(g, &decl->expr.fn, NULL);
+ return true;
+ }
+ if (decl->where.line == where->line) {
+ /* e.g. x: int = x; */
+ err_print(*where, "Use of identifier \"%s\" in its own declaration.", ident_to_str(i));
+ return false;
+ } else if (decl->where.line > where->line) {
+ /* x used before declared */
+ char *str = ident_to_str(i);
+ err_print(*where, "Use of identifier \"%s\" before its declaration.", str);
+ info_print(decl->where, "%s will be declared here.", str);
+ return false;
+ }
+ }
+ cgen_indent(g);
fprint_ident(cgen_writing_to(g), i);
+ return true;
}
static const char *builtin_type_to_str(BuiltinType b) {
@@ -158,28 +190,28 @@ static bool cgen_type_post(CGenerator *g, Type *t) {
return true;
}
-static void cgen_fn_name(CGenerator *g, FnExpr *f) {
- if (f->name)
- cgen_ident(g, f->name);
- else
+static bool cgen_fn_name(CGenerator *g, FnExpr *f, Location *where) {
+ if (f->name) {
+ if (ident_eq_str(f->name, "main"))
+ cgen_write(g, "main__");
+ else
+ return cgen_ident(g, f->name, where);
+ } else {
cgen_write(g, "a___");
+ }
if (f->id != 0)
cgen_write(g, "%lu", f->id);
+ return true;
}
static bool cgen_fn_header(CGenerator *g, FnExpr *f) {
CGenWritingTo writing_to_before = g->writing_to;
- if (ident_eq_str(f->name, "main")) {
- /* don't use actual main function */
- cgen_write(g, "void main__(void)");
- return true;
- }
if (!f->name || g->block != NULL) {
cgen_write(g, "static "); /* anonymous functions only exist in this translation unit */
}
if (!cgen_type_pre(g, &f->ret_type)) return false;
- cgen_fn_name(g, f);
+ cgen_fn_name(g, f, NULL);
if (!cgen_type_post(g, &f->ret_type)) return false;
cgen_write(g, "(");
arr_foreach(&f->params, Param, p) {
@@ -189,7 +221,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f) {
}
if (!cgen_type_pre(g, &p->type))
return false;
- cgen_ident(g, p->name);
+ cgen_ident(g, p->name, NULL);
if (!cgen_type_post(g, &p->type))
return false;
}
diff --git a/build.sh b/build.sh
index d42acc5..3c967db 100755
--- a/build.sh
+++ b/build.sh
@@ -1,2 +1,3 @@
#!/bin/bash
-gcc -o toc main.c -O0 -g -o toc -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wno-unused-function -Wno-unused-parameter -std=c11 || exit 1
+CC=gcc
+$CC -o toc main.c -O0 -g -Wall -Wextra -Wpedantic -Wconversion -Wshadow -Wno-unused-function -Wno-unused-parameter -std=c11 || exit 1
diff --git a/cgen.c b/cgen.c
index d0bf0a6..e40ba1c 100644
--- a/cgen.c
+++ b/cgen.c
@@ -17,12 +17,11 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "\"");
break;
case EXPR_IDENT:
- /* TODO: check if declared */
- cgen_ident(g, e->ident);
+ if (!cgen_ident(g, e->ident, &e->where)) return false;
break;
case EXPR_BINARY_OP:
cgen_write(g, "(");
- cgen_expr(g, e->binary.lhs);
+ if (!cgen_expr(g, e->binary.lhs)) return false;
switch (e->binary.op) {
case BINARY_PLUS:
cgen_write(g, "+");
@@ -31,7 +30,7 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "-");
break;
}
- cgen_expr(g, e->binary.rhs);
+ if (!cgen_expr(g, e->binary.rhs)) return false;
cgen_write(g, ")");
break;
case EXPR_UNARY_OP:
@@ -41,21 +40,21 @@ static bool cgen_expr(CGenerator *g, Expression *e) {
cgen_write(g, "-");
break;
}
- cgen_expr(g, e->unary.of);
+ if (!cgen_expr(g, e->unary.of)) return false;
cgen_write(g, ")");
break;
case EXPR_FN:
- cgen_fn_name(g, &e->fn);
+ if (!cgen_fn_name(g, &e->fn, &e->where)) return false;
break;
case EXPR_CALL:
- cgen_expr(g, e->call.fn);
+ if (!cgen_expr(g, e->call.fn)) return false;
cgen_write(g, "(");
arr_foreach(&e->call.args, Expression, arg) {
if (arg != e->call.args.data) {
cgen_write(g, ",");
cgen_write_space(g);
}
- cgen_expr(g, arg);
+ if (!cgen_expr(g, arg)) return false;
}
cgen_write(g, ")");
break;
@@ -87,12 +86,14 @@ static bool cgen_fn(CGenerator *g, FnExpr *f) {
static bool cgen_decl(CGenerator *g, Declaration *d) {
arr_foreach(&d->idents, Identifier, ident) {
cgen_type_pre(g, &d->type);
- cgen_ident(g, *ident);
+ cgen_ident(g, *ident, NULL);
cgen_type_post(g, &d->type);
cgen_write_space(g);
cgen_write(g, "=");
cgen_write_space(g);
- cgen_expr(g, &d->expr);
+ if (!cgen_expr(g, &d->expr)) {
+ return false;
+ }
cgen_write(g, "; ");
}
cgen_writeln(g, "");
@@ -123,11 +124,12 @@ static bool cgen_fns_in_stmt(CGenerator *g, Statement *s);
static bool cgen_fns_in_expr(CGenerator *g, Expression *e) {
switch (e->kind) {
case EXPR_FN:
- cgen_fn(g, &e->fn);
+ if (!cgen_fn(g, &e->fn)) return false;
+ bool ret = true;
arr_foreach(&e->fn.body.stmts, Statement, stmt) {
- cgen_fns_in_stmt(g, stmt);
+ ret = ret && cgen_fns_in_stmt(g, stmt);
}
- return true;
+ return ret;
case EXPR_CALL:
return cgen_fns_in_expr(g, e->call.fn);
default: return true;
@@ -146,7 +148,7 @@ static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) {
case STMT_DECL: {
Declaration *d = &s->decl;
if (d->flags & DECL_FLAG_HAS_EXPR)
- cgen_fns_in_expr(g, &d->expr);
+ return cgen_fns_in_expr(g, &d->expr);
} break;
}
return true;
diff --git a/identifiers.c b/identifiers.c
index ca6050f..ebf3f0d 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -13,6 +13,7 @@ typedef struct IdentTree {
Array decls; /* array of declarations of this identifier */
unsigned long c_fn_reps; /* number of repetitions of this identifier in the C output--only used for functions */
size_t depth;
+ struct Type *type;
} IdentTree;
typedef IdentTree *Identifier;
@@ -90,6 +91,22 @@ static bool ident_eq_str(Identifier i, const char *s) {
return true;
}
+static char *ident_to_str(Identifier i) {
+ char *str = malloc(i->depth + 1);
+ str += i->depth;
+ *str = 0;
+ while (i->parent != NULL) {
+ str--;
+ *str = identifier_chars[i - i->parent->children];
+ i = i->parent;
+ }
+ return str;
+}
+
+static IdentDecl *ident_decl(Identifier i) {
+ return (IdentDecl*)i->decls.last;
+}
+
static void idents_free_tree(IdentTree *tree) {
if (!tree->children) return;
for (int i = 0; i < NIDENTIFIER_CHARS; i++)
diff --git a/out.c b/out.c
index 767e654..0d58e0e 100644
--- a/out.c
+++ b/out.c
@@ -1,12 +1,7 @@
#include "out.h"
/* toc */
-void main__(void) {
- int64_t foo = 3;
- void (*bar)() = 0;
+void main__() {
}
-
-int main(void) {
- main__();
- return 0;
+void foo() {
}
diff --git a/out.h b/out.h
index 4cc08ee..a1fb857 100644
--- a/out.h
+++ b/out.h
@@ -1,2 +1,3 @@
#include <stdint.h>
-void main__(void);
+void main__();
+static void foo();
diff --git a/parse.c b/parse.c
index 4972cb9..c4d8588 100644
--- a/parse.c
+++ b/parse.c
@@ -21,7 +21,7 @@ typedef enum {
} BuiltinType;
-typedef struct {
+typedef struct Type {
Location where;
TypeKind kind;
union {
@@ -275,7 +275,6 @@ static bool parse_block(Parser *p, Block *b) {
Statement *stmt = arr_add(&b->stmts);
if (!parse_stmt(p, stmt)) {
ret = false;
- continue;
}
if (token_is_kw(t->token, KW_RBRACE)) break;
if (t->token->kind == TOKEN_EOF) {
diff --git a/test.toc b/test.toc
index d437110..935bd1e 100644
--- a/test.toc
+++ b/test.toc
@@ -1,4 +1,5 @@
main @= fn() {
- foo : int = 3;
- bar : fn() = 0;
+
+ foo @ int = fn() {foo();};
+
}; \ No newline at end of file
diff --git a/types_cgen.c b/types_cgen.c
index 0eaa4b3..541f1b5 100644
--- a/types_cgen.c
+++ b/types_cgen.c
@@ -1,5 +1,5 @@
static bool cgen_types_stmt(CGenerator *g, Statement *s);
-static bool cgen_types_fn(CGenerator *g, FnExpr *f) {
+static bool cgen_types_fn(CGenerator *g, FnExpr *f, Location where) {
bool ret = true;
/* assign an ID to the function */
if (f->name) {
@@ -27,7 +27,7 @@ static bool cgen_types_expr(CGenerator *g, Expression *e) {
if (e->fn.name && g->block == NULL) { /* write named function prototypes in global scope to header file */
g->writing_to = CGEN_WRITING_TO_H;
}
- if (!cgen_types_fn(g, &e->fn))
+ if (!cgen_types_fn(g, &e->fn, e->where))
return false;
g->writing_to = CGEN_WRITING_TO_C;
} break;