diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-08-27 14:38:15 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-08-27 14:38:15 -0400 |
commit | 126c496ad8a6e9a3b90ecd25c8ff3ead630f7f65 (patch) | |
tree | e4bccdc0652e1c72d756bdb03e2a7e30b6119b84 | |
parent | b40f9a3fe9f648f685649f65977ad595c998cbb7 (diff) |
checked undeclared identifiers; not totally done yet
-rw-r--r-- | base_cgen.c | 58 | ||||
-rwxr-xr-x | build.sh | 3 | ||||
-rw-r--r-- | cgen.c | 30 | ||||
-rw-r--r-- | identifiers.c | 17 | ||||
-rw-r--r-- | out.c | 9 | ||||
-rw-r--r-- | out.h | 3 | ||||
-rw-r--r-- | parse.c | 3 | ||||
-rw-r--r-- | test.toc | 5 | ||||
-rw-r--r-- | types_cgen.c | 4 |
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; } @@ -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 @@ -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++) @@ -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() { } @@ -1,2 +1,3 @@ #include <stdint.h> -void main__(void); +void main__(); +static void foo(); @@ -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) { @@ -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; |