summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--05/constants.b2
-rw-r--r--05/main.b6
-rw-r--r--05/main.c10
-rw-r--r--05/parse.b83
4 files changed, 93 insertions, 8 deletions
diff --git a/05/constants.b b/05/constants.b
index 93c2f5f..f8e15ba 100644
--- a/05/constants.b
+++ b/05/constants.b
@@ -222,7 +222,7 @@
; 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)}
; 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.
#define TYPE_VOID 1
#define TYPE_CHAR 3
diff --git a/05/main.b b/05/main.b
index 94ef526..d3e6f60 100644
--- a/05/main.b
+++ b/05/main.b
@@ -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 second one is the function body (a STATEMENT_BLOCK)
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[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)
@@ -232,8 +234,8 @@ function main
enumerators = ident_list_create(4000000)
structures = ident_list_create(4000000)
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
dat_banned_objmacros = 255
diff --git a/05/main.c b/05/main.c
index 17e4404..3d7b1ae 100644
--- a/05/main.c
+++ b/05/main.c
@@ -1,9 +1,15 @@
/* static int g; */
+int f(int a, float x[], double y, ...) {
+}
+
+float * g() {
+}
+
int main() {
- int a = exit;
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]) { */
diff --git a/05/parse.b b/05/parse.b
index 3cdbb41..f809db6 100644
--- a/05/parse.b
+++ b/05/parse.b
@@ -24,6 +24,20 @@ function token_is_type
if b != 0 goto return_1
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
; 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
@@ -201,6 +215,7 @@ function parse_toplevel_declaration
out = function_stmt_data + function_stmt_data_bytes_used
out0 = out
ident_list_add(function_statements, name, out)
+ ident_list_add(function_types, name, type)
; deal with function parameters
p = type + 1
@@ -1784,6 +1799,7 @@ function parse_type_declarators
:ftype_has_parameters
:function_type_loop
+ if *1p == SYMBOL_DOTDOTDOT goto ftype_varargs
param_base_type = p
param_prefix = type_get_base_end(param_base_type)
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
p += 16
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
if param_names_out == 0 goto ftype_skip_zpno
*1param_names_out = 0
@@ -1834,6 +1855,11 @@ function parse_type_declarators
:str_no_param_name
string Function parameter has no name.
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
; interestingly:
; int (f(int x)) { return x * 2; }
@@ -2551,12 +2577,37 @@ function parse_expression
bad_types_to_operator(tokens, *4a, *4b)
: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
if *1p == SYMBOL_RPAREN goto call_args_loop_end
n = token_next_semicolon_comma_rbracket(p)
- print_tokens(p, n)
+ arg_type = out + 4
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
if *1p == SYMBOL_RPAREN goto call_args_loop_end
if *1p != SYMBOL_COMMA goto bad_call
@@ -2565,9 +2616,16 @@ function parse_expression
:call_args_loop_end
p += 16
if p != tokens_end goto stuff_after_call
+
+
*8out = 0
out += 8
return out
+ :calling_nonfunction
+ token_error(p, .str_calling_nonfunction)
+ :str_calling_nonfunction
+ string Calling non-function.
+ byte 0
:bad_call
token_error(p, .str_bad_call)
:str_bad_call
@@ -2882,13 +2940,21 @@ function parse_expression
:not_global
; it must be a function
+ c = ident_list_lookup(function_types, a)
+ if c == 0 goto undeclared_function
*1out = EXPRESSION_FUNCTION
out += 4
- *4out = TYPE_POINTER_TO_VOID
+ *4out = c
out += 4
*8out = a
out += 8
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
; it's a local variable
@@ -3011,6 +3077,17 @@ function type_decay_array_to_pointer
type_copy_ids(dest, src)
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
argument type
local p