start translation phase 4

This commit is contained in:
pommicket 2022-01-08 14:37:39 -05:00
parent ac6cb985db
commit 3d0adb5f6f
5 changed files with 245 additions and 4 deletions

View file

@ -106,3 +106,27 @@
:str_hash_hash :str_hash_hash
string ## string ##
byte 0 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

View file

@ -8,6 +8,13 @@ byte 0
byte 0 byte 0
goto main goto main
global object_macros_size
global function_macros_size
; these are allocated in main()
global object_macros
global function_macros
function compile_error function compile_error
argument file argument file
argument line argument line
@ -15,12 +22,12 @@ function compile_error
fputs(2, file) fputs(2, file)
fputc(2, ':) fputc(2, ':)
fputn(2, line) fputn(2, line)
fputs(2, .str_error) fputs(2, .str_error_prefix)
fputs(2, message) fputs(2, message)
fputc(2, 10) fputc(2, 10)
exit(1) exit(1)
:str_error :str_error_prefix
string : Error: string : Error:
byte 32 byte 32
byte 0 byte 0
@ -38,6 +45,9 @@ function main
local output_filename local output_filename
local pptokens local pptokens
object_macros = malloc(4000000)
function_macros = malloc(4000000)
input_filename = .str_default_input_filename input_filename = .str_default_input_filename
output_filename = .str_default_output_filename output_filename = .str_default_output_filename
if argc == 1 goto have_filenames if argc == 1 goto have_filenames
@ -47,6 +57,10 @@ function main
:have_filenames :have_filenames
pptokens = split_into_preprocessing_tokens(input_filename) pptokens = split_into_preprocessing_tokens(input_filename)
print_pptokens(pptokens) print_pptokens(pptokens)
print_separator()
pptokens = translation_phase_4(input_filename, pptokens)
;print_pptokens(pptokens)
print_object_macros()
exit(0) exit(0)
:usage_error :usage_error

View file

@ -1,10 +1,13 @@
#include <stdio.h> -#include <stdio.h>
int test(int, double, ...);\ int test(int, double, ...);\
/* here is a nice /* here is a nice
comment it is comment it is
here here
*/ */
#
#define A 33
#define _Hello_there5 -76 + sqrt(A)
int main(void) { int main(void) {
printf("\"Hello, world!%c\n\"", '\''); printf("\"Hello, world!%c\n\"", '\'');
_X55 = Y4_C_; _X55 = Y4_C_;

View file

@ -360,3 +360,156 @@ function print_pptokens
:print_pptokens_loop_end :print_pptokens_loop_end
putc(10) putc(10)
return 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

View file

@ -90,6 +90,28 @@ function memchr
:memchr_loop_end :memchr_loop_end
return p 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 function strlen
argument s argument s
local p local p
@ -101,6 +123,7 @@ function strlen
:strlen_loop_end :strlen_loop_end
return p - s return p - s
; like C strcpy, but returns a pointer to the terminating null character in dest
function strcpy function strcpy
argument dest argument dest
argument src argument src
@ -119,6 +142,20 @@ function strcpy
:strcpy_loop_end :strcpy_loop_end
return p 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 function str_startswith
argument s argument s
argument prefix argument prefix
@ -150,6 +187,16 @@ function puts
fputs(1, s) fputs(1, s)
return return
function print_separator
fputs(1, .str_separator)
return
:str_separator
byte 10
string ------------------------------------------------
byte 10
byte 0
function fputn function fputn
argument fd argument fd
argument n argument n