start translation phase 4
This commit is contained in:
parent
ac6cb985db
commit
3d0adb5f6f
5 changed files with 245 additions and 4 deletions
|
@ -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
|
||||||
|
|
18
05/main.b
18
05/main.b
|
@ -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
|
||||||
|
|
|
@ -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_;
|
||||||
|
|
153
05/preprocess.b
153
05/preprocess.b
|
@ -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
|
||||||
|
|
47
05/util.b
47
05/util.b
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue