summaryrefslogtreecommitdiff
path: root/05/preprocess.b
diff options
context:
space:
mode:
Diffstat (limited to '05/preprocess.b')
-rw-r--r--05/preprocess.b69
1 files changed, 64 insertions, 5 deletions
diff --git a/05/preprocess.b b/05/preprocess.b
index ba4fdbf..2b5ca93 100644
--- a/05/preprocess.b
+++ b/05/preprocess.b
@@ -431,13 +431,18 @@ function translation_phase_4
if c == 10 goto phase4_next_line
b = isdigit(c)
if b != 0 goto phase4_next_pptoken
-
+ b = isalnum_or_underscore(c)
+ if b != 0 goto phase4_try_replacements
+ ; (fallthrough)
:phase4_next_pptoken
pptoken_copy_and_advance(&in, &out)
goto process_pptoken
:phase4_next_line
pptoken_copy_and_advance(&in, &out)
goto phase4_line
+ :phase4_try_replacements
+ macro_replacement(&in, &out)
+ goto phase4_line
:pp_directive
pptoken_skip(&in) ; skip #
pptoken_skip_spaces(&in)
@@ -477,8 +482,7 @@ function translation_phase_4
*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
+ goto phase4_next_line
:function_macro_definition
; a function-like macro, e.g. #define JOIN(a,b) a##b
local param_names
@@ -546,8 +550,7 @@ function translation_phase_4
p += 1
function_macros_size = p - function_macros
free(param_names)
- in += 2 ; skip newline and following null character
- goto phase4_line
+ goto phase4_next_line
:str_directive_error
string : #error
byte 10
@@ -605,6 +608,62 @@ function look_up_function_macro
argument name
return look_up_macro(function_macros, name)
+function macro_replacement
+ argument p_in
+ argument p_out
+ global 2000 dat_banned_macros ; 255-terminated array of strings (initialized in main)
+ local old_banned_macros_end
+ local banned_macros
+ local b
+ local p
+ local replacement
+ local in
+ local out
+
+ in = *8p_in
+ out = *8p_out
+
+ ; "banned" macros prevent #define x x from being a problem
+ ; C89 ยง 3.8.3.4
+ ; "If the name of the macro being replaced is found during this scan
+ ; of the replacement list, it is not replaced. Further, if any nested
+ ; replacements encounter the name of the macro being replaced, it is not replaced."
+
+ banned_macros = &dat_banned_macros
+ p = banned_macros
+
+ old_banned_macros_end = memchr(banned_macros, 255)
+
+ :check_banned_macros_loop
+ if *1p == 255 goto check_banned_macros_loop_end
+ b = str_equals(in, p)
+ if b != 0 goto no_replacement
+ p = memchr(p, 0)
+ p += 1
+ goto check_banned_macros_loop
+ :check_banned_macros_loop_end
+
+ p = strcpy(old_banned_macros_end, in)
+ p += 1
+ *1p = 255
+ replacement = look_up_object_macro(in)
+ if replacement == 0 goto no_replacement
+ p = replacement
+ pptoken_skip(&in)
+ :objreplace_loop
+ if *1p == 255 goto objreplace_loop_end
+ macro_replacement(&p, &out)
+ goto objreplace_loop
+ :no_replacement
+ pptoken_copy_and_advance(&in, &out)
+ ; (fallthrough)
+ :objreplace_loop_end
+ *8p_in = in
+ *8p_out = out
+ ; unban this macro
+ *1old_banned_macros_end = 255
+ return
+
function print_object_macros
print_macros(object_macros)
return