some binop typing

This commit is contained in:
pommicket 2022-01-14 13:41:44 -05:00
parent df8c5700d6
commit e3547b76b1
4 changed files with 137 additions and 10 deletions

View file

@ -27,7 +27,7 @@
; NB: for equal precedence, operators are applied left-to-right except for assignment operators (precedence 2) ; NB: for equal precedence, operators are applied left-to-right except for assignment operators (precedence 2)
#define SYMBOL_COMMA 200 #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_EQ 201
#define SYMBOL_PLUS_EQ 202 #define SYMBOL_PLUS_EQ 202
#define SYMBOL_MINUS_EQ 203 #define SYMBOL_MINUS_EQ 203
@ -39,7 +39,7 @@
#define SYMBOL_AND_EQ 209 #define SYMBOL_AND_EQ 209
#define SYMBOL_XOR_EQ 210 #define SYMBOL_XOR_EQ 210
#define SYMBOL_OR_EQ 211 #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_QUESTION 212
#define SYMBOL_OR_OR 213 #define SYMBOL_OR_OR 213
#define SYMBOL_AND_AND 214 #define SYMBOL_AND_AND 214

View file

@ -17,6 +17,16 @@ global function_macros_size
global object_macros global object_macros
global function_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 ; accepts EITHER file index OR pointer to filename
function fprint_filename function fprint_filename
argument fd argument fd

View file

@ -1 +1 @@
5+*7**8-- "hi"[33]

View file

@ -9,12 +9,15 @@ function parse_expression
local c local c
local p local p
local n local n
local type
local best local best
local best_precedence local best_precedence
local depth local depth
local value local value
:parse_expression_top :parse_expression_top
type = out + 4
if tokens == tokens_end goto empty_expression if tokens == tokens_end goto empty_expression
p = tokens + 16 p = tokens + 16
if p == tokens_end goto single_token_expression 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 if p >= tokens_end goto expr_find_operator_loop_end
c = *1p c = *1p
p += 16 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_find_operator_loop
if depth < 0 goto expr_too_many_closing_brackets if depth < 0 goto expr_too_many_closing_brackets
n = p - 16 n = p - 16
a = operator_precedence(n, b) a = operator_precedence(n, b)
n = a n = a
n -= operator_right_associative(c) ; ensure that the leftmost += / -= / etc. is processed first 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! ; new best!
best = p - 16 best = p - 16
best_precedence = a best_precedence = a
goto expr_find_operator_loop 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 :expr_findop_incdepth
depth += 1 depth += 1
@ -99,9 +104,48 @@ function parse_expression
out += 8 out += 8
if c == SYMBOL_DOT goto parse_expr_member if c == SYMBOL_DOT goto parse_expr_member
if c == SYMBOL_ARROW 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 out = parse_expression(tokens, best, out) ; first operand
p = best + 16 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 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 return out
;@TODO: casts ;@TODO: casts
@ -134,17 +178,22 @@ function parse_expression
:parse_postincrement :parse_postincrement
*1out = EXPRESSION_POST_INCREMENT *1out = EXPRESSION_POST_INCREMENT
out += 8
p = tokens_end - 16 p = tokens_end - 16
if *1p != SYMBOL_PLUS_PLUS goto bad_expression ; e.g. a ++ b 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) 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 return out
:parse_postdecrement :parse_postdecrement
*1out = EXPRESSION_POST_DECREMENT *1out = EXPRESSION_POST_DECREMENT
out += 8
p = tokens_end - 16 p = tokens_end - 16
if *1p != SYMBOL_MINUS_MINUS goto bad_expression ; e.g. a -- b 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) out = parse_expression(tokens, p, out)
*4type = *4a ; type of this = type of operand
return out return out
:single_token_expression :single_token_expression
@ -241,6 +290,74 @@ function parse_expression
:return_type_double :return_type_double
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 ; return precedence of given operator token, or 0xffff if not an operator
function operator_precedence function operator_precedence
argument token argument token