summaryrefslogtreecommitdiff
path: root/05/parse.b
diff options
context:
space:
mode:
Diffstat (limited to '05/parse.b')
-rw-r--r--05/parse.b216
1 files changed, 216 insertions, 0 deletions
diff --git a/05/parse.b b/05/parse.b
new file mode 100644
index 0000000..7502882
--- /dev/null
+++ b/05/parse.b
@@ -0,0 +1,216 @@
+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)