reading function-like macros

This commit is contained in:
pommicket 2022-01-08 18:13:48 -05:00
parent 3d0adb5f6f
commit 4d5a5d9d97
4 changed files with 162 additions and 16 deletions

View file

@ -61,6 +61,7 @@ function main
pptokens = translation_phase_4(input_filename, pptokens)
;print_pptokens(pptokens)
print_object_macros()
print_function_macros()
exit(0)
:usage_error

View file

@ -6,7 +6,11 @@ comment it is
here
*/
#
#define A 33
#define A(_Hello, there, everyone ) 33 + _Hello - everyone * there
#define B(x, y, z) 58
#define C(hello) hello * hello + hello / hello
#define A 22
#define C 33
#define _Hello_there5 -76 + sqrt(A)
int main(void) {
printf("\"Hello, world!%c\n\"", '\'');
@ -15,3 +19,4 @@ int main(void) {
5 + (.3e+5+6) & 0xff | 93 -~5;
return 0;
}
#define _Hello_there 18

View file

@ -23,6 +23,8 @@ function split_into_preprocessing_tokens
p += n
goto pptokens_read_loop
:pptokens_read_loop_end
p -= 1
if *1p != 10 goto no_newline_at_end_of_file
; okay we read the file. first, delete every backslash-newline sequence (phase 2)
local newlines ; we add more newlines to keep line numbers right
@ -331,7 +333,11 @@ function split_into_preprocessing_tokens
:str_bad_pptoken
string Bad preprocessing token.
byte 0
:no_newline_at_end_of_file
compile_error(filename, 0, .str_no_newline_at_end_of_file)
:str_no_newline_at_end_of_file
string No newline at end of file.
byte 0
; can the given character appear in a C89 ppnumber?
function is_ppnumber_char
argument c
@ -433,7 +439,8 @@ function translation_phase_4
pptoken_copy_and_advance(&in, &out)
goto phase4_line
:pp_directive
pptoken_skip(&in)
pptoken_skip(&in) ; skip #
pptoken_skip_spaces(&in)
c = *1in
if c == 10 goto phase4_next_line ; "null directive" C89 § 3.8.7
b = str_equals(in, .str_error)
@ -453,9 +460,14 @@ function translation_phase_4
pptoken_skip_spaces(&in)
macro_name = in
pptoken_skip(&in)
pptoken_skip_spaces(&in)
c = *1in
if c == '( goto function_macro_definition
; it's an object-like macro, e.g. #define X 47
b = look_up_object_macro(macro_name)
if b != 0 goto macro_redefinition
p = object_macros + object_macros_size
; copy name
p = strcpy(p, macro_name)
@ -469,7 +481,73 @@ function translation_phase_4
goto phase4_line
:function_macro_definition
; a function-like macro, e.g. #define JOIN(a,b) a##b
byte 0xcc
local param_names
local param_name
local param_idx
b = look_up_function_macro(macro_name)
if b != 0 goto macro_redefinition
param_names = malloc(4000)
pptoken_skip(&in) ; skip opening parenthesis
pptoken_skip_spaces(&in)
param_name = param_names
:macro_params_loop
c = *1in
if c == 10 goto missing_closing_bracket
b = isalpha_or_underscore(c)
if b == 0 goto bad_macro_params
param_name = strcpy(param_name, in)
param_name += 1
pptoken_skip(&in)
pptoken_skip_spaces(&in)
c = *1in
if c == ') goto macro_params_loop_end
if c != ', goto bad_macro_params
pptoken_skip(&in) ; skip ,
pptoken_skip_spaces(&in)
goto macro_params_loop
:macro_params_loop_end
pptoken_skip(&in) ; skip )
pptoken_skip_spaces(&in)
p = function_macros + function_macros_size
p = strcpy(p, macro_name)
p += 1
:fmacro_body_loop
if *1in == 10 goto fmacro_body_loop_end
param_name = param_names
param_idx = 1
; check if this token matches any of the parameter names
:fmacro_param_check_loop
if *1param_name == 0 goto fmacro_param_check_loop_end
b = str_equals(in, param_name)
if b != 0 goto fmacro_param_match
param_name = memchr(param_name, 0)
param_name += 1
param_idx += 1
goto fmacro_param_check_loop
:fmacro_param_check_loop_end
; it's not a parameter; just copy it out
p = strcpy(p, in)
p += 1
pptoken_skip(&in)
goto fmacro_body_loop
:fmacro_param_match
; a match!
*1p = param_idx ; store the parameter index (1 = first argument) as a pptoken
p += 2
pptoken_skip(&in)
goto fmacro_body_loop
:fmacro_body_loop_end
*1p = 255
p += 1
function_macros_size = p - function_macros
free(param_names)
in += 2 ; skip newline and following null character
goto phase4_line
:str_directive_error
string : #error
byte 10
@ -481,35 +559,92 @@ function translation_phase_4
:str_unrecognized_directive
string Unrecognized preprocessor directive.
byte 0
:macro_redefinition
; technically not an error if it was redefined to the same thing, but it's
; annoying to check for that
compile_error(filename, line_number, .str_macro_redefinition)
:str_macro_redefinition
string Macro redefinition.
byte 0
:missing_closing_bracket
compile_error(filename, line_number, .str_missing_closing_bracket)
:str_missing_closing_bracket
string Missing closing ).
byte 0
:bad_macro_params
compile_error(filename, line_number, .str_bad_macro_params)
:str_bad_macro_params
string Bad macro parameter list.
byte 0
; returns a pointer to the replacement pptokens, or 0 if this macro is not defined
function look_up_macro
argument macros
argument name
local p
local b
p = macros
:macro_lookup_loop
if *1p == 0 goto return_0
b = str_equals(p, name)
if b != 0 goto macro_lookup_loop_end
; advance to next macro
p = memchr(p, 255)
p += 1
goto macro_lookup_loop
:macro_lookup_loop_end
p = memchr(p, 0)
p += 1
return p
function look_up_object_macro
argument name
local p
p = object_macros
:objmacro_lookup_loop
@TODO
return look_up_macro(object_macros, name)
function look_up_function_macro
argument name
return look_up_macro(function_macros, name)
function print_object_macros
print_macros(object_macros)
return
function print_function_macros
print_macros(function_macros)
return
function print_macros
argument macros
local p
local c
p = object_macros
:print_objmacros_loop
p = macros
:print_macros_loop
if *1p == 0 goto return_0 ; done!
puts(p)
putc(':)
putc(32)
p = memchr(p, 0)
p += 1
:print_objreplacement_loop
:print_replacement_loop
c = *1p
if c == 255 goto print_replacement_loop_end
if c < 32 goto print_macro_param
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
goto print_replacement_loop
:print_macro_param
putc('{)
putc('#)
putn(c)
putc('})
p += 2
goto print_replacement_loop
:print_replacement_loop_end
p += 1
fputc(1, 10)
goto print_objmacros_loop
goto print_macros_loop

View file

@ -205,6 +205,11 @@ function fputn
fputs(fd, s)
return
function putn
argument n
fputn(1, n)
return
function fputc
argument fd
argument c