mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-12 09:18:11 +03:00
jaf: function types
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+1
-1
@@ -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')
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#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 <token> AND_OP OR_OP MUL_ASSIGN DIV_ASSIGN MOD_ASSIGN ADD_ASSIGN
|
||||
%token <token> SUB_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN
|
||||
%token <token> XOR_ASSIGN OR_ASSIGN
|
||||
%token <token> SYM_REF REF_ASSIGN FUNC_NAME SYSTEM ARRAY
|
||||
%token <token> SYM_REF REF_ASSIGN SYSTEM ARRAY FUNCTYPE
|
||||
%token <token> FILE_MACRO LINE_MACRO FUNC_MACRO DATE_MACRO TIME_MACRO
|
||||
|
||||
%token <token> CONST
|
||||
%token <token> BOOL CHAR INT LONG FLOAT VOID STRING
|
||||
@@ -158,16 +188,19 @@ static int parse_int(struct string *s)
|
||||
%type <block> translation_unit external_declaration declaration function_definition
|
||||
%type <block> struct_declaration struct_declaration_list
|
||||
%type <block> parameter_list parameter_declaration
|
||||
%type <block> functype_parameter_list functype_parameter_declaration
|
||||
%type <block> compound_statement block_item_list block_item
|
||||
%type <statement> statement labeled_statement expression_statement selection_statement
|
||||
%type <statement> iteration_statement jump_statement
|
||||
%type <fundecl> function_declarator
|
||||
%type <fundecl> 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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
functype int thunk(void);
|
||||
|
||||
int one(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
thunk f = &one;
|
||||
return !(f() == 1);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user