From e618017e787f704db8da7ce075dcb20fc8502e2b Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Sat, 13 Jun 2020 13:36:39 -0700 Subject: [PATCH] ainedit: support parsing .jaf functions --- include/system4/ain.h | 1 + src/ain.c | 7 + src/tools/ainedit/jaf.h | 125 +++++++++++--- src/tools/ainedit/jaf_ast.c | 295 +++++++++++++++++++++++++++++--- src/tools/ainedit/jaf_compile.c | 289 ++++++++++++++++++++++++++----- src/tools/ainedit/jaf_lexer.l | 2 - src/tools/ainedit/jaf_parser.y | 116 +++++++------ src/tools/ainedit/jaf_types.c | 8 +- 8 files changed, 692 insertions(+), 151 deletions(-) diff --git a/include/system4/ain.h b/include/system4/ain.h index 51cd589..90d5d6e 100644 --- a/include/system4/ain.h +++ b/include/system4/ain.h @@ -326,6 +326,7 @@ int ain_get_struct_no(struct ain *ain, char *name); int ain_add_struct(struct ain *ain, char *name); struct ain_variable *ain_add_global(struct ain *ain, char *name); void ain_add_initval(struct ain *ain, struct ain_initval *init); +int ain_add_function(struct ain *ain, struct ain_function *fun); void ain_free(struct ain *ain); void ain_free_functions(struct ain *ain); diff --git a/src/ain.c b/src/ain.c index d7e799d..eae1c06 100644 --- a/src/ain.c +++ b/src/ain.c @@ -223,6 +223,13 @@ void ain_add_initval(struct ain *ain, struct ain_initval *init) ain->global_initvals[ain->nr_initvals++] = *init; } +int ain_add_function(struct ain *ain, struct ain_function *fun) +{ + ain->functions = xrealloc_array(ain->functions, ain->nr_functions, ain->nr_functions+1, sizeof (struct ain_function)); + ain->functions[ain->nr_functions++] = *fun; + return ain->nr_functions - 1; +} + static const char *errtab[AIN_MAX_ERROR] = { [AIN_SUCCESS] = "Success", [AIN_FILE_ERROR] = "Error opening AIN file", diff --git a/src/tools/ainedit/jaf.h b/src/tools/ainedit/jaf.h index 1c9d1f0..2c89f7e 100644 --- a/src/tools/ainedit/jaf.h +++ b/src/tools/ainedit/jaf.h @@ -14,8 +14,8 @@ * along with this program; if not, see . */ -#ifndef AINEDIT_JAF_AST_H -#define AINEDIT_JAF_AST_H +#ifndef AINEDIT_JAF_H +#define AINEDIT_JAF_H #include #include @@ -120,7 +120,7 @@ struct jaf_type_specifier { enum jaf_type type; unsigned qualifiers; struct string *name; - struct jaf_declaration_list *def; + struct jaf_block *def; int struct_no; }; @@ -136,24 +136,89 @@ struct jaf_declarator_list { struct jaf_declarator **decls; }; -struct jaf_function { - // TODO +struct jaf_function_declarator { + struct string *name; + struct jaf_block *params; +}; + +enum block_item_kind { + JAF_DECLARATION, + JAF_FUNCTION, + JAF_STMT_LABELED, + JAF_STMT_COMPOUND, + JAF_STMT_EXPRESSION, + JAF_STMT_IF, + JAF_STMT_SWITCH, + JAF_STMT_WHILE, + JAF_STMT_DO_WHILE, + JAF_STMT_FOR, + JAF_STMT_GOTO, + JAF_STMT_CONTINUE, + JAF_STMT_BREAK, + JAF_STMT_RETURN, + JAF_STMT_CASE, + JAF_STMT_DEFAULT }; struct jaf_declaration { - bool function; struct string *name; struct jaf_type_specifier *type; size_t array_rank; size_t *array_dims; - struct jaf_expression *init; - struct jaf_function *fun; - int var_no; + union { + struct { + struct jaf_expression *init; + int var_no; + }; + struct { + struct jaf_block *params; + struct jaf_block *body; + int func_no; + }; + }; }; -struct jaf_declaration_list { - size_t nr_decls; - struct jaf_declaration **decls; +// declaration or statement +struct jaf_block_item { + enum block_item_kind kind; + union { + struct jaf_declaration decl; + struct { + struct string *name; + struct jaf_block_item *stmt; + } label; + struct { + struct jaf_expression *expr; + struct jaf_block_item *stmt; + } swi_case; + struct jaf_block *block; + struct jaf_expression *expr; + struct { + struct jaf_expression *test; + struct jaf_block_item *consequent; + struct jaf_block_item *alternative; + } cond; + struct { + struct jaf_expression *expr; + struct jaf_block *body; + } swi; + struct { + struct jaf_expression *test; + struct jaf_block_item *body; + } while_loop; + struct { + struct jaf_block *init; + struct jaf_expression *test; + struct jaf_expression *after; + struct jaf_block_item *body; + } for_loop; + struct string *target; // goto + }; +}; + +struct jaf_block { + size_t nr_items; + struct jaf_block_item **items; }; struct jaf_expression *jaf_integer(struct string *text); @@ -166,29 +231,49 @@ struct jaf_expression *jaf_ternary_expr(struct jaf_expression *test, struct jaf_ struct jaf_expression *jaf_seq_expr(struct jaf_expression *head, struct jaf_expression *tail); struct jaf_type_specifier *jaf_type(enum jaf_type type); -struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_declaration_list *fields); +struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_block *fields); struct jaf_type_specifier *jaf_typedef(struct string *name); struct jaf_declarator *jaf_declarator(struct string *name); struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, struct jaf_declarator *tail); -struct jaf_declaration_list *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators); -struct jaf_declaration_list *jaf_type_declaration(struct jaf_type_specifier *type); -struct jaf_declaration_list *jaf_declarations(struct jaf_declaration_list *head, struct jaf_declaration_list *tail); +struct jaf_block *jaf_parameter(struct jaf_type_specifier *type, struct jaf_declarator *declarator); +struct jaf_function_declarator *jaf_function_declarator(struct string *name, struct jaf_block *params); +struct jaf_block *jaf_function(struct jaf_type_specifier *type, struct jaf_function_declarator *decl, struct jaf_block *body); + +struct jaf_block *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators); +struct jaf_block *jaf_type_declaration(struct jaf_type_specifier *type); +struct jaf_block *jaf_merge_blocks(struct jaf_block *head, struct jaf_block *tail); + +struct jaf_block *jaf_block(struct jaf_block_item *item); +struct jaf_block_item *jaf_compound_statement(struct jaf_block *block); +struct jaf_block_item *jaf_label_statement(struct string *label, struct jaf_block_item *stmt); +struct jaf_block_item *jaf_case_statement(struct jaf_expression *expr, struct jaf_block_item *stmt); +struct jaf_block_item *jaf_expression_statement(struct jaf_expression *expr); +struct jaf_block_item *jaf_if_statement(struct jaf_expression *test, struct jaf_block_item *cons, struct jaf_block_item *alt); +struct jaf_block_item *jaf_switch_statement(struct jaf_expression *expr, struct jaf_block *body); +struct jaf_block_item *jaf_while_loop(struct jaf_expression *test, struct jaf_block_item *body); +struct jaf_block_item *jaf_do_while_loop(struct jaf_expression *test, struct jaf_block_item *body); +struct jaf_block_item *jaf_for_loop(struct jaf_block *init, struct jaf_block_item *test, struct jaf_expression *after, struct jaf_block_item *body); +struct jaf_block_item *jaf_goto(struct string *target); +struct jaf_block_item *jaf_continue(void); +struct jaf_block_item *jaf_break(void); +struct jaf_block_item *jaf_return(struct jaf_expression *expr); void jaf_free_expr(struct jaf_expression *expr); +void jaf_free_block(struct jaf_block *block); // jaf_compile.c struct ain *jaf_ain_out; -struct jaf_declaration_list *jaf_toplevel; +struct jaf_block *jaf_toplevel; void jaf_compile(struct ain *out, const char *path); void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type); // jaf_eval.c struct jaf_expression *jaf_simplify(struct jaf_expression *in); -struct jaf_expression *jaf_compute_constexpr(struct jaf_expression *in); // jaf_types.c -void jaf_check_types(struct jaf_expression *expr, struct jaf_type_specifier *type); +void jaf_derive_types(struct jaf_expression *expr); +void jaf_check_type(struct jaf_expression *expr, struct jaf_type_specifier *type); -#endif /* AINEDIT_JAF_AST_H */ +#endif /* AINEDIT_JAF_H */ diff --git a/src/tools/ainedit/jaf_ast.c b/src/tools/ainedit/jaf_ast.c index 7816192..ff26dd1 100644 --- a/src/tools/ainedit/jaf_ast.c +++ b/src/tools/ainedit/jaf_ast.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "system4.h" #include "system4/string.h" #include "jaf.h" @@ -104,7 +105,7 @@ struct jaf_type_specifier *jaf_type(enum jaf_type type) return p; } -struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_declaration_list *fields) +struct jaf_type_specifier *jaf_struct(struct string *name, struct jaf_block *fields) { struct jaf_type_specifier *p = jaf_type(JAF_STRUCT); p->name = name; @@ -137,55 +138,211 @@ struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, st return head; } -struct jaf_declaration_list *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators) +static void init_declaration(struct jaf_type_specifier *type, struct jaf_block_item *dst, struct jaf_declarator *src) { - struct jaf_declaration_list *decls = xcalloc(1, sizeof(struct jaf_declaration_list)); - decls->nr_decls = declarators->nr_decls; - decls->decls = xcalloc(declarators->nr_decls, sizeof(struct jaf_declaration*)); - for (size_t i = 0; i < declarators->nr_decls; i++) { - struct jaf_declaration *decl = xcalloc(1, sizeof(struct jaf_declaration)); - decl->function = false; - decl->name = declarators->decls[i]->name; - decl->type = type; - decl->init = declarators->decls[i]->init; - decls->decls[i] = decl; + dst->kind = JAF_DECLARATION; + dst->decl.name = src->name; + dst->decl.type = type; + dst->decl.init = src->init; + free(src); +} - free(declarators->decls[i]); +struct jaf_block *jaf_parameter(struct jaf_type_specifier *type, struct jaf_declarator *declarator) +{ + struct jaf_block *p = xmalloc(sizeof(struct jaf_block)); + p->nr_items = 1; + p->items = xmalloc(sizeof(struct jaf_block_item*)); + p->items[0] = xcalloc(1, sizeof(struct jaf_block_item)); + init_declaration(type, p->items[0], declarator); + return p; +} + +struct jaf_function_declarator *jaf_function_declarator(struct string *name, struct jaf_block *params) +{ + struct jaf_function_declarator *decl = xmalloc(sizeof(struct jaf_function_declarator)); + decl->name = name; + decl->params = params; + return decl; +} + +struct jaf_block *jaf_function(struct jaf_type_specifier *type, struct jaf_function_declarator *decl, struct jaf_block *body) +{ + struct jaf_block *p = xmalloc(sizeof(struct jaf_block)); + p->nr_items = 1; + p->items = xmalloc(sizeof(struct jaf_block_item*)); + p->items[0] = xcalloc(1, sizeof(struct jaf_block_item)); + p->items[0]->kind = JAF_FUNCTION; + p->items[0]->decl.type = type; + p->items[0]->decl.name = decl->name; + p->items[0]->decl.params = decl->params; + p->items[0]->decl.body = body; + free(decl); + return p; +} + +struct jaf_block *jaf_declaration(struct jaf_type_specifier *type, struct jaf_declarator_list *declarators) +{ + struct jaf_block *decls = xcalloc(1, sizeof(struct jaf_block)); + decls->nr_items = declarators->nr_decls; + decls->items = xcalloc(declarators->nr_decls, sizeof(struct jaf_block_item*)); + for (size_t i = 0; i < declarators->nr_decls; i++) { + decls->items[i] = xcalloc(1, sizeof(struct jaf_block_item)); + init_declaration(type, decls->items[i], declarators->decls[i]); } + free(declarators->decls); free(declarators); return decls; } -struct jaf_declaration_list *jaf_type_declaration(struct jaf_type_specifier *type) +struct jaf_block *jaf_type_declaration(struct jaf_type_specifier *type) { - struct jaf_declaration_list *decls = xcalloc(1, sizeof(struct jaf_declaration_list)); - decls->nr_decls = 1; - decls->decls = xcalloc(1, sizeof(struct jaf_declaration*)); - decls->decls[0] = xcalloc(1, sizeof(struct jaf_declaration)); - decls->decls[0]->type = type; + struct jaf_block *decls = xcalloc(1, sizeof(struct jaf_block)); + decls->nr_items = 1; + decls->items = xcalloc(1, sizeof(struct jaf_block_item*)); + decls->items[0] = xcalloc(1, sizeof(struct jaf_block_item)); + decls->items[0]->kind = JAF_DECLARATION; + decls->items[0]->decl.type = type; return decls; } - -struct jaf_declaration_list *jaf_declarations(struct jaf_declaration_list *head, struct jaf_declaration_list *tail) +struct jaf_block *jaf_merge_blocks(struct jaf_block *head, struct jaf_block *tail) { if (!head) return tail; - size_t nr_decls = head->nr_decls + tail->nr_decls; - head->decls = xrealloc_array(head->decls, head->nr_decls, nr_decls, sizeof(struct jaf_toplevel_decl*)); + size_t nr_decls = head->nr_items + tail->nr_items; + head->items = xrealloc_array(head->items, head->nr_items, nr_decls, sizeof(struct jaf_toplevel_decl*)); - for (size_t i = 0; i < tail->nr_decls; i++) { - head->decls[head->nr_decls+i] = tail->decls[i]; + for (size_t i = 0; i < tail->nr_items; i++) { + head->items[head->nr_items+i] = tail->items[i]; } - head->nr_decls = nr_decls; + head->nr_items = nr_decls; + free(tail->items); free(tail); return head; } +struct jaf_block *jaf_block(struct jaf_block_item *item) +{ + struct jaf_block *block = xcalloc(1, sizeof(struct jaf_block)); + if (!item) + return block; + block->items = xmalloc(sizeof(struct jaf_block_item*)); + block->items[0] = item; + block->nr_items = 1; + return block; +} + +static struct jaf_block_item *block_item(enum block_item_kind kind) +{ + struct jaf_block_item *item = xcalloc(1, sizeof(struct jaf_block_item)); + item->kind = kind; + return item; +} + +struct jaf_block_item *jaf_compound_statement(struct jaf_block *block) +{ + struct jaf_block_item *item = block_item(JAF_STMT_COMPOUND); + item->block = block; + return item; +} + +struct jaf_block_item *jaf_label_statement(struct string *label, struct jaf_block_item *stmt) +{ + struct jaf_block_item *item = block_item(JAF_STMT_LABELED); + item->label.name = label; + item->label.stmt = stmt; + return item; +} + +struct jaf_block_item *jaf_case_statement(struct jaf_expression *expr, struct jaf_block_item *stmt) +{ + struct jaf_block_item *item = block_item(expr ? JAF_STMT_CASE : JAF_STMT_DEFAULT); + item->swi_case.expr = expr; + item->swi_case.stmt = stmt; + return item; +} + +struct jaf_block_item *jaf_expression_statement(struct jaf_expression *expr) +{ + struct jaf_block_item *item = block_item(JAF_STMT_EXPRESSION); + item->expr = expr; + return item; +} + +struct jaf_block_item *jaf_if_statement(struct jaf_expression *test, struct jaf_block_item *cons, struct jaf_block_item *alt) +{ + struct jaf_block_item *item = block_item(JAF_STMT_IF); + item->cond.test = test; + item->cond.consequent = cons; + item->cond.alternative = alt; + return item; +} + +struct jaf_block_item *jaf_switch_statement(struct jaf_expression *expr, struct jaf_block *body) +{ + struct jaf_block_item *item = block_item(JAF_STMT_SWITCH); + item->swi.expr = expr; + item->swi.body = body; + return item; +} + +struct jaf_block_item *jaf_while_loop(struct jaf_expression *test, struct jaf_block_item *body) +{ + struct jaf_block_item *item = block_item(JAF_STMT_WHILE); + item->while_loop.test = test; + item->while_loop.body = body; + return item; +} + +struct jaf_block_item *jaf_do_while_loop(struct jaf_expression *test, struct jaf_block_item *body) +{ + struct jaf_block_item *item = block_item(JAF_STMT_DO_WHILE); + item->while_loop.test = test; + item->while_loop.body = body; + return item; +} + +struct jaf_block_item *jaf_for_loop(struct jaf_block *init, struct jaf_block_item *test, struct jaf_expression *after, struct jaf_block_item *body) +{ + assert(test->kind == JAF_STMT_EXPRESSION); + struct jaf_block_item *item = block_item(JAF_STMT_FOR); + item->for_loop.init = init; + item->for_loop.test = test->expr; + item->for_loop.after = after; + item->for_loop.body = body; + return item; +} + +struct jaf_block_item *jaf_goto(struct string *target) +{ + struct jaf_block_item *item = block_item(JAF_STMT_GOTO); + item->target = target; + return item; +} + +struct jaf_block_item *jaf_continue(void) +{ + return block_item(JAF_STMT_CONTINUE); +} + +struct jaf_block_item *jaf_break(void) +{ + return block_item(JAF_STMT_BREAK); +} + +struct jaf_block_item *jaf_return(struct jaf_expression *expr) +{ + struct jaf_block_item *item = block_item(JAF_STMT_RETURN); + item->expr = expr; + return item; +} + void jaf_free_expr(struct jaf_expression *expr) { + if (!expr) + return; if (expr->type == JAF_EXP_UNARY) { jaf_free_expr(expr->expr); } else if (expr->type == JAF_EXP_BINARY) { @@ -198,3 +355,89 @@ void jaf_free_expr(struct jaf_expression *expr) } free(expr); } + +void jaf_free_type_specifier(struct jaf_type_specifier *type) +{ + if (!type) + return; + if (type->name) + free_string(type->name); + jaf_free_block(type->def); + free(type); +} + +void jaf_free_block_item(struct jaf_block_item *item) +{ + if (!item) + return; + + switch (item->kind) { + case JAF_DECLARATION: + if (item->decl.name) + free_string(item->decl.name); + jaf_free_type_specifier(item->decl.type); + jaf_free_expr(item->decl.init); + break; + case JAF_FUNCTION: + if (item->decl.name) + free_string(item->decl.name); + jaf_free_type_specifier(item->decl.type); + jaf_free_block(item->decl.params); + jaf_free_block(item->decl.body); + break; + case JAF_STMT_LABELED: + free_string(item->label.name); + jaf_free_block_item(item->label.stmt); + break; + case JAF_STMT_COMPOUND: + jaf_free_block(item->block); + break; + case JAF_STMT_EXPRESSION: + jaf_free_expr(item->expr); + break; + case JAF_STMT_IF: + jaf_free_expr(item->cond.test); + jaf_free_block_item(item->cond.consequent); + jaf_free_block_item(item->cond.alternative); + break; + case JAF_STMT_SWITCH: + ERROR("switch not supported"); + break; + case JAF_STMT_WHILE: + case JAF_STMT_DO_WHILE: + jaf_free_expr(item->while_loop.test); + jaf_free_block_item(item->while_loop.body); + break; + case JAF_STMT_FOR: + jaf_free_block(item->for_loop.init); + jaf_free_expr(item->for_loop.test); + jaf_free_expr(item->for_loop.after); + jaf_free_block_item(item->for_loop.body); + break; + case JAF_STMT_GOTO: + free_string(item->target); + case JAF_STMT_CONTINUE: + case JAF_STMT_BREAK: + break; + case JAF_STMT_RETURN: + jaf_free_expr(item->expr); + break; + case JAF_STMT_CASE: + case JAF_STMT_DEFAULT: + jaf_free_expr(item->swi_case.expr); + jaf_free_block_item(item->swi_case.stmt); + break; + } + free(item); +} + +void jaf_free_block(struct jaf_block *block) +{ + if (!block) + return; + for (size_t i = 0; i < block->nr_items; i++) { + jaf_free_block_item(block->items[i]); + } + free(block->items); + free(block); +} diff --git a/src/tools/ainedit/jaf_compile.c b/src/tools/ainedit/jaf_compile.c index 717b418..7d3d45a 100644 --- a/src/tools/ainedit/jaf_compile.c +++ b/src/tools/ainedit/jaf_compile.c @@ -30,7 +30,7 @@ FILE *yyin; int yyparse(void); struct ain *jaf_ain_out; -struct jaf_declaration_list *jaf_toplevel; +struct jaf_block *jaf_toplevel; int sym_type(char *name) { @@ -38,12 +38,13 @@ int sym_type(char *name) struct ain_struct *s = ain_get_struct(jaf_ain_out, u); free(u); - if (s) + if (s) { return TYPEDEF_NAME; + } return IDENTIFIER; } -static void define_types(struct ain *ain, struct jaf_declaration *decl); +static void define_types(struct ain *ain, struct jaf_block_item *decl); void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type) { @@ -58,21 +59,21 @@ void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type) type->struct_no = ain_add_struct(ain, u); free(u); - for (size_t i = 0; i < type->def->nr_decls; i++) { - define_types(ain, type->def->decls[i]); + for (size_t i = 0; i < type->def->nr_items; i++) { + define_types(ain, type->def->items[i]); } } -static void define_types(struct ain *ain, struct jaf_declaration *decl) +static void define_types(struct ain *ain, struct jaf_block_item *decl) { if (!decl) ERROR("DECL IS NULL"); - if (!decl->type) + if (!decl->decl.type) ERROR("TYPE IS NULL"); - if (decl->type->type != JAF_STRUCT) + if (decl->decl.type->type != JAF_STRUCT) return; - jaf_define_struct(ain, decl->type); + jaf_define_struct(ain, decl->decl.type); } static enum ain_data_type jaf_to_ain_data_type(enum jaf_type type) @@ -130,16 +131,88 @@ static void jaf_to_initval(struct ain_initval *dst, struct jaf_expression *expr) } } -static void analyze_expression(possibly_unused struct ain *ain, struct jaf_expression **expr, struct jaf_type_specifier *type) +static void analyze_expression(possibly_unused struct ain *ain, struct jaf_expression **expr) { - jaf_check_types(*expr, type); + if (!*expr) + return; + jaf_derive_types(*expr); *expr = jaf_simplify(*expr); } -static void resolve_types(struct ain *ain, struct jaf_declaration *decl) +static void analyze_block(struct ain *ain, struct jaf_block *block); + +static void analyze_statement(struct ain *ain, struct jaf_block_item *item) { - if (decl->function) + if (!item) return; + switch (item->kind) { + case JAF_DECLARATION: + if (!item->decl.init) + break; + analyze_expression(ain, &item->decl.init); + jaf_check_type(item->decl.init, item->decl.type); + // add initval to ain object + struct ain_initval init = { .global_index = item->decl.var_no }; + jaf_to_initval(&init, item->decl.init); + ain_add_initval(ain, &init); + break; + case JAF_FUNCTION: + analyze_block(ain, item->decl.body); + break; + case JAF_STMT_LABELED: + analyze_statement(ain, item->label.stmt); + break; + case JAF_STMT_COMPOUND: + analyze_block(ain, item->block); + break; + case JAF_STMT_EXPRESSION: + analyze_expression(ain, &item->expr); + break; + case JAF_STMT_IF: + analyze_expression(ain, &item->cond.test); + analyze_statement(ain, item->cond.consequent); + analyze_statement(ain, item->cond.alternative); + break; + case JAF_STMT_SWITCH: + analyze_expression(ain, &item->swi.expr); + analyze_block(ain, item->swi.body); + break; + case JAF_STMT_WHILE: + case JAF_STMT_DO_WHILE: + analyze_expression(ain, &item->while_loop.test); + analyze_statement(ain, item->while_loop.body); + break; + case JAF_STMT_FOR: + analyze_block(ain, item->for_loop.init); + analyze_expression(ain, &item->for_loop.test); + analyze_expression(ain, &item->for_loop.after); + analyze_statement(ain, item->for_loop.body); + break; + case JAF_STMT_RETURN: + analyze_expression(ain, &item->expr); + break; + case JAF_STMT_CASE: + case JAF_STMT_DEFAULT: + analyze_statement(ain, item->swi_case.stmt); + break; + case JAF_STMT_GOTO: + case JAF_STMT_CONTINUE: + case JAF_STMT_BREAK: + break; + } +} + +static void analyze_block(struct ain *ain, struct jaf_block *block) +{ + for (size_t i = 0; i < block->nr_items; i++) { + analyze_statement(ain, block->items[i]); + } +} + +static void resolve_types(struct ain *ain, struct jaf_block *block); + +static void resolve_decl_types(struct ain *ain, struct jaf_declaration *decl) +{ if (decl->type->type == JAF_TYPEDEF) resolve_typedef(ain, decl->type); if (decl->type->type != JAF_STRUCT || !decl->type->def) @@ -149,20 +222,163 @@ static void resolve_types(struct ain *ain, struct jaf_declaration *decl) assert(decl->type->struct_no < ain->nr_structures); // create struct definition in ain object - struct jaf_declaration_list *def = decl->type->def; - struct ain_variable *members = xcalloc(def->nr_decls, sizeof(struct ain_variable)); - for (size_t i = 0; i < def->nr_decls; i++) { - members[i].name = encode_text_to_input_format(def->decls[i]->name->text); + struct jaf_block *def = decl->type->def; + struct ain_variable *members = xcalloc(def->nr_items, sizeof(struct ain_variable)); + for (size_t i = 0; i < def->nr_items; i++) { + members[i].name = encode_text_to_input_format(def->items[i]->decl.name->text); if (ain->version >= 12) members[i].name2 = strdup(""); - jaf_to_ain_type(ain, &members[i].type, def->decls[i]->type); + jaf_to_ain_type(ain, &members[i].type, def->items[i]->decl.type); } struct ain_struct *s = &ain->structures[decl->type->struct_no]; - s->nr_members = def->nr_decls; + s->nr_members = def->nr_items; s->members = members; } +static void resolve_statement_types(struct ain *ain, struct jaf_block_item *item) +{ + switch (item->kind) { + case JAF_DECLARATION: + resolve_decl_types(ain, &item->decl); + break; + case JAF_FUNCTION: + if (item->decl.params) + resolve_types(ain, item->decl.params); + resolve_types(ain, item->decl.body); + break; + case JAF_STMT_LABELED: + resolve_statement_types(ain, item->label.stmt); + break; + case JAF_STMT_COMPOUND: + resolve_types(ain, item->block); + break; + case JAF_STMT_IF: + resolve_statement_types(ain, item->cond.consequent); + resolve_statement_types(ain, item->cond.alternative); + break; + case JAF_STMT_SWITCH: + resolve_types(ain, item->swi.body); + break; + case JAF_STMT_WHILE: + case JAF_STMT_DO_WHILE: + resolve_statement_types(ain, item->while_loop.body); + break; + case JAF_STMT_FOR: + resolve_types(ain, item->for_loop.init); + resolve_statement_types(ain, item->for_loop.body); + break; + case JAF_STMT_CASE: + case JAF_STMT_DEFAULT: + resolve_statement_types(ain, item->swi_case.stmt); + break; + case JAF_STMT_EXPRESSION: + case JAF_STMT_GOTO: + case JAF_STMT_CONTINUE: + case JAF_STMT_BREAK: + case JAF_STMT_RETURN: + break; + } +} + +static void resolve_types(struct ain *ain, struct jaf_block *block) +{ + for (size_t i = 0; i < block->nr_items; i++) { + resolve_statement_types(ain, block->items[i]); + } +} + +static void init_variable(struct ain *ain, struct ain_variable *var, struct string *name, struct jaf_type_specifier *type) +{ + var->name = encode_text_to_input_format(name->text); + if (ain->version >= 12) + var->name2 = strdup(""); + jaf_to_ain_type(ain, &var->type, type); +} + +static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars); + +static struct ain_variable *block_item_get_vars(struct ain *ain, struct jaf_block_item *item, struct ain_variable *vars, int *nr_vars) +{ + switch (item->kind) { + case JAF_DECLARATION: + if (!item->decl.name) + break; + vars = xrealloc_array(vars, *nr_vars, *nr_vars + 1, sizeof(struct ain_variable)); + init_variable(ain, vars + *nr_vars, item->decl.name, item->decl.type); + (*nr_vars)++; + break; + case JAF_STMT_LABELED: + vars = block_item_get_vars(ain, item->label.stmt, vars, nr_vars); + break; + case JAF_STMT_COMPOUND: + vars = block_get_vars(ain, item->block, vars, nr_vars); + break; + case JAF_STMT_IF: + vars = block_item_get_vars(ain, item->cond.consequent, vars, nr_vars); + vars = block_item_get_vars(ain, item->cond.alternative, vars, nr_vars); + break; + case JAF_STMT_SWITCH: + vars = block_get_vars(ain, item->swi.body, vars, nr_vars); + break; + case JAF_STMT_WHILE: + case JAF_STMT_DO_WHILE: + vars = block_item_get_vars(ain, item->while_loop.body, vars, nr_vars); + break; + case JAF_STMT_FOR: + vars = block_get_vars(ain, item->for_loop.init, vars, nr_vars); + vars = block_item_get_vars(ain, item->for_loop.body, vars, nr_vars); + break; + case JAF_STMT_CASE: + case JAF_STMT_DEFAULT: + vars = block_item_get_vars(ain, item->swi_case.stmt, vars, nr_vars); + break; + + case JAF_STMT_EXPRESSION: + case JAF_STMT_GOTO: + case JAF_STMT_CONTINUE: + case JAF_STMT_BREAK: + case JAF_STMT_RETURN: + break; + + case JAF_FUNCTION: + ERROR("Nested functions not supported"); + } + return vars; +} + +static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *block, struct ain_variable *vars, int *nr_vars) +{ + for (size_t i = 0; i < block->nr_items; i++) { + vars = block_item_get_vars(ain, block->items[i], vars, nr_vars); + } + return vars; +} + +static void function_init_vars(struct ain *ain, struct ain_function *f, struct jaf_declaration *decl) +{ + f->nr_args = decl->params ? decl->params->nr_items : 0; + f->nr_vars = f->nr_args; + f->vars = xcalloc(f->nr_args, sizeof(struct ain_variable)); + for (int i = 0; i < f->nr_args; i++) { + assert(decl->params->items[i]->kind == JAF_DECLARATION); + assert(decl->params->items[i]->decl.name); + struct jaf_declaration *param = &decl->params->items[i]->decl; + init_variable(ain, &f->vars[i], param->name, param->type); + } + f->vars = block_get_vars(ain, decl->body, f->vars, &f->nr_vars); +} + +static void add_function(struct ain *ain, struct jaf_declaration *decl) +{ + struct ain_function f = {0}; + f.name = strdup(decl->name->text); + jaf_to_ain_type(ain, &f.return_type, decl->type); + function_init_vars(ain, &f, decl); + + decl->func_no = ain_add_function(ain, &f); +} + static void add_global(struct ain *ain, struct jaf_declaration *decl) { char *u = encode_text_to_input_format(decl->name->text); @@ -172,9 +388,9 @@ static void add_global(struct ain *ain, struct jaf_declaration *decl) free(u); } -static void compile_declaration(possibly_unused struct ain *ain, struct jaf_declaration *decl) +static void compile_declaration(possibly_unused struct ain *ain, struct jaf_block_item *decl) { - if (decl->function) { + if (decl->kind == JAF_FUNCTION) { WARNING("Functions not supported"); return; } @@ -199,32 +415,21 @@ void jaf_compile(struct ain *out, const char *path) ERROR("Failed to parse .jaf file"); // pass 1: typedefs && struct definitions - for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) { - resolve_types(out, jaf_toplevel->decls[i]); - } + resolve_types(out, jaf_toplevel); // pass 2: register globals (names, types) - for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) { - if (jaf_toplevel->decls[i]->name) { - if (jaf_toplevel->decls[i]->function) - ERROR("Functions not supported"); + for (size_t i = 0; i < jaf_toplevel->nr_items; i++) { + if (jaf_toplevel->items[i]->decl.name) { + if (jaf_toplevel->items[i]->kind == JAF_FUNCTION) + add_function(out, &jaf_toplevel->items[i]->decl); else - add_global(out, jaf_toplevel->decls[i]); + add_global(out, &jaf_toplevel->items[i]->decl); } } // pass 3: type analysis & simplification & global initvals (static analysis) - for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) { - if (jaf_toplevel->decls[i]->init) { - analyze_expression(out, &jaf_toplevel->decls[i]->init, jaf_toplevel->decls[i]->type); - - // add initval to ain object - struct ain_initval init = { .global_index = jaf_toplevel->decls[i]->var_no }; - jaf_to_initval(&init, jaf_toplevel->decls[i]->init); - ain_add_initval(out, &init); - } - } + analyze_block(out, jaf_toplevel); // pass 4: generate bytecode - for (size_t i = 0; i < jaf_toplevel->nr_decls; i++) { - compile_declaration(out, jaf_toplevel->decls[i]); + for (size_t i = 0; i < jaf_toplevel->nr_items; i++) { + compile_declaration(out, jaf_toplevel->items[i]); } // XXX: ain_add_initval adds initval to GSET section of the ain file. @@ -233,4 +438,6 @@ void jaf_compile(struct ain *out, const char *path) if (out->nr_initvals && !out->GSET.present) { WARNING("%d global initvals ignored", out->nr_initvals); } + + jaf_free_block(jaf_toplevel); } diff --git a/src/tools/ainedit/jaf_lexer.l b/src/tools/ainedit/jaf_lexer.l index 7b20790..58b0984 100644 --- a/src/tools/ainedit/jaf_lexer.l +++ b/src/tools/ainedit/jaf_lexer.l @@ -49,8 +49,6 @@ extern void yyerror(const char *); /* prints grammar violation message */ extern int sym_type(const char *); /* returns type from symbol table */ -#define sym_type(identifier) IDENTIFIER /* with no symbol table, fake it */ - static void comment(void); static int check_type(void); diff --git a/src/tools/ainedit/jaf_parser.y b/src/tools/ainedit/jaf_parser.y index 91150da..3e97a26 100644 --- a/src/tools/ainedit/jaf_parser.y +++ b/src/tools/ainedit/jaf_parser.y @@ -31,7 +31,9 @@ void yyerror(const char *s); struct jaf_type_specifier *type; struct jaf_declarator *declarator; struct jaf_declarator_list *declarators; - struct jaf_declaration_list *declarations; + struct jaf_block *block; + struct jaf_block_item *statement; + struct jaf_function_declarator *fundecl; } %token I_CONSTANT F_CONSTANT STRING_LITERAL @@ -62,8 +64,13 @@ void yyerror(const char *s); %type type_specifier struct_specifier declaration_specifiers %type init_declarator declarator %type init_declarator_list struct_declarator_list -%type translation_unit external_declaration declaration -%type struct_declaration struct_declaration_list +%type translation_unit external_declaration declaration function_definition +%type struct_declaration struct_declaration_list +%type parameter_list parameter_declaration +%type compound_statement block_item_list block_item +%type statement labeled_statement expression_statement selection_statement +%type iteration_statement jump_statement +%type function_declarator /* * Shift-reduce conflicts: @@ -276,7 +283,7 @@ type_parameter_list struct_declaration_list : struct_declaration { $$ = $1; } - | struct_declaration_list struct_declaration { $$ = jaf_declarations($1, $2); } + | struct_declaration_list struct_declaration { $$ = jaf_merge_blocks($1, $2); } ; struct_declaration @@ -315,8 +322,6 @@ declarator : IDENTIFIER { $$ = jaf_declarator($1); } // | '(' declarator ')' // XXX: causes shift-reduce conflict with function-like casts (e.g. "string(identifier)") | array_allocation { ERROR("Arrays not supported"); } - | IDENTIFIER '(' parameter_type_list ')' { ERROR("Function declarator not supported"); } // ??? remove? - | IDENTIFIER '(' ')' { ERROR("Function declarator not supported"); } // ??? remove? ; array_allocation @@ -324,21 +329,6 @@ array_allocation | array_allocation '[' constant ']' ; -parameter_type_list - : parameter_list ',' ELLIPSIS - | parameter_list - ; - -parameter_list - : parameter_declaration - | parameter_list ',' parameter_declaration - ; - -parameter_declaration - : declaration_specifiers declarator - | declaration_specifiers - ; - initializer : '{' initializer_list '}' { $$ = NULL; } | '{' initializer_list ',' '}' { $$ = NULL; } @@ -367,61 +357,61 @@ designator ; statement - : labeled_statement - | compound_statement - | expression_statement - | selection_statement - | iteration_statement - | jump_statement + : labeled_statement { $$ = $1; } + | compound_statement { $$ = jaf_compound_statement($1); } + | expression_statement { $$ = $1; } + | selection_statement { $$ = $1; } + | iteration_statement { $$ = $1; } + | jump_statement { $$ = $1; } ; labeled_statement - : IDENTIFIER ':' statement - | CASE constant_expression ':' statement - | DEFAULT ':' statement + : IDENTIFIER ':' statement { $$ = jaf_label_statement($1, $3); } + | CASE constant_expression ':' statement { $$ = jaf_case_statement($2, $4); } + | DEFAULT ':' statement { $$ = jaf_case_statement(NULL, $3); } ; compound_statement - : '{' '}' - | '{' block_item_list '}' + : '{' '}' { $$ = jaf_block(NULL); } + | '{' block_item_list '}' { $$ = $2; } ; block_item_list - : block_item - | block_item_list block_item + : block_item { $$ = $1; } + | block_item_list block_item { $$ = jaf_merge_blocks($1, $2); } ; block_item - : declaration - | statement + : declaration { $$ = $1; } + | statement { $$ = jaf_block($1); } ; expression_statement - : ';' - | expression ';' + : ';' { $$ = jaf_expression_statement(NULL); } + | expression ';' { $$ = jaf_expression_statement($1); } ; selection_statement - : IF '(' expression ')' statement ELSE statement - | IF '(' expression ')' statement - | SYM_SWITCH '(' expression ')' statement + : IF '(' expression ')' statement ELSE statement { $$ = jaf_if_statement($3, $5, $7); } + | IF '(' expression ')' statement { $$ = jaf_if_statement($3, $5, NULL); } + | SYM_SWITCH '(' expression ')' compound_statement { $$ = jaf_switch_statement($3, $5); } ; iteration_statement - : WHILE '(' expression ')' statement - | DO statement WHILE '(' expression ')' ';' - | FOR '(' expression_statement expression_statement ')' statement - | FOR '(' expression_statement expression_statement expression ')' statement - | FOR '(' declaration expression_statement ')' statement - | FOR '(' declaration expression_statement expression ')' statement + : WHILE '(' expression ')' statement { $$ = jaf_while_loop($3, $5); } + | DO statement WHILE '(' expression ')' ';' { $$ = jaf_do_while_loop($5, $2); } + | FOR '(' expression_statement expression_statement ')' statement { $$ = jaf_for_loop(jaf_block($3), $4, NULL, $6); } + | FOR '(' expression_statement expression_statement expression ')' statement { $$ = jaf_for_loop(jaf_block($3), $4, $5, $7); } + | FOR '(' declaration expression_statement ')' statement { $$ = jaf_for_loop($3, $4, NULL, $6); } + | FOR '(' declaration expression_statement expression ')' statement { $$ = jaf_for_loop($3, $4, $5, $7); } ; jump_statement - : GOTO IDENTIFIER ';' - | CONTINUE ';' - | BREAK ';' - | SYM_RETURN ';' - | SYM_RETURN expression ';' + : GOTO IDENTIFIER ';' { $$ = jaf_goto($2); } + | CONTINUE ';' { $$ = jaf_continue(); } + | BREAK ';' { $$ = jaf_break(); } + | SYM_RETURN ';' { $$ = jaf_return(NULL); } + | SYM_RETURN expression ';' { $$ = jaf_return($2); } ; toplevel @@ -429,17 +419,31 @@ toplevel ; translation_unit - : external_declaration { $$ = jaf_declarations(NULL, $1); } - | translation_unit external_declaration { $$ = jaf_declarations($1, $2); } + : external_declaration { $$ = jaf_merge_blocks(NULL, $1); } + | translation_unit external_declaration { $$ = jaf_merge_blocks($1, $2); } ; external_declaration - : function_definition { ERROR("Functions not yet supported"); } + : function_definition { $$ = $1; } | declaration { $$ = $1; } ; function_definition - : declaration_specifiers declarator compound_statement + : declaration_specifiers function_declarator compound_statement { $$ = jaf_function($1, $2, $3); } + ; + +function_declarator + : IDENTIFIER '(' parameter_list ')' { $$ = jaf_function_declarator($1, $3); } + | IDENTIFIER '(' ')' { $$ = jaf_function_declarator($1, NULL); } + ; + +parameter_list + : parameter_declaration { $$ = $1; } + | parameter_list ',' parameter_declaration { $$ = jaf_merge_blocks($1, $3); } + ; + +parameter_declaration + : declaration_specifiers declarator { $$ = jaf_parameter($1, $2); } ; %% diff --git a/src/tools/ainedit/jaf_types.c b/src/tools/ainedit/jaf_types.c index 7ba9550..808dad8 100644 --- a/src/tools/ainedit/jaf_types.c +++ b/src/tools/ainedit/jaf_types.c @@ -23,8 +23,6 @@ #define TYPE_CHECK(expr, expected) { if (expr->derived_type != expected) TYPE_ERROR(expr, expected); } #define TYPE_CHECK_NUMERIC(expr) { if (expr->derived_type != JAF_INT && expr->derived_type != JAF_FLOAT) TYPE_ERROR(expr, JAF_INT); } -static void jaf_derive_types(struct jaf_expression *expr); - static enum jaf_type jaf_type_check_numeric(struct jaf_expression *expr) { if (expr->derived_type != JAF_INT && expr->derived_type != JAF_FLOAT) @@ -166,15 +164,13 @@ static enum jaf_type _jaf_check_types(struct jaf_expression *expr) ERROR("Unhandled expression type"); } -static void jaf_derive_types(struct jaf_expression *expr) +void jaf_derive_types(struct jaf_expression *expr) { expr->derived_type = _jaf_check_types(expr); } -void jaf_check_types(struct jaf_expression *expr, struct jaf_type_specifier *type) +void jaf_check_type(struct jaf_expression *expr, struct jaf_type_specifier *type) { - jaf_derive_types(expr); - // TODO: struct types, etc. if (expr->derived_type != type->type) { TYPE_ERROR(expr, type->type); }