cleanup - declaring functions without defining them, etc.
This commit is contained in:
parent
9372a72d43
commit
4b6fe5266a
3 changed files with 51 additions and 30 deletions
|
@ -49,9 +49,7 @@ global output_file_data
|
||||||
; ident list of global variables. each one is stored as
|
; ident list of global variables. each one is stored as
|
||||||
; (type << 32) | address
|
; (type << 32) | address
|
||||||
global global_variables
|
global global_variables
|
||||||
; ident list of functions. each entry is a pointer two statements
|
; ident list of functions. each entry is a pointer to a statement (specifically, a STATEMENT_BLOCK)
|
||||||
; - 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
|
global function_statements
|
||||||
; ident list mapping function names to function types (TYPE_FUNCTION {...})
|
; ident list mapping function names to function types (TYPE_FUNCTION {...})
|
||||||
global function_types
|
global function_types
|
||||||
|
|
13
05/main.c
13
05/main.c
|
@ -1,17 +1,24 @@
|
||||||
/* static int g; */
|
/* static int g; */
|
||||||
|
|
||||||
|
int G;
|
||||||
|
|
||||||
int f(int a, float x[], double y, ...) {
|
int f(int a, float x[], double y, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float * g() {
|
float * g(void);
|
||||||
}
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int b[] = {1,2,3};
|
int b[] = {1,2,3};
|
||||||
int a = f(1, 17, b, 36, 55.0, 22.3f);
|
int a = f(G, 17, b, 36, 55.0, 22.3f);
|
||||||
float *f = g(17.2, b);
|
float *f = g(17.2, b);
|
||||||
|
int *y;
|
||||||
|
y = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float *g () {
|
||||||
|
float j;
|
||||||
|
return &j;
|
||||||
|
}
|
||||||
/* int f(int x, int y[3]) { */
|
/* int f(int x, int y[3]) { */
|
||||||
/* int z = 17 +x; */
|
/* int z = 17 +x; */
|
||||||
/* int g[]={1,2,3,4,5}; */
|
/* int g[]={1,2,3,4,5}; */
|
||||||
|
|
62
05/parse.b
62
05/parse.b
|
@ -137,8 +137,22 @@ function parse_toplevel_declaration
|
||||||
rwdata_end_addr <= 3
|
rwdata_end_addr <= 3
|
||||||
|
|
||||||
token = suffix_end
|
token = suffix_end
|
||||||
if *1token == SYMBOL_LBRACE goto parse_function_definition
|
p = types + type
|
||||||
if is_extern != 0 goto parse_tl_decl_cont ; ignore external variable declarations
|
if *1p == TYPE_FUNCTION goto parse_function_declaration
|
||||||
|
|
||||||
|
; ignore external variable declarations
|
||||||
|
; @NONSTANDARD: this means we don't handle
|
||||||
|
; extern int X;
|
||||||
|
; int main() { printf("%d\n", X); }
|
||||||
|
; int X;
|
||||||
|
; correctly. There is no (good) way for us to handle this properly without two passes.
|
||||||
|
; Consider:
|
||||||
|
; extern int X[]; /* how many bytes to allocate? */
|
||||||
|
; int Y = 123; /* where do we put this? */
|
||||||
|
; int main() { printf("%d\n", Y); }
|
||||||
|
; int X[] = {1, 2, 3, 4}; /* 16 bytes (but it's too late) */
|
||||||
|
if is_extern != 0 goto parse_tl_decl_cont
|
||||||
|
|
||||||
; deal with the initializer if there is one
|
; deal with the initializer if there is one
|
||||||
if *1token == SYMBOL_SEMICOLON goto parse_tld_no_initializer
|
if *1token == SYMBOL_SEMICOLON goto parse_tld_no_initializer
|
||||||
if *1token == SYMBOL_COMMA goto parse_tld_no_initializer
|
if *1token == SYMBOL_COMMA goto parse_tld_no_initializer
|
||||||
|
@ -170,9 +184,18 @@ function parse_toplevel_declaration
|
||||||
:str_tld_bad_stuff_after_decl
|
:str_tld_bad_stuff_after_decl
|
||||||
string Declarations should be immediately followed by a comma or semicolon.
|
string Declarations should be immediately followed by a comma or semicolon.
|
||||||
byte 0
|
byte 0
|
||||||
|
:parse_function_declaration
|
||||||
|
b = ident_list_lookup(function_types, name)
|
||||||
|
if b != 0 goto function_decl_have_type ; e.g. function declared then defined
|
||||||
|
ident_list_add(function_types, name, type)
|
||||||
|
:function_decl_have_type
|
||||||
|
if *1token == SYMBOL_LBRACE goto parse_function_definition
|
||||||
|
if *1token == SYMBOL_SEMICOLON goto parse_tl_decl_cont
|
||||||
|
token_error(token, .str_bad_fdecl_suffix)
|
||||||
|
:str_bad_fdecl_suffix
|
||||||
|
string Expected semicolon or { after function declaration.
|
||||||
|
byte 0
|
||||||
:parse_tld_no_initializer
|
:parse_tld_no_initializer
|
||||||
p = types + type
|
|
||||||
if *1p == TYPE_FUNCTION goto parse_tl_decl_cont ; ignore function declarations -- we do two passes anyways
|
|
||||||
b = ident_list_lookup(static_vars, name)
|
b = ident_list_lookup(static_vars, name)
|
||||||
if b != 0 goto global_redefinition
|
if b != 0 goto global_redefinition
|
||||||
c = type < 32
|
c = type < 32
|
||||||
|
@ -215,7 +238,6 @@ 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
|
||||||
|
@ -237,24 +259,18 @@ function parse_toplevel_declaration
|
||||||
name += 1
|
name += 1
|
||||||
goto fn_params_loop
|
goto fn_params_loop
|
||||||
:fn_params_loop_end
|
:fn_params_loop_end
|
||||||
|
; NOTE: it's the caller's responsibility to properly set rsp to accomodate all the arguments.
|
||||||
write_statement_header(out, STATEMENT_LOCAL_DECLARATION, token)
|
; it needs to be this way because of varargs functions (the function doesn't know how many arguments there are).
|
||||||
out += 8
|
|
||||||
*8out = local_var_rbp_offset
|
|
||||||
out += 32
|
|
||||||
|
|
||||||
parse_statement(&token, &out)
|
parse_statement(&token, &out)
|
||||||
if block_depth != 0 goto stmtdepth_internal_err
|
if block_depth != 0 goto blockdepth_internal_err
|
||||||
function_stmt_data_bytes_used = out - function_stmt_data
|
function_stmt_data_bytes_used = out - function_stmt_data
|
||||||
print_statement(out0)
|
print_statement(out0)
|
||||||
out0 += 40
|
|
||||||
print_statement(out0)
|
|
||||||
goto parse_tld_ret
|
goto parse_tld_ret
|
||||||
|
|
||||||
:stmtdepth_internal_err
|
:blockdepth_internal_err
|
||||||
token_error(token, .str_stmtdepth_internal_err)
|
token_error(token, .str_blockdepth_internal_err)
|
||||||
:str_stmtdepth_internal_err
|
:str_blockdepth_internal_err
|
||||||
string Internal compiler error: parse_stmt_depth is not 0 after parsing function body.
|
string Internal compiler error: block_depth is not 0 after parsing function body.
|
||||||
byte 0
|
byte 0
|
||||||
:lbrace_after_declaration
|
:lbrace_after_declaration
|
||||||
token_error(token, .str_lbrace_after_declaration)
|
token_error(token, .str_lbrace_after_declaration)
|
||||||
|
@ -2941,7 +2957,7 @@ function parse_expression
|
||||||
|
|
||||||
; it must be a function
|
; it must be a function
|
||||||
c = ident_list_lookup(function_types, a)
|
c = ident_list_lookup(function_types, a)
|
||||||
if c == 0 goto undeclared_function
|
if c == 0 goto undeclared_variable
|
||||||
*1out = EXPRESSION_FUNCTION
|
*1out = EXPRESSION_FUNCTION
|
||||||
out += 4
|
out += 4
|
||||||
*4out = c
|
*4out = c
|
||||||
|
@ -2949,11 +2965,11 @@ function parse_expression
|
||||||
*8out = a
|
*8out = a
|
||||||
out += 8
|
out += 8
|
||||||
return out
|
return out
|
||||||
:undeclared_function
|
:undeclared_variable
|
||||||
; @NONSTANDARD: C89 allows calling functions without declaring them
|
; @NONSTANDARD: C89 allows calling functions without declaring them
|
||||||
token_error(in, .str_undeclared_function)
|
token_error(in, .str_undeclared_variable)
|
||||||
:str_undeclared_function
|
:str_undeclared_variable
|
||||||
string Undeclared function.
|
string Undeclared variable.
|
||||||
byte 0
|
byte 0
|
||||||
|
|
||||||
:found_local_variable
|
:found_local_variable
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue