summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--05/constants.b4
-rw-r--r--05/main.b10
-rw-r--r--05/main.c2
-rw-r--r--05/parse.b131
4 files changed, 137 insertions, 10 deletions
diff --git a/05/constants.b b/05/constants.b
index bb77909..4269e3e 100644
--- a/05/constants.b
+++ b/05/constants.b
@@ -27,7 +27,7 @@
; NB: for equal precedence, operators are applied left-to-right except for assignment operators (precedence 2)
#define SYMBOL_COMMA 200
-; NOTE: operator_right_associative requires SYMBOL_EQ to be the first assignment operator
+; NOTE: operator_right_associative and others require SYMBOL_EQ to be the first assignment operator
#define SYMBOL_EQ 201
#define SYMBOL_PLUS_EQ 202
#define SYMBOL_MINUS_EQ 203
@@ -39,7 +39,7 @@
#define SYMBOL_AND_EQ 209
#define SYMBOL_XOR_EQ 210
#define SYMBOL_OR_EQ 211
-; NOTE: operator_right_associative requires SYMBOL_OR_EQ to be the last assignment operator
+; NOTE: operator_right_associative and others require SYMBOL_OR_EQ to be the last assignment operator
#define SYMBOL_QUESTION 212
#define SYMBOL_OR_OR 213
#define SYMBOL_AND_AND 214
diff --git a/05/main.b b/05/main.b
index 7f6eaa1..32c6144 100644
--- a/05/main.b
+++ b/05/main.b
@@ -17,6 +17,16 @@ global function_macros_size
global object_macros
global function_macros
+function fprint_token_location
+ argument fd
+ argument token
+ token += 2
+ fprint_filename(fd, *2token)
+ token += 2
+ fputc(fd, ':)
+ fputn(fd, *4token)
+ return
+
; accepts EITHER file index OR pointer to filename
function fprint_filename
argument fd
diff --git a/05/main.c b/05/main.c
index 5406e3f..f74e65b 100644
--- a/05/main.c
+++ b/05/main.c
@@ -1 +1 @@
-5+*7**8--
+"hi"[33]
diff --git a/05/parse.b b/05/parse.b
index 76f82a4..0f128a4 100644
--- a/05/parse.b
+++ b/05/parse.b
@@ -9,12 +9,15 @@ function parse_expression
local c
local p
local n
+ local type
local best
local best_precedence
local depth
local value
:parse_expression_top
+ type = out + 4
+
if tokens == tokens_end goto empty_expression
p = tokens + 16
if p == tokens_end goto single_token_expression
@@ -61,21 +64,23 @@ function parse_expression
if p >= tokens_end goto expr_find_operator_loop_end
c = *1p
p += 16
- if c == SYMBOL_LPAREN goto expr_findop_incdepth
- if c == SYMBOL_RPAREN goto expr_findop_decdepth
- if c == SYMBOL_LSQUARE goto expr_findop_incdepth
- if c == SYMBOL_RSQUARE goto expr_findop_decdepth
if depth > 0 goto expr_find_operator_loop
if depth < 0 goto expr_too_many_closing_brackets
n = p - 16
a = operator_precedence(n, b)
n = a
n -= operator_right_associative(c) ; ensure that the leftmost += / -= / etc. is processed first
- if n > best_precedence goto expr_find_operator_loop
+ if n > best_precedence goto expr_findop_not_new_best
; new best!
best = p - 16
best_precedence = a
goto expr_find_operator_loop
+ :expr_findop_not_new_best
+ if c == SYMBOL_LPAREN goto expr_findop_incdepth
+ if c == SYMBOL_RPAREN goto expr_findop_decdepth
+ if c == SYMBOL_LSQUARE goto expr_findop_incdepth
+ if c == SYMBOL_RSQUARE goto expr_findop_decdepth
+ goto expr_find_operator_loop
:expr_findop_incdepth
depth += 1
@@ -99,9 +104,48 @@ function parse_expression
out += 8
if c == SYMBOL_DOT goto parse_expr_member
if c == SYMBOL_ARROW goto parse_expr_member
+ a = out + 4 ; type of first operand
out = parse_expression(tokens, best, out) ; first operand
p = best + 16
+ b = out + 4 ; type of second operand
+ if c != SYMBOL_LSQUARE goto binary_not_subscript
+ tokens_end -= 16
+ if *1tokens_end != SYMBOL_RSQUARE goto unrecognized_expression
+ :binary_not_subscript
out = parse_expression(p, tokens_end, out) ; second operand
+
+ if c == SYMBOL_LSHIFT goto type_binary_left_promote
+ if c == SYMBOL_RSHIFT goto type_binary_left_promote
+ if c == SYMBOL_LSQUARE goto type_subscript
+ if c < SYMBOL_EQ goto type_binary_usual
+ if c > SYMBOL_OR_EQ goto type_binary_usual
+ goto type_binary_left
+ :type_subscript
+ p = types + *4a
+ if *1p == TYPE_POINTER goto type_subscript_pointer
+ if *1p == TYPE_ARRAY goto type_subscript_array
+ goto subscript_bad_type
+ :type_subscript_pointer
+ *4type = *4a + 1
+ return out
+ :type_subscript_array
+ *4type = *4a + 9
+ return out
+ :subscript_bad_type
+ token_error(tokens, .str_subscript_bad_type)
+ :str_subscript_bad_type
+ string Subscript of non-pointer type.
+ byte 0
+ :type_binary_usual
+ *4type = expr_binary_type_usual_conversions(tokens, *4a, *4b)
+ return out
+ :type_binary_left
+ *4type = *4a
+ return out
+ :type_binary_left_promote
+ *4type = type_promotion(*4a)
+ return out
+
return out
;@TODO: casts
@@ -134,17 +178,22 @@ function parse_expression
:parse_postincrement
*1out = EXPRESSION_POST_INCREMENT
- out += 8
p = tokens_end - 16
if *1p != SYMBOL_PLUS_PLUS goto bad_expression ; e.g. a ++ b
+ out += 8
+ a = out + 4 ; type of operand
out = parse_expression(tokens, p, out)
+ *4type = *4a ; this expression's type is the operand's type (yes even for types smaller than int)
return out
+
:parse_postdecrement
*1out = EXPRESSION_POST_DECREMENT
- out += 8
p = tokens_end - 16
if *1p != SYMBOL_MINUS_MINUS goto bad_expression ; e.g. a -- b
+ out += 8
+ a = out + 4 ; type of operand
out = parse_expression(tokens, p, out)
+ *4type = *4a ; type of this = type of operand
return out
:single_token_expression
@@ -241,6 +290,74 @@ function parse_expression
:return_type_double
return TYPE_DOUBLE
+function expr_binary_type_usual_conversions
+ argument token ; for errors
+ argument type1
+ argument type2
+
+ local ptype1
+ local ptype2
+
+ if type1 == 0 goto return_0
+ if type2 == 0 goto return_0
+ ; @TODO: pointer types
+ ptype1 = types + type1
+ ptype2 = types + type2
+
+ type1 = *1ptype1
+ type2 = *1ptype2
+ if type1 == TYPE_POINTER goto type1_pointer
+ if type2 == TYPE_POINTER goto type2_pointer
+
+ if type1 > TYPE_DOUBLE goto bad_types_to_operator
+ if type2 > TYPE_DOUBLE goto bad_types_to_operator
+
+ ; "if either operand has type double, the other operand is converted to double"
+ if type1 == TYPE_DOUBLE goto return_type_double
+ if type2 == TYPE_DOUBLE goto return_type_double
+ ; "if either operand has type float, the other operand is converted to float"
+ if type1 == TYPE_FLOAT goto return_type_float
+ if type2 == TYPE_FLOAT goto return_type_float
+ ; "If either operand has type unsigned long int, the other operand is converted to unsigned long int"
+ if type1 == TYPE_UNSIGNED_LONG goto return_type_unsigned_long
+ if type2 == TYPE_UNSIGNED_LONG goto return_type_unsigned_long
+ ; "if either operand has type long int, the other operand is converted to long int"
+ if type1 == TYPE_LONG goto return_type_long
+ if type2 == TYPE_LONG goto return_type_long
+ ; "if either operand has type unsigned int, the other operand is converted to unsigned int."
+ if type1 == TYPE_UNSIGNED_INT goto return_type_unsigned_int
+ if type2 == TYPE_UNSIGNED_INT goto return_type_unsigned_int
+ ; "Otherwise, both operands have type int."
+ goto return_type_int
+
+ :type1_pointer
+ if type2 == TYPE_POINTER goto return_type_long ; this must be a pointer difference
+ return ptype1 - types ; e.g. p_int + 5
+ :type2_pointer
+ return ptype2 - types ; e.g. 5 + p_int
+
+ :bad_types_to_operator
+ fprint_token_location(2, token)
+ fputs(2, .str_bad_types_to_operator)
+ print_type(type1)
+ fputs(2, .str_space_and_space)
+ print_type(type2)
+ putc(10)
+ exit(1)
+ :str_bad_types_to_operator
+ string : Bad types to operator:
+ byte 32
+ byte 0
+ :str_space_and_space
+ string and
+ byte 32
+ byte 0
+
+function type_promotion
+ argument type
+ if type < TYPE_INT goto return_type_int
+ return type
+
; return precedence of given operator token, or 0xffff if not an operator
function operator_precedence
argument token