summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--05/constants.b24
-rw-r--r--05/main.b18
-rw-r--r--05/main.c5
-rw-r--r--05/preprocess.b153
-rw-r--r--05/util.b49
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 <stdio.h>
+-#include <stdio.h>
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