sprintf working! (but not snprintf ...)
This commit is contained in:
parent
2fef698195
commit
b9fd2a2b9c
7 changed files with 1724 additions and 65 deletions
43
05/codegen.b
43
05/codegen.b
|
@ -2741,18 +2741,25 @@ function generate_statement
|
|||
continue_refs = malloc(8000)
|
||||
break_refs = malloc(8000)
|
||||
|
||||
generate_push_expression_casted(statement, dat1, TYPE_VOID)
|
||||
emit_add_rsp_imm32(8) ; void is stored as 8 bytes
|
||||
if dat1 == 0 goto gen_for_no_expr1
|
||||
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
|
||||
p = dat2 + 4
|
||||
generate_push_expression(statement, dat2)
|
||||
generate_stack_compare_against_zero(statement, *4p)
|
||||
emit_je_rel32(0) ; je +0 (temporary)
|
||||
if dat2 == 0 goto gen_for_no_expr2
|
||||
generate_push_expression(statement, dat2)
|
||||
generate_stack_compare_against_zero(statement, *4p)
|
||||
emit_je_rel32(0) ; je +0 (temporary)
|
||||
:gen_for_no_dat2_cont
|
||||
addr1 = code_output
|
||||
generate_statement(dat4)
|
||||
generate_statement(dat4) ; body
|
||||
handle_refs(&continue_refs, prev_continue_refs, code_output)
|
||||
generate_push_expression_casted(statement, dat3, TYPE_VOID)
|
||||
emit_add_rsp_imm32(8) ; void is stored as 8 bytes
|
||||
if dat3 == 0 goto gen_for_no_expr3
|
||||
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)
|
||||
addr2 = code_output
|
||||
handle_refs(&break_refs, prev_break_refs, addr2)
|
||||
|
@ -2767,6 +2774,13 @@ function generate_statement
|
|||
p = addr2 - 4
|
||||
*4p = d
|
||||
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
|
||||
if continue_refs == 0 goto continue_outside_of_loop
|
||||
emit_jmp_rel32(0) ; jmp +0 (temporary)
|
||||
|
@ -2889,6 +2903,8 @@ function generate_function
|
|||
local out0
|
||||
local n_stack_bytes
|
||||
|
||||
debug_putsln(function_name)
|
||||
|
||||
function_type = ident_list_lookup(function_types, function_name)
|
||||
|
||||
curr_function_return_type = functype_return_type(function_type)
|
||||
|
@ -3015,11 +3031,13 @@ function generate_code
|
|||
local end_addr
|
||||
code_output = output_file_data + FUNCTIONS_ADDR
|
||||
codegen_second_pass = 0
|
||||
debug_puts(.str_first_pass)
|
||||
generate_functions()
|
||||
end_addr = code_output - output_file_data
|
||||
if end_addr ] FUNCTIONS_END goto too_much_code
|
||||
code_output = output_file_data + FUNCTIONS_ADDR
|
||||
codegen_second_pass = 1
|
||||
debug_puts(.str_second_pass)
|
||||
generate_functions()
|
||||
; generate code at the entry point of the executable
|
||||
local main_addr
|
||||
|
@ -3066,3 +3084,12 @@ function generate_code
|
|||
:str_too_much_code
|
||||
string Too much code for executable.
|
||||
byte 0
|
||||
:str_first_pass
|
||||
string First codegen pass...
|
||||
byte 0xa
|
||||
byte 0
|
||||
:str_second_pass
|
||||
string Second codegen pass...
|
||||
byte 0xa
|
||||
byte 0
|
||||
|
||||
|
|
14
05/main.b
14
05/main.b
|
@ -1,3 +1,5 @@
|
|||
#define G_DEBUG 0
|
||||
|
||||
; add 24 + 16 = 40 to the stack pointer to put argc, argv in the right place
|
||||
byte 0x48
|
||||
byte 0x81
|
||||
|
@ -8,7 +10,6 @@ byte 0
|
|||
byte 0
|
||||
goto main
|
||||
|
||||
|
||||
global object_macros_size
|
||||
global function_macros_size
|
||||
; these are allocated in main()
|
||||
|
@ -86,6 +87,15 @@ global functions_required_stack_space
|
|||
#include parse.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
|
||||
argument _types
|
||||
argument ptypes_bytes_used
|
||||
|
@ -208,7 +218,7 @@ function main
|
|||
local i
|
||||
local output_fd
|
||||
local memory
|
||||
|
||||
|
||||
memory = malloc(4000)
|
||||
statement_datas = memory
|
||||
statement_datas_ends = memory + 400
|
||||
|
|
52
05/main.c
52
05/main.c
|
@ -1,50 +1,10 @@
|
|||
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))
|
||||
|
||||
typedef unsigned long size_t;
|
||||
|
||||
long write(int fd, void *buf, size_t count) {
|
||||
__syscall(1, fd, buf, count, 0, 0, 0);
|
||||
}
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
write(1, "Hello, world!\n", 14);
|
||||
return 0;
|
||||
char buf[200] = {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;
|
||||
}
|
||||
|
||||
|
|
61
05/parse.b
61
05/parse.b
|
@ -276,6 +276,9 @@ function parse_toplevel_declaration
|
|||
p = types + type
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
; ENABLE/DISABLE PARSING DEBUG OUTPUT:
|
||||
if G_DEBUG == 0 goto skip_print_statement
|
||||
print_statement(out0)
|
||||
:skip_print_statement
|
||||
|
||||
goto parse_tld_ret
|
||||
|
||||
|
@ -348,6 +353,11 @@ function parse_toplevel_declaration
|
|||
:str_nested_function
|
||||
string Nested function.
|
||||
byte 0
|
||||
:function_redefinition
|
||||
token_error(token, .str_function_redefinition)
|
||||
:str_function_redefinition
|
||||
string Redefinition of function.
|
||||
byte 0
|
||||
:parse_typedef
|
||||
if block_depth > 0 goto local_typedef
|
||||
base_type = token + 16
|
||||
|
@ -1258,8 +1268,8 @@ function parse_constant_initializer
|
|||
expr = &dat_const_initializer
|
||||
parse_expression(token, end, expr)
|
||||
evaluate_constant_expression(token, expr, &value)
|
||||
if *1p == TYPE_FLOAT goto init_floating_check
|
||||
if *1p == TYPE_DOUBLE goto init_floating_check
|
||||
if *1p == TYPE_FLOAT goto init_float_check
|
||||
if *1p == TYPE_DOUBLE goto init_double_check
|
||||
:init_good
|
||||
token = end
|
||||
c = type_sizeof(type)
|
||||
|
@ -1289,10 +1299,25 @@ function parse_constant_initializer
|
|||
:write_initializer8
|
||||
*8p = value
|
||||
goto const_init_ret
|
||||
:init_floating_check ; we only support 0 as a floating-point initializer
|
||||
if value != 0 goto floating_initializer_other_than_0
|
||||
:init_double_check
|
||||
; check if someone did double x[] = {3};
|
||||
; 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
|
||||
*8p_token = token
|
||||
return
|
||||
|
@ -3498,8 +3523,9 @@ function type_alignof
|
|||
; evaluate an expression which can be the size of an array, e.g.
|
||||
; enum { A, B, C };
|
||||
; int x[A * sizeof(float) + 3 << 5];
|
||||
; @NONSTANDARD: doesn't handle floats. this means you can't do
|
||||
; e.g. double x[] = {1.5,2.3};
|
||||
; @NONSTANDARD: only allows double-precision floating-point literals or 0; otherwise floats aren't allowed in constant expressions.
|
||||
; 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
|
||||
; 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)
|
||||
|
@ -3520,8 +3546,15 @@ function evaluate_constant_expression
|
|||
c = *1expr
|
||||
|
||||
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_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_LOGICAL_NOT goto eval_logical_not
|
||||
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_CONDITIONAL goto eval_conditional
|
||||
|
||||
|
||||
:bad_constexpr
|
||||
token_error(token, .str_eval_bad_exprtype)
|
||||
|
||||
:str_eval_bad_exprtype
|
||||
|
@ -3555,7 +3588,6 @@ function evaluate_constant_expression
|
|||
p = types + type
|
||||
c = *1p
|
||||
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_DOUBLE 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
|
||||
string Bad type for constant cast (note: floating-point casts are not supported even though they are standard).
|
||||
byte 0
|
||||
:eval_constant_float
|
||||
expr += 8
|
||||
*8p_value = *8expr
|
||||
expr += 8
|
||||
return expr
|
||||
:eval_constant_int
|
||||
; @TODO : check if 0
|
||||
expr += 8
|
||||
*8p_value = *8expr
|
||||
expr += 8
|
||||
|
@ -3579,8 +3617,13 @@ function evaluate_constant_expression
|
|||
:eval_unary_minus
|
||||
expr += 8
|
||||
expr = evaluate_constant_expression(token, expr, &a)
|
||||
p = types + type
|
||||
if *1p == TYPE_DOUBLE goto eval_minus_double
|
||||
*8p_value = 0 - a
|
||||
goto eval_fit_to_type
|
||||
:eval_minus_double
|
||||
*8p_value = 0x8000000000000000 ^ a
|
||||
return expr
|
||||
:eval_bitwise_not
|
||||
expr += 8
|
||||
expr = evaluate_constant_expression(token, expr, &a)
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
#ifndef _STDARG_H
|
||||
#define _STDARG_H
|
||||
|
||||
typedef unsigned long va_list;
|
||||
|
||||
#define va_start(list, arg) ((list) = (unsigned long)&arg)
|
||||
#define va_arg(list, type) (*((type *)(list += ((sizeof(type) + 7) & 0xfffffffffffffff8))))
|
||||
#define va_end(list)
|
||||
|
||||
#endif // _STDARG_H
|
||||
|
|
66
05/stdc_common.h
Normal file
66
05/stdc_common.h
Normal 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
1547
05/stdio.h
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue