diff --git a/include/system4/ain.h b/include/system4/ain.h index 76421ff..b37808a 100644 --- a/include/system4/ain.h +++ b/include/system4/ain.h @@ -336,10 +336,12 @@ struct ain_struct *ain_get_struct(struct ain *ain, char *name); 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); -struct ain_variable *ain_get_global(struct ain *ain, char *name); -int ain_get_global_no(struct ain *ain, char *name); +struct ain_variable *ain_get_global(struct ain *ain, const char *name); +int ain_get_global_no(struct ain *ain, const char *name); void ain_add_initval(struct ain *ain, struct ain_initval *init); int ain_add_function(struct ain *ain, struct ain_function *fun); +int ain_add_functype(struct ain *ain, struct ain_function_type *fun); +int ain_get_functype(struct ain *ain, const char *name); int ain_add_string(struct ain *ain, const char *str); int ain_add_file(struct ain *ain, const char *filename); diff --git a/src/ain.c b/src/ain.c index c052d55..ffa5ebf 100644 --- a/src/ain.c +++ b/src/ain.c @@ -248,7 +248,7 @@ struct ain_variable *ain_add_global(struct ain *ain, char *name) return &ain->globals[no]; } -struct ain_variable *ain_get_global(struct ain *ain, char *name) +struct ain_variable *ain_get_global(struct ain *ain, const char *name) { // TODO: use hash table for faster lookup for (int i = 0; i < ain->nr_globals; i++) { @@ -258,7 +258,7 @@ struct ain_variable *ain_get_global(struct ain *ain, char *name) return NULL; } -int ain_get_global_no(struct ain *ain, char *name) +int ain_get_global_no(struct ain *ain, const char *name) { struct ain_variable *v = ain_get_global(ain, name); return v ? v - ain->globals : -1; @@ -281,6 +281,24 @@ int ain_add_function(struct ain *ain, struct ain_function *fun) return no; } +int ain_add_functype(struct ain *ain, struct ain_function_type *fun) +{ + int no = ain->nr_function_types; + ain->function_types = xrealloc_array(ain->function_types, no, no+1, sizeof(struct ain_function_type)); + ain->function_types[no] = *fun; + ain->nr_function_types++; + return no; +} + +int ain_get_functype(struct ain *ain, const char *name) +{ + for (int i = 0; i < ain->nr_function_types; i++) { + if (!strcmp(ain->function_types[i].name, name)) + return i; + } + return -1; +} + int ain_add_string(struct ain *ain, const char *str) { if (!ain->_string_ht) diff --git a/src/meson.build b/src/meson.build index 49f251c..290e072 100644 --- a/src/meson.build +++ b/src/meson.build @@ -73,7 +73,7 @@ flexgen = generator(flex, bisongen = generator(bison, output: ['@BASENAME@.tab.c', '@BASENAME@.tab.h'], - arguments : ['@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']) + arguments : ['--verbose', '@INPUT@', '--defines=@OUTPUT1@', '--output=@OUTPUT0@']) system4 += flexgen.process('ini_lexer.l') system4 += bisongen.process('ini_parser.y') diff --git a/src/tools/ainedit/jaf.h b/src/tools/ainedit/jaf.h index fd96665..cccb3e1 100644 --- a/src/tools/ainedit/jaf.h +++ b/src/tools/ainedit/jaf.h @@ -31,7 +31,7 @@ enum jaf_type { JAF_STRUCT, JAF_ENUM, JAF_TYPEDEF, - JAF_FUNCTION, + JAF_FUNCTYPE, }; enum jaf_type_qualifier { @@ -195,6 +195,7 @@ struct jaf_function_declarator { enum block_item_kind { JAF_DECLARATION, + JAF_FUNCTYPE_DECL, JAF_FUNDECL, JAF_STMT_LABELED, JAF_STMT_COMPOUND, @@ -314,6 +315,7 @@ struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, st 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_functype(struct jaf_type_specifier *type, struct jaf_function_declarator *decl); 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); @@ -346,8 +348,6 @@ struct jaf_block *jaf_parse(struct ain *ain, const char **files, unsigned nr_fil // jaf_compile.c void jaf_build(struct ain *out, const char **files, unsigned nr_files); -void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type); - // jaf_eval.c struct jaf_expression *jaf_simplify(struct jaf_expression *in); @@ -359,5 +359,7 @@ void jaf_check_type(struct jaf_expression *expr, struct ain_type *type); // jaf_static_analysis.c struct jaf_block *jaf_static_analyze(struct ain *ain, struct jaf_block *block); enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers); +void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type); +void jaf_define_functype(struct ain *ain, struct jaf_declaration *decl); #endif /* AINEDIT_JAF_H */ diff --git a/src/tools/ainedit/jaf_ast.c b/src/tools/ainedit/jaf_ast.c index 7e3a95e..ebff146 100644 --- a/src/tools/ainedit/jaf_ast.c +++ b/src/tools/ainedit/jaf_ast.c @@ -120,7 +120,7 @@ struct jaf_expression *jaf_function_call(struct jaf_expression *fun, struct jaf_ { struct jaf_expression *e = jaf_expr(JAF_EXP_FUNCALL, 0); e->call.fun = fun; - e->call.args = args; + e->call.args = args ? args : xcalloc(1, sizeof(struct jaf_argument_list)); return e; } @@ -251,13 +251,17 @@ struct jaf_declarator_list *jaf_declarators(struct jaf_declarator_list *head, st static void init_declaration(struct jaf_type_specifier *type, struct jaf_block_item *dst, struct jaf_declarator *src) { dst->kind = JAF_DECLARATION; - dst->decl.name = src->name; dst->decl.type = type; - dst->decl.init = src->init; - dst->decl.array_dims = src->array_dims; - if (src->array_rank && src->array_rank != type->rank) - ERROR("Invalid array declaration"); - free(src); + if (src) { + dst->decl.name = src->name; + dst->decl.init = src->init; + dst->decl.array_dims = src->array_dims; + if (src->array_rank && src->array_rank != type->rank) + ERROR("Invalid array declaration"); + free(src); + } else { + dst->decl.name = make_string("", 0); + } } struct jaf_block *jaf_parameter(struct jaf_type_specifier *type, struct jaf_declarator *declarator) @@ -275,9 +279,30 @@ struct jaf_function_declarator *jaf_function_declarator(struct string *name, str struct jaf_function_declarator *decl = xmalloc(sizeof(struct jaf_function_declarator)); decl->name = name; decl->params = params; + + // XXX: special case for f(void) functype declarator. + if (params && params->nr_items == 1 && params->items[0]->decl.type->type == JAF_VOID) { + decl->params = NULL; + jaf_free_block(params); + } + return decl; } +struct jaf_block *jaf_functype(struct jaf_type_specifier *type, struct jaf_function_declarator *decl) +{ + 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_FUNCTYPE_DECL; + p->items[0]->decl.type = type; + p->items[0]->decl.name = decl->name; + p->items[0]->decl.params = decl->params; + free(decl); + return p; +} + 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)); @@ -542,6 +567,12 @@ void jaf_free_block_item(struct jaf_block_item *item) } jaf_free_type_specifier(item->decl.type); break; + case JAF_FUNCTYPE_DECL: + if (item->decl.name) + free_string(item->decl.name); + jaf_free_type_specifier(item->decl.type); + jaf_free_block(item->decl.params); + break; case JAF_FUNDECL: if (item->decl.name) free_string(item->decl.name); diff --git a/src/tools/ainedit/jaf_compile.c b/src/tools/ainedit/jaf_compile.c index 84fe651..f32c668 100644 --- a/src/tools/ainedit/jaf_compile.c +++ b/src/tools/ainedit/jaf_compile.c @@ -253,12 +253,14 @@ static void compile_dereference(struct compiler_state *state, struct ain_type *t case AIN_FLOAT: case AIN_BOOL: case AIN_LONG_INT: + case AIN_FUNC_TYPE: write_instruction0(state, REF); break; case AIN_REF_INT: case AIN_REF_FLOAT: case AIN_REF_BOOL: case AIN_REF_LONG_INT: + case AIN_REF_FUNC_TYPE: write_instruction0(state, REFREF); write_instruction0(state, REF); break; @@ -318,7 +320,8 @@ static void compile_unary(struct compiler_state *state, struct jaf_expression *e { switch (expr->op) { case JAF_AMPERSAND: - ERROR("Function types not supported"); + write_instruction1(state, PUSH, expr->valuetype.struc); + break; case JAF_UNARY_PLUS: compile_expression(state, expr->expr); break; @@ -453,8 +456,37 @@ static bool ain_ref_type(enum ain_data_type type) } } +static void jaf_compile_functype_call(struct compiler_state *state, struct jaf_expression *expr) +{ + // NOTE: The functype expression has to be compiled first and then swapped with each + // argument in case one of the argument expressions changes the value of the + // functype expression. + compile_expression(state, expr->call.fun); + + struct ain_function_type *f = &state->ain->function_types[expr->call.func_no]; + for (size_t i = 0; i < expr->call.args->nr_items; i++) { + enum ain_data_type type = f->variables[expr->call.args->var_nos[i]].type.data; + if (ain_ref_type(type)) { + compile_lvalue(state, expr->call.args->items[i]); + write_instruction0(state, DUP2_X1); + write_instruction0(state, POP); + write_instruction0(state, POP); + } else { + compile_expression(state, expr->call.args->items[i]); + write_instruction0(state, SWAP); + } + } + write_instruction1(state, PUSH, expr->call.fun->valuetype.struc); + write_instruction0(state, CALLFUNC2); +} + static void compile_funcall(struct compiler_state *state, struct jaf_expression *expr) { + if (expr->call.fun->valuetype.data == AIN_FUNC_TYPE) { + jaf_compile_functype_call(state, expr); + return; + } + for (size_t i = 0; i < expr->call.args->nr_items; i++) { struct ain_function *f = &state->ain->functions[expr->call.func_no]; if (ain_ref_type(f->vars[expr->call.args->var_nos[i]].type.data)) { @@ -630,6 +662,7 @@ static void compile_vardecl(struct compiler_state *state, struct jaf_declaration case AIN_INT: case AIN_BOOL: case AIN_LONG_INT: + case AIN_FUNC_TYPE: write_instruction0(state, PUSHLOCALPAGE); write_instruction1(state, PUSH, decl->var_no); if (decl->init) @@ -668,6 +701,7 @@ static void compile_vardecl(struct compiler_state *state, struct jaf_declaration case AIN_REF_BOOL: case AIN_REF_FLOAT: case AIN_REF_LONG_INT: + case AIN_REF_FUNC_TYPE: if (state->ain->version < 6) { write_instruction1(state, CALLSYS, SYS_LOCK_PEEK); write_instruction0(state, POP); @@ -859,11 +893,12 @@ static void compile_statement(struct compiler_state *state, struct jaf_block_ite case JAF_DECLARATION: compile_vardecl(state, &item->decl); break; + case JAF_FUNCTYPE_DECL: + ERROR("Function types must be declared at top-level"); case JAF_FUNDECL: ERROR("Nested functions not supported"); case JAF_STMT_LABELED: ERROR("Labels not supported"); - break; case JAF_STMT_COMPOUND: compile_block(state, item->block); break; diff --git a/src/tools/ainedit/jaf_lexer.l b/src/tools/ainedit/jaf_lexer.l index dd6d7e7..a62deeb 100644 --- a/src/tools/ainedit/jaf_lexer.l +++ b/src/tools/ainedit/jaf_lexer.l @@ -84,10 +84,15 @@ unsigned long jaf_line = 1; "void" { return(VOID); } "while" { return(WHILE); } "bool" { return BOOL; } -"__func__" { return FUNC_NAME; } +"__FILE__" { return FILE_MACRO; } +"__LINE__" { return LINE_MACRO; } +"__FUNC__" { return FUNC_MACRO; } +"__DATE__" { return DATE_MACRO; } +"__TIME__" { return TIME_MACRO; } "ref" { return SYM_REF; } "system" { return SYSTEM; } "array" { return ARRAY; } +"functype" { return FUNCTYPE; } {L}{A}* { return check_type(); } diff --git a/src/tools/ainedit/jaf_parser.y b/src/tools/ainedit/jaf_parser.y index 014b5da..90623e8 100644 --- a/src/tools/ainedit/jaf_parser.y +++ b/src/tools/ainedit/jaf_parser.y @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include "system4.h" @@ -91,12 +92,15 @@ struct jaf_block *jaf_parse(struct ain *ain, const char **files, unsigned nr_fil int sym_type(char *name) { char *u = encode_text_to_input_format(name); - struct ain_struct *s = ain_get_struct(jaf_ain_out, u); - free(u); - - if (s) { + if (ain_get_struct(jaf_ain_out, u)) { + free(u); return TYPEDEF_NAME; } + if (ain_get_functype(jaf_ain_out, u) >= 0) { + free(u); + return TYPEDEF_NAME; + } + free(u); return IDENTIFIER; } @@ -111,6 +115,31 @@ static int parse_int(struct string *s) return i; } +static struct string *string_ftime(const char *fmt) +{ + char out[200]; + time_t t; + struct tm *tmp; + + t = time(NULL); + if (!(tmp = localtime(&t))) + ERROR("localtime: %s", strerror(errno)); + if (strftime(out, sizeof(out), fmt, tmp) == 0) + ERROR("strftime returned 0"); + + return make_string(out, strlen(out)); +} + +static struct string *date_macro(void) +{ + return string_ftime("%Y/%m/%d"); +} + +static struct string *time_macro(void) +{ + return string_ftime("%H:%M:%S"); +} + %} %union { @@ -133,7 +162,8 @@ static int parse_int(struct string *s) %token AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN %token SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN %token XOR_ASSIGN OR_ASSIGN -%token SYM_REF REF_ASSIGN FUNC_NAME SYSTEM ARRAY +%token SYM_REF REF_ASSIGN SYSTEM ARRAY FUNCTYPE +%token FILE_MACRO LINE_MACRO FUNC_MACRO DATE_MACRO TIME_MACRO %token CONST %token BOOL CHAR INT LONG FLOAT VOID STRING @@ -158,16 +188,19 @@ static int parse_int(struct string *s) %type translation_unit external_declaration declaration function_definition %type struct_declaration struct_declaration_list %type parameter_list parameter_declaration +%type functype_parameter_list functype_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 +%type function_declarator functype_declarator /* * Shift-reduce conflicts: * 1. dangling else + * 2. functype vs global */ %expect 1 +%precedence FUNCTYPE %start toplevel %% @@ -191,8 +224,11 @@ enumeration_constant /* before it has been defined as such */ string : STRING_LITERAL { $$ = $1; } - | FUNC_NAME { ERROR("__func__ not supported"); } -// | STRING '(' assignment_expression ')' + | FILE_MACRO { $$ = cstr_to_string(jaf_file); } + | LINE_MACRO { $$ = integer_to_string(jaf_line); } + | FUNC_MACRO { ERROR("__FUNC__ not supported"); } + | DATE_MACRO { $$ = date_macro(); } + | TIME_MACRO { $$ = time_macro(); } ; postfix_expression @@ -524,8 +560,24 @@ translation_unit ; external_declaration - : function_definition { $$ = $1; } - | declaration { $$ = $1; } + : function_definition { $$ = $1; } + | declaration { $$ = $1; } + | FUNCTYPE declaration_specifiers functype_declarator ';' { $$ = jaf_functype($2, $3); jaf_define_functype(jaf_ain_out, &$$->items[0]->decl); } + ; + +functype_declarator + : IDENTIFIER '(' functype_parameter_list ')' { $$ = jaf_function_declarator($1, $3); } + | IDENTIFIER '(' ')' { $$ = jaf_function_declarator($1, NULL); } + ; + +functype_parameter_list + : functype_parameter_declaration { $$ = $1; } + | functype_parameter_list ',' functype_parameter_declaration { $$ = jaf_merge_blocks($1, $3); } + ; + +functype_parameter_declaration + : declaration_specifiers { $$ = jaf_parameter($1, NULL); } + | declaration_specifiers declarator { $$ = jaf_parameter($1, $2); } ; function_definition diff --git a/src/tools/ainedit/jaf_static_analysis.c b/src/tools/ainedit/jaf_static_analysis.c index def6c0d..1c95920 100644 --- a/src/tools/ainedit/jaf_static_analysis.c +++ b/src/tools/ainedit/jaf_static_analysis.c @@ -46,6 +46,15 @@ void jaf_define_struct(struct ain *ain, struct jaf_type_specifier *type) } } +void jaf_define_functype(struct ain *ain, struct jaf_declaration *decl) +{ + struct ain_function_type f = {0}; + f.name = encode_text_to_input_format(decl->name->text); + if (ain_get_functype(ain, f.name) >= 0) + ERROR("Multiple definitions of function type '%s'", decl->name->text); + decl->func_no = ain_add_functype(ain, &f); +} + static void define_types(struct ain *ain, struct jaf_block_item *decl) { if (!decl) @@ -69,7 +78,7 @@ enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers) case JAF_STRUCT: return AIN_REF_ARRAY_STRUCT; case JAF_ENUM: ERROR("Enums not supported"); case JAF_TYPEDEF: ERROR("Unresolved typedef"); - case JAF_FUNCTION: ERROR("Function types not supported"); + case JAF_FUNCTYPE: return AIN_REF_ARRAY_FUNC_TYPE; } } else if (qualifiers & JAF_QUAL_REF) { switch (type) { @@ -80,7 +89,7 @@ enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers) case JAF_STRUCT: return AIN_REF_STRUCT; case JAF_ENUM: ERROR("Enums not supported"); case JAF_TYPEDEF: ERROR("Unresolved typedef"); - case JAF_FUNCTION: ERROR("Function types not supported"); + case JAF_FUNCTYPE: return AIN_REF_FUNC_TYPE; } } else if (qualifiers & JAF_QUAL_ARRAY) { switch (type) { @@ -91,7 +100,7 @@ enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers) case JAF_STRUCT: return AIN_ARRAY_STRUCT; case JAF_ENUM: ERROR("Enums not supported"); case JAF_TYPEDEF: ERROR("Unresolved typedef"); - case JAF_FUNCTION: ERROR("Function types not supported"); + case JAF_FUNCTYPE: return AIN_ARRAY_FUNC_TYPE; } } else { switch (type) { @@ -102,7 +111,7 @@ enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers) case JAF_STRUCT: return AIN_STRUCT; case JAF_ENUM: ERROR("Enums not supported"); case JAF_TYPEDEF: ERROR("Unresolved typedef"); - case JAF_FUNCTION: ERROR("Function types not supported"); + case JAF_FUNCTYPE: return AIN_FUNC_TYPE; } } ERROR("Unknown type: %d", type); @@ -111,7 +120,7 @@ enum ain_data_type jaf_to_ain_data_type(enum jaf_type type, unsigned qualifiers) static void jaf_to_ain_type(possibly_unused struct ain *ain, struct ain_type *out, struct jaf_type_specifier *in) { out->data = jaf_to_ain_data_type(in->type, in->qualifiers); - if (in->type == JAF_STRUCT) { + if (in->type == JAF_STRUCT || in->type == JAF_FUNCTYPE) { out->struc = in->struct_no; } else { out->struc = -1; @@ -123,11 +132,14 @@ static void jaf_to_ain_type(possibly_unused struct ain *ain, struct ain_type *ou static void resolve_typedef(struct ain *ain, struct jaf_type_specifier *type) { + int no; char *u = encode_text_to_input_format(type->name->text); - int sno = ain_get_struct_no(ain, u); - if (sno >= 0) { + if ((no = ain_get_struct_no(ain, u)) >= 0) { type->type = JAF_STRUCT; - type->struct_no = sno; + type->struct_no = no; + } else if ((no = ain_get_functype(ain, u)) >= 0) { + type->type = JAF_FUNCTYPE; + type->func_no = no; } else { ERROR("Failed to resolve typedef \"%s\"", type->name->text); } @@ -189,6 +201,8 @@ static void analyze_global_declaration(struct jaf_env *env, struct jaf_declarati jaf_to_initval(&init, decl->init); ain_add_initval(env->ain, &init); analyze_array_allocation(env, decl); + if (decl->init) + analyze_expression(env, &decl->init); } static void analyze_local_declaration(struct jaf_env *env, struct jaf_declaration *decl) @@ -201,6 +215,8 @@ static void analyze_local_declaration(struct jaf_env *env, struct jaf_declaratio env->locals = xrealloc_array(env->locals, env->nr_locals, env->nr_locals+1, sizeof(struct ain_variable*)); env->locals[env->nr_locals++] = &env->ain->functions[env->func_no].vars[decl->var_no]; analyze_array_allocation(env, decl); + if (decl->init) + analyze_expression(env, &decl->init); } static void analyze_function(struct jaf_env *env, struct jaf_declaration *decl) @@ -297,6 +313,7 @@ static void analyze_statement(struct jaf_env *env, struct jaf_block_item *item) case JAF_STMT_DEFAULT: analyze_statement(env, item->swi_case.stmt); break; + case JAF_FUNCTYPE_DECL: case JAF_STMT_GOTO: case JAF_STMT_CONTINUE: case JAF_STMT_BREAK: @@ -352,6 +369,10 @@ static void resolve_statement_types(struct ain *ain, struct jaf_block_item *item case JAF_DECLARATION: resolve_decl_types(ain, &item->decl); break; + case JAF_FUNCTYPE_DECL: + if (item->decl.params) + jaf_resolve_types(ain, item->decl.params); + break; case JAF_FUNDECL: if (item->decl.params) jaf_resolve_types(ain, item->decl.params); @@ -465,6 +486,7 @@ static struct ain_variable *block_item_get_vars(struct ain *ain, struct jaf_bloc vars = block_item_get_vars(ain, item->swi_case.stmt, vars, nr_vars); break; + case JAF_FUNCTYPE_DECL: case JAF_STMT_EXPRESSION: case JAF_STMT_GOTO: case JAF_STMT_CONTINUE: @@ -487,19 +509,20 @@ static struct ain_variable *block_get_vars(struct ain *ain, struct jaf_block *bl return vars; } -static void function_init_vars(struct ain *ain, struct ain_function *f, struct jaf_declaration *decl) +static void function_init_vars(struct ain *ain, struct jaf_declaration *decl, int32_t *nr_args, int32_t *nr_vars, struct ain_variable **vars) { int nr_params = decl->params ? decl->params->nr_items : 0; - f->nr_args = 0; - f->vars = xcalloc(nr_params * 2, sizeof(struct ain_variable)); + *nr_args = 0; + *vars = xcalloc(nr_params * 2, sizeof(struct ain_variable)); for (int i = 0; i < nr_params; 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, &f->nr_args, param); + init_variable(ain, *vars, nr_args, param); } - f->nr_vars = f->nr_args; - f->vars = block_get_vars(ain, decl->body, f->vars, &f->nr_vars); + *nr_vars = *nr_args; + if (decl->body) + *vars = block_get_vars(ain, decl->body, *vars, nr_vars); } static void add_function(struct ain *ain, struct jaf_declaration *decl) @@ -507,7 +530,7 @@ 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); + function_init_vars(ain, decl, &f.nr_args, &f.nr_vars, &f.vars); decl->func_no = ain_add_function(ain, &f); if (!strcmp(decl->name->text, "main")) { @@ -519,6 +542,14 @@ static void add_function(struct ain *ain, struct jaf_declaration *decl) } } +static void add_functype(struct ain *ain, struct jaf_declaration *decl) +{ + assert(decl->func_no >= 0 && decl->func_no <= ain->nr_function_types); + struct ain_function_type *f = &ain->function_types[decl->func_no]; + jaf_to_ain_type(ain, &f->return_type, decl->type); + function_init_vars(ain, decl, &f->nr_arguments, &f->nr_variables, &f->variables); +} + static void add_global(struct ain *ain, struct jaf_declaration *decl) { char *u = encode_text_to_input_format(decl->name->text); @@ -534,6 +565,8 @@ static void jaf_process_declarations(struct ain *ain, struct jaf_block *block) if (block->items[i]->decl.name) { if (block->items[i]->kind == JAF_FUNDECL) add_function(ain, &block->items[i]->decl); + else if (block->items[i]->kind == JAF_FUNCTYPE_DECL) + add_functype(ain, &block->items[i]->decl); else if (block->items[i]->kind == JAF_DECLARATION) add_global(ain, &block->items[i]->decl); } diff --git a/src/tools/ainedit/jaf_types.c b/src/tools/ainedit/jaf_types.c index 3f38da3..a39bd5e 100644 --- a/src/tools/ainedit/jaf_types.c +++ b/src/tools/ainedit/jaf_types.c @@ -22,6 +22,8 @@ #include "ainedit.h" #include "jaf.h" +#define AIN_FUNCTION 8000 + // TODO: better error messages #define TYPE_ERROR(expr, expected) ERROR("Type error (expected %s; got %s)", ain_strtype(NULL, expected, -1), ain_strtype(NULL, expr->valuetype.data, -1)) #define TYPE_CHECK(expr, expected) { if (expr->valuetype.data != expected) TYPE_ERROR(expr, expected); } @@ -36,7 +38,7 @@ const char *jaf_typestr(enum jaf_type type) case JAF_STRUCT: return "struct"; case JAF_ENUM: return "enum"; case JAF_TYPEDEF: return "typedef"; - case JAF_FUNCTION: return "functype"; + case JAF_FUNCTYPE: return "functype"; } return "unknown"; } @@ -69,6 +71,8 @@ static bool jaf_type_equal(struct ain_type *a, struct ain_type *b) return false; if (a_data == AIN_STRUCT && a->struc != b->struc) return false; + if (a_data == AIN_FUNCTION && a->struc != b->struc) + return false; if (a_data == AIN_FUNC_TYPE && a->struc != b->struc) return false; return true; @@ -175,7 +179,13 @@ static void jaf_check_types_unary(struct jaf_env *env, struct jaf_expression *ex expr->valuetype.data = jaf_type_check_int(expr->expr); break; case JAF_AMPERSAND: - ERROR("Function types not supported"); + if (expr->expr->type != JAF_EXP_IDENTIFIER) + ERROR("Non-identifier in '&' expression"); + if (expr->expr->valuetype.data != AIN_FUNCTION) + ERROR("Non-function in '&' expression"); + expr->valuetype.data = AIN_FUNCTION; + expr->valuetype.struc = expr->expr->valuetype.struc; + break; default: ERROR("Unhandled unary operator"); } @@ -279,7 +289,7 @@ static void jaf_check_types_ternary(struct jaf_env *env, struct jaf_expression * expr->valuetype = expr->consequent->valuetype; } -static struct ain_variable *jaf_scope_lookup(struct jaf_env *env, char *name, int *var_no) +static struct ain_variable *jaf_scope_lookup(struct jaf_env *env, const char *name, int *var_no) { for (size_t i = 0; i < env->nr_locals; i++) { if (!strcmp(env->locals[i]->name, name)) { @@ -290,22 +300,18 @@ static struct ain_variable *jaf_scope_lookup(struct jaf_env *env, char *name, in return NULL; } -struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name, int *var_no) +struct ain_variable *jaf_env_lookup(struct jaf_env *env, const char *name, int *var_no) { - char *u = encode_text_to_input_format(name->text); struct jaf_env *scope = env; while (scope) { - struct ain_variable *v = jaf_scope_lookup(scope, u, var_no); + struct ain_variable *v = jaf_scope_lookup(scope, name, var_no); if (v) { - free(u); return v; } scope = scope->parent; } - int no = ain_get_global_no(env->ain, u); - free(u); - + int no = ain_get_global_no(env->ain, name); if (no >= 0) { *var_no = no; return &env->ain->globals[no]; @@ -316,24 +322,20 @@ struct ain_variable *jaf_env_lookup(struct jaf_env *env, struct string *name, in static void jaf_check_types_identifier(struct jaf_env *env, struct jaf_expression *expr) { - int var_no; - struct ain_variable *v = jaf_env_lookup(env, expr->ident.name, &var_no); - if (v) { + int no; + struct ain_variable *v; + char *u = encode_text_to_input_format(expr->s->text); + if ((v = jaf_env_lookup(env, u, &no))) { expr->valuetype = v->type; expr->ident.var_type = v->var_type; - expr->ident.var_no = var_no; - return; - } - - char *u = encode_text_to_input_format(expr->s->text); - int func_no = ain_get_function_no(env->ain, u); - free(u); - if (func_no < 0) + expr->ident.var_no = no; + } else if ((no = ain_get_function_no(env->ain, u)) >= 0) { + expr->valuetype.data = AIN_FUNCTION; + expr->valuetype.struc = no; + } else { ERROR("Undefined variable: %s", expr->s->text); - - // FIXME: this isn't quite right... - expr->valuetype.data = AIN_FUNC_TYPE; - expr->valuetype.struc = func_no; + } + free(u); } static bool ain_wide_type(enum ain_data_type type) { @@ -348,23 +350,57 @@ static bool ain_wide_type(enum ain_data_type type) { } } +// FIXME: use struct ain_function for function types so that this function isn't needed. +static void jaf_check_types_functype_call(struct jaf_env *env, struct jaf_expression *expr) +{ + unsigned nr_args = expr->call.args ? expr->call.args->nr_items : 0; + int ft_no = expr->call.fun->valuetype.struc; + assert(ft_no >= 0 && ft_no <= env->ain->nr_function_types); + expr->valuetype = env->ain->function_types[ft_no].return_type; + expr->call.func_no = ft_no; + + struct ain_function_type *f = &env->ain->function_types[ft_no]; + expr->call.args->var_nos = xcalloc(nr_args, sizeof(int)); + + // type check arguments against function prototype. + int arg = 0; + for (size_t i = 0; i < nr_args; i++, arg++) { + if (arg >= f->nr_arguments) + ERROR("Too many arguments to function"); + + jaf_check_type(expr->call.args->items[i], &f->variables[arg].type); + + expr->call.args->var_nos[i] = arg; + if (ain_wide_type(f->variables[arg].type.data)) + arg++; + } + if (arg != f->nr_arguments) + ERROR("Too few arguments to function"); +} + static void jaf_check_types_funcall(struct jaf_env *env, struct jaf_expression *expr) { jaf_derive_types(env, expr->call.fun); - TYPE_CHECK(expr->call.fun, AIN_FUNC_TYPE); + if (expr->call.fun->valuetype.data != AIN_FUNCTION && expr->call.fun->valuetype.data != AIN_FUNC_TYPE) + TYPE_ERROR(expr->call.fun, AIN_FUNC_TYPE); unsigned nr_args = expr->call.args ? expr->call.args->nr_items : 0; for (size_t i = 0; i < nr_args; i++) { jaf_derive_types(env, expr->call.args->items[i]); } + if (expr->call.fun->valuetype.data == AIN_FUNC_TYPE) { + jaf_check_types_functype_call(env, expr); + return; + } + int func_no = expr->call.fun->valuetype.struc; assert(func_no >= 0 && func_no < env->ain->nr_functions); expr->valuetype = env->ain->functions[func_no].return_type; expr->call.func_no = func_no; struct ain_function *f = &env->ain->functions[func_no]; - expr->call.args->var_nos = xcalloc(expr->call.args->nr_items, sizeof(int)); + expr->call.args->var_nos = xcalloc(nr_args, sizeof(int)); // type check arguments against function prototype. int arg = 0; diff --git a/src/tools/ainedit/test/functype-ref-int.jaf b/src/tools/ainedit/test/functype-ref-int.jaf new file mode 100644 index 0000000..7dd6fe7 --- /dev/null +++ b/src/tools/ainedit/test/functype-ref-int.jaf @@ -0,0 +1,13 @@ +functype int arithmetic(ref int, int); + +int add(ref int a, int b) +{ + return a + b; +} + +int main() +{ + int a = 1; + arithmetic f = &add; + return !(f(a, 2) == 3); +} diff --git a/src/tools/ainedit/test/functype-void.jaf b/src/tools/ainedit/test/functype-void.jaf new file mode 100644 index 0000000..cb43925 --- /dev/null +++ b/src/tools/ainedit/test/functype-void.jaf @@ -0,0 +1,12 @@ +functype int thunk(void); + +int one(void) +{ + return 1; +} + +int main() +{ + thunk f = &one; + return !(f() == 1); +} diff --git a/src/tools/ainedit/test/functype.jaf b/src/tools/ainedit/test/functype.jaf new file mode 100644 index 0000000..50c11bb --- /dev/null +++ b/src/tools/ainedit/test/functype.jaf @@ -0,0 +1,12 @@ +functype int arithmetic(int, int); + +int add(int a, int b) +{ + return a + b; +} + +int main() +{ + arithmetic f = &add; + return !(f(1, 2) == 3); +} diff --git a/src/tools/ainedit/test/run-tests.sh b/src/tools/ainedit/test/run-tests.sh index c14fd63..21b9b10 100755 --- a/src/tools/ainedit/test/run-tests.sh +++ b/src/tools/ainedit/test/run-tests.sh @@ -97,3 +97,7 @@ cd $(dirname "$0") ./test-runner.sh float-ref.jaf ./test-runner.sh string-ref.jaf ./test-runner.sh local-ref-string.jaf + +./test-runner.sh functype.jaf +./test-runner.sh functype-void.jaf +./test-runner.sh functype-ref-int.jaf