proper call typing?
This commit is contained in:
parent
c2377fa40f
commit
9372a72d43
4 changed files with 93 additions and 8 deletions
|
@ -222,7 +222,7 @@
|
||||||
; array of n t's: TYPE_ARRAY {n as 8 bytes} t
|
; array of n t's: TYPE_ARRAY {n as 8 bytes} t
|
||||||
; struct/union: TYPE_STRUCT {8-byte pointer to struct/union data (see structures in main.b)}
|
; struct/union: TYPE_STRUCT {8-byte pointer to struct/union data (see structures in main.b)}
|
||||||
; note: incomplete structs/unions are replaced with void.
|
; note: incomplete structs/unions are replaced with void.
|
||||||
; function: TYPE_FUNCTION {arg1 type} {arg2 type} ... {argn type} 0 {return type}
|
; function: TYPE_FUNCTION {arg1 type} {arg2 type} ... {argn type} 0 {return type} - NB: varargs (...) are ignored
|
||||||
; note that enum types are just treated as ints.
|
; note that enum types are just treated as ints.
|
||||||
#define TYPE_VOID 1
|
#define TYPE_VOID 1
|
||||||
#define TYPE_CHAR 3
|
#define TYPE_CHAR 3
|
||||||
|
|
|
@ -53,6 +53,8 @@ global global_variables
|
||||||
; - the first one is a STATEMENT_LOCAL_DECLARATION (with dat2=dat3=dat4=0), which is only there to set rsp properly because of parameters
|
; - the first one is a STATEMENT_LOCAL_DECLARATION (with dat2=dat3=dat4=0), which is only there to set rsp properly because of parameters
|
||||||
; - the second one is the function body (a STATEMENT_BLOCK)
|
; - the second one is the function body (a STATEMENT_BLOCK)
|
||||||
global function_statements
|
global function_statements
|
||||||
|
; ident list mapping function names to function types (TYPE_FUNCTION {...})
|
||||||
|
global function_types
|
||||||
; statement_datas[0] = pointer to statement data for block-nesting depth 0 (i.e. function bodies)
|
; statement_datas[0] = pointer to statement data for block-nesting depth 0 (i.e. function bodies)
|
||||||
; statement_datas[1] = pointer to statement data for block-nesting depth 1 (blocks inside functions)
|
; statement_datas[1] = pointer to statement data for block-nesting depth 1 (blocks inside functions)
|
||||||
; statement_datas[2] = pointer to statement data for block-nesting depth 2 (blocks inside blocks inside functions)
|
; statement_datas[2] = pointer to statement data for block-nesting depth 2 (blocks inside blocks inside functions)
|
||||||
|
@ -232,8 +234,8 @@ function main
|
||||||
enumerators = ident_list_create(4000000)
|
enumerators = ident_list_create(4000000)
|
||||||
structures = ident_list_create(4000000)
|
structures = ident_list_create(4000000)
|
||||||
global_variables = ident_list_create(400000)
|
global_variables = ident_list_create(400000)
|
||||||
function_statements = ident_list_create(400000)
|
function_statements = ident_list_create(800000)
|
||||||
|
function_types = ident_list_create(800000)
|
||||||
function_stmt_data = malloc(800000) ; should be at least 40 bytes * max # of functions
|
function_stmt_data = malloc(800000) ; should be at least 40 bytes * max # of functions
|
||||||
|
|
||||||
dat_banned_objmacros = 255
|
dat_banned_objmacros = 255
|
||||||
|
|
10
05/main.c
10
05/main.c
|
@ -1,9 +1,15 @@
|
||||||
/* static int g; */
|
/* static int g; */
|
||||||
|
|
||||||
|
int f(int a, float x[], double y, ...) {
|
||||||
|
}
|
||||||
|
|
||||||
|
float * g() {
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int a = exit;
|
|
||||||
int b[] = {1,2,3};
|
int b[] = {1,2,3};
|
||||||
exit(1, 17, a+b);
|
int a = f(1, 17, b, 36, 55.0, 22.3f);
|
||||||
|
float *f = g(17.2, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* int f(int x, int y[3]) { */
|
/* int f(int x, int y[3]) { */
|
||||||
|
|
83
05/parse.b
83
05/parse.b
|
@ -24,6 +24,20 @@ function token_is_type
|
||||||
if b != 0 goto return_1
|
if b != 0 goto return_1
|
||||||
goto return_0
|
goto return_0
|
||||||
|
|
||||||
|
function functype_return_type
|
||||||
|
argument ftype
|
||||||
|
local type
|
||||||
|
local p
|
||||||
|
|
||||||
|
type = ftype + 1
|
||||||
|
:ftype_rettype_loop
|
||||||
|
p = types + type
|
||||||
|
if *1p == 0 goto ftype_rettype_loop_end
|
||||||
|
type += type_length(type)
|
||||||
|
goto ftype_rettype_loop
|
||||||
|
:ftype_rettype_loop_end
|
||||||
|
return type + 1
|
||||||
|
|
||||||
; NB: this takes a pointer to struct data, NOT a type
|
; NB: this takes a pointer to struct data, NOT a type
|
||||||
; Returns 1 if it's a union OR a struct with 1 member (we don't distinguish between these in any way)
|
; Returns 1 if it's a union OR a struct with 1 member (we don't distinguish between these in any way)
|
||||||
function structure_is_union
|
function structure_is_union
|
||||||
|
@ -201,6 +215,7 @@ function parse_toplevel_declaration
|
||||||
out = function_stmt_data + function_stmt_data_bytes_used
|
out = function_stmt_data + function_stmt_data_bytes_used
|
||||||
out0 = out
|
out0 = out
|
||||||
ident_list_add(function_statements, name, out)
|
ident_list_add(function_statements, name, out)
|
||||||
|
ident_list_add(function_types, name, type)
|
||||||
|
|
||||||
; deal with function parameters
|
; deal with function parameters
|
||||||
p = type + 1
|
p = type + 1
|
||||||
|
@ -1784,6 +1799,7 @@ function parse_type_declarators
|
||||||
|
|
||||||
:ftype_has_parameters
|
:ftype_has_parameters
|
||||||
:function_type_loop
|
:function_type_loop
|
||||||
|
if *1p == SYMBOL_DOTDOTDOT goto ftype_varargs
|
||||||
param_base_type = p
|
param_base_type = p
|
||||||
param_prefix = type_get_base_end(param_base_type)
|
param_prefix = type_get_base_end(param_base_type)
|
||||||
param_prefix_end = type_get_prefix_end(param_prefix)
|
param_prefix_end = type_get_prefix_end(param_prefix)
|
||||||
|
@ -1817,6 +1833,11 @@ function parse_type_declarators
|
||||||
if *1p != SYMBOL_COMMA goto parse_typedecls_bad_type
|
if *1p != SYMBOL_COMMA goto parse_typedecls_bad_type
|
||||||
p += 16
|
p += 16
|
||||||
goto function_type_loop
|
goto function_type_loop
|
||||||
|
:ftype_varargs
|
||||||
|
; ignore varargs
|
||||||
|
p += 16
|
||||||
|
if *1p != SYMBOL_RPAREN goto stuff_after_ftype_varargs
|
||||||
|
goto function_type_loop_end
|
||||||
:function_type_loop_end
|
:function_type_loop_end
|
||||||
if param_names_out == 0 goto ftype_skip_zpno
|
if param_names_out == 0 goto ftype_skip_zpno
|
||||||
*1param_names_out = 0
|
*1param_names_out = 0
|
||||||
|
@ -1834,6 +1855,11 @@ function parse_type_declarators
|
||||||
:str_no_param_name
|
:str_no_param_name
|
||||||
string Function parameter has no name.
|
string Function parameter has no name.
|
||||||
byte 0
|
byte 0
|
||||||
|
:stuff_after_ftype_varargs
|
||||||
|
token_error(p, .str_stuff_after_ftype_varargs)
|
||||||
|
:str_stuff_after_ftype_varargs
|
||||||
|
string Stuff after ... (varargs) in function type.
|
||||||
|
byte 0
|
||||||
:parse_type_remove_parentheses
|
:parse_type_remove_parentheses
|
||||||
; interestingly:
|
; interestingly:
|
||||||
; int (f(int x)) { return x * 2; }
|
; int (f(int x)) { return x * 2; }
|
||||||
|
@ -2551,12 +2577,37 @@ function parse_expression
|
||||||
bad_types_to_operator(tokens, *4a, *4b)
|
bad_types_to_operator(tokens, *4a, *4b)
|
||||||
|
|
||||||
:parse_call
|
:parse_call
|
||||||
*4type = TYPE_INT ; @TODO: proper typing
|
local arg_type
|
||||||
|
local param_type
|
||||||
|
; type call
|
||||||
|
b = types + *4a
|
||||||
|
if *1b == TYPE_FUNCTION goto type_call_cont
|
||||||
|
if *1b != TYPE_POINTER goto calling_nonfunction
|
||||||
|
b += 1 ; handle calling function pointer
|
||||||
|
if *1b != TYPE_FUNCTION goto calling_nonfunction
|
||||||
|
:type_call_cont
|
||||||
|
b -= types
|
||||||
|
*4type = functype_return_type(b)
|
||||||
|
param_type = b + 1
|
||||||
|
|
||||||
:call_args_loop
|
:call_args_loop
|
||||||
if *1p == SYMBOL_RPAREN goto call_args_loop_end
|
if *1p == SYMBOL_RPAREN goto call_args_loop_end
|
||||||
n = token_next_semicolon_comma_rbracket(p)
|
n = token_next_semicolon_comma_rbracket(p)
|
||||||
print_tokens(p, n)
|
arg_type = out + 4
|
||||||
out = parse_expression(p, n, out)
|
out = parse_expression(p, n, out)
|
||||||
|
b = types + param_type
|
||||||
|
if *1b == 0 goto arg_is_varargs ; reached the end of arguments (so presumably this function has varargs)
|
||||||
|
; set argument type to parameter type. this is necessary because:
|
||||||
|
; float f(float t) { return 2*t; }
|
||||||
|
; float g(int x) { return f(x); } <- x passed as a float
|
||||||
|
*4arg_type = param_type
|
||||||
|
param_type += type_length(param_type)
|
||||||
|
goto call_arg_type_cont
|
||||||
|
:arg_is_varargs
|
||||||
|
type_promote_float_to_double(*4arg_type)
|
||||||
|
type_decay_array_to_pointer(*4arg_type)
|
||||||
|
:call_arg_type_cont
|
||||||
|
|
||||||
p = n
|
p = n
|
||||||
if *1p == SYMBOL_RPAREN goto call_args_loop_end
|
if *1p == SYMBOL_RPAREN goto call_args_loop_end
|
||||||
if *1p != SYMBOL_COMMA goto bad_call
|
if *1p != SYMBOL_COMMA goto bad_call
|
||||||
|
@ -2565,9 +2616,16 @@ function parse_expression
|
||||||
:call_args_loop_end
|
:call_args_loop_end
|
||||||
p += 16
|
p += 16
|
||||||
if p != tokens_end goto stuff_after_call
|
if p != tokens_end goto stuff_after_call
|
||||||
|
|
||||||
|
|
||||||
*8out = 0
|
*8out = 0
|
||||||
out += 8
|
out += 8
|
||||||
return out
|
return out
|
||||||
|
:calling_nonfunction
|
||||||
|
token_error(p, .str_calling_nonfunction)
|
||||||
|
:str_calling_nonfunction
|
||||||
|
string Calling non-function.
|
||||||
|
byte 0
|
||||||
:bad_call
|
:bad_call
|
||||||
token_error(p, .str_bad_call)
|
token_error(p, .str_bad_call)
|
||||||
:str_bad_call
|
:str_bad_call
|
||||||
|
@ -2882,13 +2940,21 @@ function parse_expression
|
||||||
:not_global
|
:not_global
|
||||||
|
|
||||||
; it must be a function
|
; it must be a function
|
||||||
|
c = ident_list_lookup(function_types, a)
|
||||||
|
if c == 0 goto undeclared_function
|
||||||
*1out = EXPRESSION_FUNCTION
|
*1out = EXPRESSION_FUNCTION
|
||||||
out += 4
|
out += 4
|
||||||
*4out = TYPE_POINTER_TO_VOID
|
*4out = c
|
||||||
out += 4
|
out += 4
|
||||||
*8out = a
|
*8out = a
|
||||||
out += 8
|
out += 8
|
||||||
return out
|
return out
|
||||||
|
:undeclared_function
|
||||||
|
; @NONSTANDARD: C89 allows calling functions without declaring them
|
||||||
|
token_error(in, .str_undeclared_function)
|
||||||
|
:str_undeclared_function
|
||||||
|
string Undeclared function.
|
||||||
|
byte 0
|
||||||
|
|
||||||
:found_local_variable
|
:found_local_variable
|
||||||
; it's a local variable
|
; it's a local variable
|
||||||
|
@ -3011,6 +3077,17 @@ function type_decay_array_to_pointer
|
||||||
type_copy_ids(dest, src)
|
type_copy_ids(dest, src)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
; change type to `double` if it's `float`
|
||||||
|
; in C, float arguments have to be passed as double for varargs
|
||||||
|
; there is also a rule that char/short/int are passed as ints, but we don't need to worry about it since we're passing everything as >=8 bytes.
|
||||||
|
function type_promote_float_to_double
|
||||||
|
argument type
|
||||||
|
local p
|
||||||
|
p = types + type
|
||||||
|
if *1p != TYPE_FLOAT goto return_0
|
||||||
|
*1p = TYPE_DOUBLE
|
||||||
|
return
|
||||||
|
|
||||||
function type_sizeof
|
function type_sizeof
|
||||||
argument type
|
argument type
|
||||||
local p
|
local p
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue