sprintf working! (but not snprintf ...)

This commit is contained in:
pommicket 2022-02-13 22:12:44 -05:00
parent 2fef698195
commit b9fd2a2b9c
7 changed files with 1724 additions and 65 deletions

View file

@ -2741,18 +2741,25 @@ function generate_statement
continue_refs = malloc(8000) continue_refs = malloc(8000)
break_refs = malloc(8000) break_refs = malloc(8000)
generate_push_expression_casted(statement, dat1, TYPE_VOID) if dat1 == 0 goto gen_for_no_expr1
emit_add_rsp_imm32(8) ; void is stored as 8 bytes generate_push_expression_casted(statement, dat1, TYPE_VOID)
emit_add_rsp_imm32(8) ; void is stored as 8 bytes
:gen_for_no_expr1
addr0 = code_output addr0 = code_output
p = dat2 + 4 p = dat2 + 4
generate_push_expression(statement, dat2) if dat2 == 0 goto gen_for_no_expr2
generate_stack_compare_against_zero(statement, *4p) generate_push_expression(statement, dat2)
emit_je_rel32(0) ; je +0 (temporary) generate_stack_compare_against_zero(statement, *4p)
emit_je_rel32(0) ; je +0 (temporary)
:gen_for_no_dat2_cont
addr1 = code_output addr1 = code_output
generate_statement(dat4) generate_statement(dat4) ; body
handle_refs(&continue_refs, prev_continue_refs, code_output) handle_refs(&continue_refs, prev_continue_refs, code_output)
generate_push_expression_casted(statement, dat3, TYPE_VOID) if dat3 == 0 goto gen_for_no_expr3
emit_add_rsp_imm32(8) ; void is stored as 8 bytes generate_push_expression_casted(statement, dat3, TYPE_VOID)
emit_add_rsp_imm32(8) ; void is stored as 8 bytes
:gen_for_no_expr3
emit_jmp_rel32(0) ; jmp +0 (temporary) emit_jmp_rel32(0) ; jmp +0 (temporary)
addr2 = code_output addr2 = code_output
handle_refs(&break_refs, prev_break_refs, addr2) handle_refs(&break_refs, prev_break_refs, addr2)
@ -2767,6 +2774,13 @@ function generate_statement
p = addr2 - 4 p = addr2 - 4
*4p = d *4p = d
return return
:gen_for_no_expr2
; we need to have a fake jump to be filled in here
; so let's make a jump that'll never happen
emit_zero_rax() ; xor eax, eax
emit_test_rax_rax() ; test rax, rax
emit_jne_rel32(0) ; jne +0 (temporary)
goto gen_for_no_dat2_cont
:gen_stmt_continue :gen_stmt_continue
if continue_refs == 0 goto continue_outside_of_loop if continue_refs == 0 goto continue_outside_of_loop
emit_jmp_rel32(0) ; jmp +0 (temporary) emit_jmp_rel32(0) ; jmp +0 (temporary)
@ -2889,6 +2903,8 @@ function generate_function
local out0 local out0
local n_stack_bytes local n_stack_bytes
debug_putsln(function_name)
function_type = ident_list_lookup(function_types, function_name) function_type = ident_list_lookup(function_types, function_name)
curr_function_return_type = functype_return_type(function_type) curr_function_return_type = functype_return_type(function_type)
@ -3015,11 +3031,13 @@ function generate_code
local end_addr local end_addr
code_output = output_file_data + FUNCTIONS_ADDR code_output = output_file_data + FUNCTIONS_ADDR
codegen_second_pass = 0 codegen_second_pass = 0
debug_puts(.str_first_pass)
generate_functions() generate_functions()
end_addr = code_output - output_file_data end_addr = code_output - output_file_data
if end_addr ] FUNCTIONS_END goto too_much_code if end_addr ] FUNCTIONS_END goto too_much_code
code_output = output_file_data + FUNCTIONS_ADDR code_output = output_file_data + FUNCTIONS_ADDR
codegen_second_pass = 1 codegen_second_pass = 1
debug_puts(.str_second_pass)
generate_functions() generate_functions()
; generate code at the entry point of the executable ; generate code at the entry point of the executable
local main_addr local main_addr
@ -3066,3 +3084,12 @@ function generate_code
:str_too_much_code :str_too_much_code
string Too much code for executable. string Too much code for executable.
byte 0 byte 0
:str_first_pass
string First codegen pass...
byte 0xa
byte 0
:str_second_pass
string Second codegen pass...
byte 0xa
byte 0

View file

@ -1,3 +1,5 @@
#define G_DEBUG 0
; add 24 + 16 = 40 to the stack pointer to put argc, argv in the right place ; add 24 + 16 = 40 to the stack pointer to put argc, argv in the right place
byte 0x48 byte 0x48
byte 0x81 byte 0x81
@ -8,7 +10,6 @@ byte 0
byte 0 byte 0
goto main goto main
global object_macros_size global object_macros_size
global function_macros_size global function_macros_size
; these are allocated in main() ; these are allocated in main()
@ -86,6 +87,15 @@ global functions_required_stack_space
#include parse.b #include parse.b
#include codegen.b #include codegen.b
function debug_puts
argument str
if G_DEBUG == 0 goto return_0
return puts(str)
function debug_putsln
argument str
if G_DEBUG == 0 goto return_0
return putsln(str)
function types_init function types_init
argument _types argument _types
argument ptypes_bytes_used argument ptypes_bytes_used

View file

@ -1,50 +1,10 @@
static unsigned char __syscall_data[] = { #include <stdio.h>
// mov rax, [rsp+24]
0x48, 0x8b, 0x84, 0x24, 24, 0, 0, 0,
// mov rdi, rax
0x48, 0x89, 0xc7,
// mov rax, [rsp+32]
0x48, 0x8b, 0x84, 0x24, 32, 0, 0, 0,
// mov rsi, rax
0x48, 0x89, 0xc6,
// mov rax, [rsp+40]
0x48, 0x8b, 0x84, 0x24, 40, 0, 0, 0,
// mov rdx, rax
0x48, 0x89, 0xc2,
// mov rax, [rsp+48]
0x48, 0x8b, 0x84, 0x24, 48, 0, 0, 0,
// mov r10, rax
0x49, 0x89, 0xc2,
// mov rax, [rsp+56]
0x48, 0x8b, 0x84, 0x24, 56, 0, 0, 0,
// mov r8, rax
0x49, 0x89, 0xc0,
// mov rax, [rsp+64]
0x48, 0x8b, 0x84, 0x24, 64, 0, 0, 0,
// mov r9, rax
0x49, 0x89, 0xc1,
// mov rax, [rsp+16]
0x48, 0x8b, 0x84, 0x24, 16, 0, 0, 0,
// syscall
0x0f, 0x05,
// mov [rsp+8], rax
0x48, 0x89, 0x84, 0x24, 8, 0, 0, 0,
// ret
0xc3
};
#define __syscall(no, arg1, arg2, arg3, arg4, arg5, arg6)\
(((unsigned long (*)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long))__syscall_data)\
(no, arg1, arg2, arg3, arg4, arg5, arg6))
typedef unsigned long size_t;
long write(int fd, void *buf, size_t count) {
__syscall(1, fd, buf, count, 0, 0, 0);
}
int main(int argc, char **argv) { int main(int argc, char **argv) {
write(1, "Hello, world!\n", 14); char buf[200] = {0};
return 0; sprintf(buf, "Hello, %d %.2f %g %s %p\n", 187, 77.3, 349e12, "Wow!", "yea");
// snprintf(buf, 200, "Hello\n"); //<- NOT WORKING
write(1, buf, sizeof buf);
return *buf;
} }

View file

@ -276,6 +276,9 @@ function parse_toplevel_declaration
p = types + type p = types + type
if *1p != TYPE_FUNCTION goto lbrace_after_declaration if *1p != TYPE_FUNCTION goto lbrace_after_declaration
c = ident_list_lookup(function_statements, name)
if c != 0 goto function_redefinition
ret_type = functype_return_type(type) ret_type = functype_return_type(type)
global function_stmt_data ; initialized in main global function_stmt_data ; initialized in main
@ -324,7 +327,9 @@ function parse_toplevel_declaration
ident_list_add(functions_required_stack_space, f_name, curr_function_stack_space) ident_list_add(functions_required_stack_space, f_name, curr_function_stack_space)
; ENABLE/DISABLE PARSING DEBUG OUTPUT: ; ENABLE/DISABLE PARSING DEBUG OUTPUT:
if G_DEBUG == 0 goto skip_print_statement
print_statement(out0) print_statement(out0)
:skip_print_statement
goto parse_tld_ret goto parse_tld_ret
@ -348,6 +353,11 @@ function parse_toplevel_declaration
:str_nested_function :str_nested_function
string Nested function. string Nested function.
byte 0 byte 0
:function_redefinition
token_error(token, .str_function_redefinition)
:str_function_redefinition
string Redefinition of function.
byte 0
:parse_typedef :parse_typedef
if block_depth > 0 goto local_typedef if block_depth > 0 goto local_typedef
base_type = token + 16 base_type = token + 16
@ -1258,8 +1268,8 @@ function parse_constant_initializer
expr = &dat_const_initializer expr = &dat_const_initializer
parse_expression(token, end, expr) parse_expression(token, end, expr)
evaluate_constant_expression(token, expr, &value) evaluate_constant_expression(token, expr, &value)
if *1p == TYPE_FLOAT goto init_floating_check if *1p == TYPE_FLOAT goto init_float_check
if *1p == TYPE_DOUBLE goto init_floating_check if *1p == TYPE_DOUBLE goto init_double_check
:init_good :init_good
token = end token = end
c = type_sizeof(type) c = type_sizeof(type)
@ -1289,10 +1299,25 @@ function parse_constant_initializer
:write_initializer8 :write_initializer8
*8p = value *8p = value
goto const_init_ret goto const_init_ret
:init_floating_check ; we only support 0 as a floating-point initializer :init_double_check
if value != 0 goto floating_initializer_other_than_0 ; check if someone did double x[] = {3};
goto init_good ; we would screw this up and set x[0] to the binary representation of 3 as an integer
if value == 0 goto init_good ; 0 is fine
; this isn't foolproof, but it should work most of the time
if value [ 0x10000000000000 goto bad_float_initializer
if value ] 0xfff0000000000000 goto bad_float_initializer
goto init_good
:init_float_check
if value == 0 goto init_good
goto bad_float_initializer
:bad_float_initializer
token_error(token, .str_bad_float_initializer)
:str_bad_float_initializer
string Bad floating-point initializer.
byte 0
:const_init_ret :const_init_ret
*8p_token = token *8p_token = token
return return
@ -3498,8 +3523,9 @@ function type_alignof
; evaluate an expression which can be the size of an array, e.g. ; evaluate an expression which can be the size of an array, e.g.
; enum { A, B, C }; ; enum { A, B, C };
; int x[A * sizeof(float) + 3 << 5]; ; int x[A * sizeof(float) + 3 << 5];
; @NONSTANDARD: doesn't handle floats. this means you can't do ; @NONSTANDARD: only allows double-precision floating-point literals or 0; otherwise floats aren't allowed in constant expressions.
; e.g. double x[] = {1.5,2.3}; ; this means you can't do
; e.g. float x[] = {1,2,3}; or double x[] = {1.5+2.3, 5.5*6.4};
; this is also used for #if evaluation ; this is also used for #if evaluation
; token is used for error messages (e.g. if this "constant" expression is *x or something) ; token is used for error messages (e.g. if this "constant" expression is *x or something)
; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value) ; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value)
@ -3520,8 +3546,15 @@ function evaluate_constant_expression
c = *1expr c = *1expr
if c == EXPRESSION_CONSTANT_INT goto eval_constant_int if c == EXPRESSION_CONSTANT_INT goto eval_constant_int
p = types + type
if *1p == TYPE_FLOAT goto bad_constexpr
if c == EXPRESSION_CONSTANT_FLOAT goto eval_constant_float
if c == EXPRESSION_UNARY_PLUS goto eval_unary_plus if c == EXPRESSION_UNARY_PLUS goto eval_unary_plus
if c == EXPRESSION_UNARY_MINUS goto eval_unary_minus if c == EXPRESSION_UNARY_MINUS goto eval_unary_minus
; only 0 and floating-point constants are supported as double initializers
if *1p == TYPE_DOUBLE goto bad_constexpr
if c == EXPRESSION_BITWISE_NOT goto eval_bitwise_not if c == EXPRESSION_BITWISE_NOT goto eval_bitwise_not
if c == EXPRESSION_LOGICAL_NOT goto eval_logical_not if c == EXPRESSION_LOGICAL_NOT goto eval_logical_not
if c == EXPRESSION_CAST goto eval_cast if c == EXPRESSION_CAST goto eval_cast
@ -3545,7 +3578,7 @@ function evaluate_constant_expression
if c == EXPRESSION_LOGICAL_OR goto eval_logical_or if c == EXPRESSION_LOGICAL_OR goto eval_logical_or
if c == EXPRESSION_CONDITIONAL goto eval_conditional if c == EXPRESSION_CONDITIONAL goto eval_conditional
:bad_constexpr
token_error(token, .str_eval_bad_exprtype) token_error(token, .str_eval_bad_exprtype)
:str_eval_bad_exprtype :str_eval_bad_exprtype
@ -3555,7 +3588,6 @@ function evaluate_constant_expression
p = types + type p = types + type
c = *1p c = *1p
if c == TYPE_VOID goto eval_cast_bad_type if c == TYPE_VOID goto eval_cast_bad_type
; @NONSTANDARD: we don't support, for example, int x[(int)(float)5];
if c == TYPE_FLOAT goto eval_cast_bad_type if c == TYPE_FLOAT goto eval_cast_bad_type
if c == TYPE_DOUBLE goto eval_cast_bad_type if c == TYPE_DOUBLE goto eval_cast_bad_type
if c > TYPE_POINTER goto eval_cast_bad_type if c > TYPE_POINTER goto eval_cast_bad_type
@ -3567,7 +3599,13 @@ function evaluate_constant_expression
:str_eval_cast_bad_type :str_eval_cast_bad_type
string Bad type for constant cast (note: floating-point casts are not supported even though they are standard). string Bad type for constant cast (note: floating-point casts are not supported even though they are standard).
byte 0 byte 0
:eval_constant_float
expr += 8
*8p_value = *8expr
expr += 8
return expr
:eval_constant_int :eval_constant_int
; @TODO : check if 0
expr += 8 expr += 8
*8p_value = *8expr *8p_value = *8expr
expr += 8 expr += 8
@ -3579,8 +3617,13 @@ function evaluate_constant_expression
:eval_unary_minus :eval_unary_minus
expr += 8 expr += 8
expr = evaluate_constant_expression(token, expr, &a) expr = evaluate_constant_expression(token, expr, &a)
p = types + type
if *1p == TYPE_DOUBLE goto eval_minus_double
*8p_value = 0 - a *8p_value = 0 - a
goto eval_fit_to_type goto eval_fit_to_type
:eval_minus_double
*8p_value = 0x8000000000000000 ^ a
return expr
:eval_bitwise_not :eval_bitwise_not
expr += 8 expr += 8
expr = evaluate_constant_expression(token, expr, &a) expr = evaluate_constant_expression(token, expr, &a)

View file

@ -1,4 +1,10 @@
#ifndef _STDARG_H
#define _STDARG_H
typedef unsigned long va_list; typedef unsigned long va_list;
#define va_start(list, arg) ((list) = (unsigned long)&arg) #define va_start(list, arg) ((list) = (unsigned long)&arg)
#define va_arg(list, type) (*((type *)(list += ((sizeof(type) + 7) & 0xfffffffffffffff8)))) #define va_arg(list, type) (*((type *)(list += ((sizeof(type) + 7) & 0xfffffffffffffff8))))
#define va_end(list) #define va_end(list)
#endif // _STDARG_H

66
05/stdc_common.h Normal file
View file

@ -0,0 +1,66 @@
#ifndef _STDC_COMMON_H
#define _STDC_COMMON_H
#define signed
#define volatile
#define register
#define const
typedef unsigned char uint8_t;
typedef char int8_t;
typedef unsigned short uint16_t;
typedef short int16_t;
typedef unsigned int uint32_t;
typedef int int32_t;
typedef unsigned long uint64_t;
typedef long int64_t;
typedef unsigned long size_t;
typedef long ptrdiff_t;
typedef unsigned long uintptr_t;
typedef long intptr_t;
static unsigned char __syscall_data[] = {
// mov rax, [rsp+24]
0x48, 0x8b, 0x84, 0x24, 24, 0, 0, 0,
// mov rdi, rax
0x48, 0x89, 0xc7,
// mov rax, [rsp+32]
0x48, 0x8b, 0x84, 0x24, 32, 0, 0, 0,
// mov rsi, rax
0x48, 0x89, 0xc6,
// mov rax, [rsp+40]
0x48, 0x8b, 0x84, 0x24, 40, 0, 0, 0,
// mov rdx, rax
0x48, 0x89, 0xc2,
// mov rax, [rsp+48]
0x48, 0x8b, 0x84, 0x24, 48, 0, 0, 0,
// mov r10, rax
0x49, 0x89, 0xc2,
// mov rax, [rsp+56]
0x48, 0x8b, 0x84, 0x24, 56, 0, 0, 0,
// mov r8, rax
0x49, 0x89, 0xc0,
// mov rax, [rsp+64]
0x48, 0x8b, 0x84, 0x24, 64, 0, 0, 0,
// mov r9, rax
0x49, 0x89, 0xc1,
// mov rax, [rsp+16]
0x48, 0x8b, 0x84, 0x24, 16, 0, 0, 0,
// syscall
0x0f, 0x05,
// mov [rsp+8], rax
0x48, 0x89, 0x84, 0x24, 8, 0, 0, 0,
// ret
0xc3
};
#define __syscall(no, arg1, arg2, arg3, arg4, arg5, arg6)\
(((unsigned long (*)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long))__syscall_data)\
(no, arg1, arg2, arg3, arg4, arg5, arg6))
long write(int fd, void *buf, size_t count) {
__syscall(1, fd, buf, count, 0, 0, 0);
}
#endif // _STDC_COMMON_H

1547
05/stdio.h Normal file

File diff suppressed because it is too large Load diff