summaryrefslogtreecommitdiff
path: root/05/preprocess.b
diff options
context:
space:
mode:
Diffstat (limited to '05/preprocess.b')
-rw-r--r--05/preprocess.b153
1 files changed, 153 insertions, 0 deletions
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