lang-bootstrap/05/parse.b

217 lines
5.1 KiB
Brainfuck
Raw Normal View History

2022-01-13 16:12:28 -05:00
function parse_expression
argument tokens
argument tokens_end
argument out
local in
local a
local b
local c
local p
local value
if tokens == tokens_end goto empty_expression
p = tokens + 16
if p == tokens_end goto single_token_expression
goto unrecognized_expression
:single_token_expression
in = tokens
c = *1in
if c == TOKEN_CONSTANT_INT goto expression_integer
if c == TOKEN_CONSTANT_CHAR goto expression_integer ; character constants are basically the same as integer constants
if c == TOKEN_CONSTANT_FLOAT goto expression_float
if c == TOKEN_STRING_LITERAL goto expression_string_literal
byte 0xcc
:expression_integer
*1out = EXPRESSION_CONSTANT_INT
p = in + 8
value = *8p
p = out + 8
*8p = value
p = in + 1
a = int_suffix_to_type(*1p) ; what the suffix says the type should be
b = int_value_to_type(value) ; what the value says the type should be (if the value is too large to fit in int)
a = max_signed(a, b) ; take the maximum of the two types
; make sure that if the integer has a u suffix, the type will be unsigned
a &= b | 0xfe
p = out + 4
*4p = a
in += 16
out += 16
return out
:expression_float
*1out = EXPRESSION_CONSTANT_FLOAT
p = in + 8
value = *8p
p = out + 8
*8p = value
p = in + 1
a = float_suffix_to_type(*1p)
p = out + 4
*4p = a
in += 16
out += 16
return out
:expression_string_literal
*1out = EXPRESSION_STRING_LITERAL
p = in + 8
value = *8p
p = out + 8
*8p = value
; we already know this is char*
p = out + 4
*4p = TYPE_POINTER_TO_CHAR
in += 16
out += 16
return out
:empty_expression
token_error(tokens, .str_empty_expression)
:str_empty_expression
string Empty expression.
byte 0
:unrecognized_expression
token_error(tokens, .str_unrecognized_expression)
:str_unrecognized_expression
string Unrecognized expression.
byte 0
:return_type_int
return TYPE_INT
:return_type_long
return TYPE_LONG
:return_type_unsigned_int
return TYPE_UNSIGNED_INT
:return_type_unsigned_long
return TYPE_UNSIGNED_LONG
:return_type_float
return TYPE_FLOAT
:return_type_double
return TYPE_DOUBLE
function int_suffix_to_type
argument suffix
if suffix == NUMBER_SUFFIX_L goto return_type_long
if suffix == NUMBER_SUFFIX_U goto return_type_unsigned_int
if suffix == NUMBER_SUFFIX_UL goto return_type_unsigned_long
goto return_type_int
function float_suffix_to_type
argument suffix
if suffix == NUMBER_SUFFIX_F goto return_type_float
goto return_type_double
; smallest integer type which can fit this value, only using unsigned if necessary
function int_value_to_type
argument value
if value [ 0x80000000 goto return_type_int
if value [ 0x8000000000000000 goto return_type_long
goto return_type_unsigned_long
function print_expression
argument expression
local c
local p
p = expression + 4
putc(40)
print_type(*4p)
putc(41)
c = *1expression
if c == EXPRESSION_CONSTANT_INT goto print_expr_int
if c == EXPRESSION_CONSTANT_FLOAT goto print_expr_float
if c == EXPRESSION_STRING_LITERAL goto print_expr_str
byte 0xcc
:print_expr_int
expression += 8
putn(*8expression)
return
:print_expr_float
expression += 8
putx64(*8expression)
return
:print_expr_str
expression += 8
putc('0)
putc('x)
putx32(*8expression)
return
; NOTE: to make things easier, the format which this outputs isn't the same as C's, specifically we have
; *int for pointer to int and [5]int for array of 5 ints
function print_type
argument type
local c
:print_type_top
c = types + type
c = *1c
if c == TYPE_VOID goto print_type_void
if c == TYPE_CHAR goto print_type_char
if c == TYPE_UNSIGNED_CHAR goto print_type_unsigned_char
if c == TYPE_SHORT goto print_type_short
if c == TYPE_UNSIGNED_SHORT goto print_type_unsigned_short
if c == TYPE_INT goto print_type_int
if c == TYPE_UNSIGNED_INT goto print_type_unsigned_int
if c == TYPE_LONG goto print_type_long
if c == TYPE_UNSIGNED_LONG goto print_type_unsigned_long
if c == TYPE_FLOAT goto print_type_float
if c == TYPE_DOUBLE goto print_type_double
if c == TYPE_POINTER goto print_type_pointer
if c == TYPE_ARRAY goto print_type_array
if c == TYPE_STRUCT goto print_type_struct
if c == TYPE_UNION goto print_type_union
fputs(2, .str_bad_print_type)
exit(1)
:str_bad_print_type
string Bad type passed to print_type.
byte 10
byte 0
:print_type_void
return puts(.str_void)
:print_type_char
return puts(.str_char)
:print_type_unsigned_char
return puts(.str_unsigned_char)
:print_type_short
return puts(.str_short)
:print_type_unsigned_short
return puts(.str_unsigned_short)
:print_type_int
return puts(.str_int)
:print_type_unsigned_int
return puts(.str_unsigned_int)
:print_type_long
return puts(.str_long)
:print_type_unsigned_long
return puts(.str_unsigned_long)
:print_type_float
return puts(.str_float)
:print_type_double
return puts(.str_double)
:print_type_pointer
putc('*)
type += 1
goto print_type_top
:print_type_array
putc('[)
type += 1
putn(*8type) ; UNALIGNED
putc('])
type += 8
goto print_type_top
:print_type_struct
return puts(.str_struct)
:print_type_union
return puts(.str_union)