From 3d0adb5f6fd92696513d332bfe17eb38f07f9499 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sat, 8 Jan 2022 14:37:39 -0500 Subject: start translation phase 4 --- 05/constants.b | 24 +++++++++ 05/main.b | 18 ++++++- 05/main.c | 5 +- 05/preprocess.b | 153 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 05/util.b | 49 +++++++++++++++++- 5 files changed, 245 insertions(+), 4 deletions(-) diff --git a/05/constants.b b/05/constants.b index 852d714..aab3b08 100644 --- a/05/constants.b +++ b/05/constants.b @@ -106,3 +106,27 @@ :str_hash_hash string ## byte 0 +:str_error + string error + byte 0 +:str_define + string define + byte 0 +:str_include + string include + byte 0 +:str_ifdef + string ifdef + byte 0 +:str_ifndef + string ifndef + byte 0 +:str_if + string if + byte 0 +:str_elif + string elif + byte 0 +:str_else + string else + byte 0 diff --git a/05/main.b b/05/main.b index 59a11a0..4b1a225 100644 --- a/05/main.b +++ b/05/main.b @@ -8,6 +8,13 @@ byte 0 byte 0 goto main + +global object_macros_size +global function_macros_size +; these are allocated in main() +global object_macros +global function_macros + function compile_error argument file argument line @@ -15,12 +22,12 @@ function compile_error fputs(2, file) fputc(2, ':) fputn(2, line) - fputs(2, .str_error) + fputs(2, .str_error_prefix) fputs(2, message) fputc(2, 10) exit(1) -:str_error +:str_error_prefix string : Error: byte 32 byte 0 @@ -38,6 +45,9 @@ function main local output_filename local pptokens + object_macros = malloc(4000000) + function_macros = malloc(4000000) + input_filename = .str_default_input_filename output_filename = .str_default_output_filename if argc == 1 goto have_filenames @@ -47,6 +57,10 @@ function main :have_filenames pptokens = split_into_preprocessing_tokens(input_filename) print_pptokens(pptokens) + print_separator() + pptokens = translation_phase_4(input_filename, pptokens) + ;print_pptokens(pptokens) + print_object_macros() exit(0) :usage_error diff --git a/05/main.c b/05/main.c index 3a38edf..cbe77ed 100644 --- a/05/main.c +++ b/05/main.c @@ -1,10 +1,13 @@ -#include +-#include int test(int, double, ...);\ /* here is a nice comment it is here */ +# +#define A 33 +#define _Hello_there5 -76 + sqrt(A) int main(void) { printf("\"Hello, world!%c\n\"", '\''); _X55 = Y4_C_; diff --git a/05/preprocess.b b/05/preprocess.b index ddc0c3b..0be0bc9 100644 --- a/05/preprocess.b +++ b/05/preprocess.b @@ -360,3 +360,156 @@ function print_pptokens :print_pptokens_loop_end putc(10) return + +function pptoken_copy_and_advance + argument p_in + argument p_out + local in + local out + in = *8p_in + out = *8p_out + out = strcpy(out, in) + in = memchr(in, 0) + *8p_in = in + 1 + *8p_out = out + 1 + return + +function pptoken_skip + argument p_in + local in + in = *8p_in + in = memchr(in, 0) + *8p_in = in + 1 + return + +; skip any space tokens here +function pptoken_skip_spaces + argument p_in + local in + in = *8p_in + :pptoken_skip_spaces_loop + if *1in != 32 goto pptoken_skip_spaces_loop_end + pptoken_skip(&in) + goto pptoken_skip_spaces_loop + :pptoken_skip_spaces_loop_end + *8p_in = in + return + +; phase 4: +; Preprocessing directives are executed and macro invocations are expanded. +; A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively. +function translation_phase_4 + argument filename + argument input + local output + local in + local out + local p + local c + local b + local line_number + + output = malloc(16000000) + out = output + in = input + line_number = 0 + + :phase4_line + line_number += 1 + c = *1in + if c == 0 goto phase4_end + if c == '# goto pp_directive ; NOTE: ## cannot appear at the start of a line + + :process_pptoken + c = *1in + if c == 10 goto phase4_next_line + b = isdigit(c) + if b != 0 goto phase4_next_pptoken + + :phase4_next_pptoken + pptoken_copy_and_advance(&in, &out) + goto process_pptoken + :phase4_next_line + pptoken_copy_and_advance(&in, &out) + goto phase4_line + :pp_directive + pptoken_skip(&in) + c = *1in + if c == 10 goto phase4_next_line ; "null directive" C89 ยง 3.8.7 + b = str_equals(in, .str_error) + if b != 0 goto pp_directive_error + b = str_equals(in, .str_define) + if b != 0 goto pp_directive_define + goto unrecognized_directive + :pp_directive_error + fputs(2, filename) + fputc(2, ':) + fputn(2, line_number) + fputs(2, .str_directive_error) + exit(1) + :pp_directive_define + local macro_name + pptoken_skip(&in) + pptoken_skip_spaces(&in) + macro_name = in + pptoken_skip(&in) + c = *1in + if c == '( goto function_macro_definition + ; it's an object-like macro, e.g. #define X 47 + p = object_macros + object_macros_size + ; copy name + p = strcpy(p, macro_name) + p += 1 + ; copy contents + memccpy_advance(&p, &in, 10) ; copy until newline + *1p = 255 ; replace newline with special "macro end" character + p += 1 + object_macros_size = p - object_macros + in += 2 ; skip newline and following null character + goto phase4_line + :function_macro_definition + ; a function-like macro, e.g. #define JOIN(a,b) a##b + byte 0xcc + :str_directive_error + string : #error + byte 10 + byte 0 + :phase4_end + return output + :unrecognized_directive + compile_error(filename, line_number, .str_unrecognized_directive) + :str_unrecognized_directive + string Unrecognized preprocessor directive. + byte 0 + +function look_up_object_macro + argument name + local p + p = object_macros + :objmacro_lookup_loop + @TODO + +function print_object_macros + local p + local c + p = object_macros + :print_objmacros_loop + if *1p == 0 goto return_0 ; done! + puts(p) + putc(':) + putc(32) + p = memchr(p, 0) + p += 1 + :print_objreplacement_loop + putc('{) + puts(p) + putc('}) + p = memchr(p, 0) + p += 1 + c = *1p + if c == 255 goto print_objreplacement_loop_end + goto print_objreplacement_loop + :print_objreplacement_loop_end + p += 1 + fputc(1, 10) + goto print_objmacros_loop diff --git a/05/util.b b/05/util.b index c8f2851..24c072f 100644 --- a/05/util.b +++ b/05/util.b @@ -90,6 +90,28 @@ function memchr :memchr_loop_end return p +; copy from *p_src to *p_dest until terminator is reached, setting both to point to their respective terminators +function memccpy_advance + argument p_dest + argument p_src + argument terminator + local src + local dest + local c + src = *8p_src + dest = *8p_dest + :memccpy_advance_loop + c = *1src + *1dest = c + if c == terminator goto memccpy_advance_loop_end + src += 1 + dest += 1 + goto memccpy_advance_loop + :memccpy_advance_loop_end + *8p_src = src + *8p_dest = dest + return + function strlen argument s local p @@ -101,6 +123,7 @@ function strlen :strlen_loop_end return p - s +; like C strcpy, but returns a pointer to the terminating null character in dest function strcpy argument dest argument src @@ -118,7 +141,21 @@ function strcpy goto strcpy_loop :strcpy_loop_end return p - + +function str_equals + argument a + argument b + local c + local d + :str_equals_loop + c = *1a + d = *1b + if c != d goto return_0 + if c == 0 goto return_1 + a += 1 + b += 1 + goto str_equals_loop + function str_startswith argument s argument prefix @@ -150,6 +187,16 @@ function puts fputs(1, s) return +function print_separator + fputs(1, .str_separator) + return + +:str_separator + byte 10 + string ------------------------------------------------ + byte 10 + byte 0 + function fputn argument fd argument n -- cgit v1.2.3