This commit is contained in:
pommicket 2022-01-24 18:27:09 -05:00
parent 466de93583
commit 150fbb9dd8
4 changed files with 99 additions and 64 deletions

View file

@ -132,6 +132,7 @@
; - for constant floats, the 64-bit double value (even if expression has type float)
; - for string literals, a 64-bit pointer to the string (for the executable, not for the compiler)
; - for unary operators, the operand
; - for casts, the operand (type is given by type member)
; - for binary operators, the first operand followed by the second
; - for the operators . and ->, the first argument is a 64-bit pointer to the name of the member and the second is the left hand side of the . / ->
; - for the ternary operator ? :, the first followed by the second followed by the third

View file

@ -3,10 +3,4 @@
long double d;
} (*x)(void);
*/
#if 5+FLURGE==5
typedef long int unsigned Foo[sizeof"hello"+sizeof(double[sizeof(int) * sizeof 3])];
typedef int (*x)(Foo);
#else
typedef aaa x;
#endif
/* */
typedef int Foo[(char)((unsigned char)0xff + (unsigned char)0xf02)];

View file

@ -288,6 +288,15 @@ function parse_type_to
prefix_end = p
goto parse_type_loop
:parse_array_type
local prev_types
local prev_types_bytes_used
; little hack to avoid screwing up types like double[sizeof(int)]
; temporarily switch out types array to parse the cast's type
prev_types = types
prev_types_bytes_used = types_bytes_used
types = malloc(4000)
types_init(types, &types_bytes_used)
local expr
expr = malloc(4000)
*1out = TYPE_ARRAY
@ -296,11 +305,16 @@ function parse_type_to
token_skip_to_matching_rsquare(&p)
suffix += 16 ; skip [
parse_expression(suffix, p, expr)
evaluate_constant_expression(expr, &n)
print_expression(expr)
putc(10)
evaluate_constant_expression(*8p_token, expr, &n)
if n < 0 goto bad_array_size
*8out = n
out += 8
free(expr)
free(types)
types = prev_types
types_bytes_used = prev_types_bytes_used
suffix = p + 16
goto parse_type_loop
:bad_array_size
@ -782,13 +796,13 @@ function parse_expression
return out
:expr_binary_bad_types
bad_types_to_operator(tokens, *4a, *4b)
;@TODO: casts
:parse_expr_unary
if c == KEYWORD_SIZEOF goto parse_sizeof
*1out = unary_op_to_expression_type(c)
c = *1out
if c == EXPRESSION_CAST goto parse_cast
out += 8
a = out + 4 ; type of operand
p = tokens + 16
@ -808,6 +822,22 @@ function parse_expression
string Bad unary symbol (this shouldn't happen).
byte 10
byte 0
:parse_cast
p = best + 16
a = parse_type(&p, &c)
if c != 0 goto bad_cast ; e.g. (int x)5
if *1p != SYMBOL_RPAREN goto bad_cast ; e.g. (int ,)5
out += 4
*4out = a
out += 4
p += 16
out = parse_expression(p, tokens_end, out)
return out
:bad_cast
token_error(tokens, .str_bad_cast)
:str_bad_cast
string Bad cast.
byte 0
:unary_address_of
*4type = type_create_pointer(*4a)
return out
@ -842,14 +872,6 @@ function parse_expression
byte 0
:parse_sizeof
; little hack to avoid screwing up types like double[sizeof(int)]
; temporarily switch out types array to parse the sizeof's type
local prev_types
local prev_types_bytes_used
prev_types = types
prev_types_bytes_used = types_bytes_used
types = malloc(4000)
types_init(types, &types_bytes_used)
*1out = EXPRESSION_CONSTANT_INT
out += 4
*1out = TYPE_UNSIGNED_LONG
@ -874,9 +896,6 @@ function parse_expression
*8out = type_sizeof(*4p)
free(temp)
:parse_sizeof_finish
free(types)
types = prev_types
types_bytes_used = prev_types_bytes_used
out += 8
return out
@ -1094,8 +1113,10 @@ function type_sizeof
; @NONSTANDARD: doesn't handle floats, but really why would you use floats in an array size
; e.g. SomeType x[(int)3.3];
; this is also used for #if evaluation
; tokens is used for error messages (e.g. if this "constant" expression is *x or something)
; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value)
function evaluate_constant_expression
argument token
argument expr
argument p_value
local a
@ -1116,7 +1137,7 @@ function evaluate_constant_expression
if c == EXPRESSION_UNARY_MINUS goto eval_unary_minus
if c == EXPRESSION_BITWISE_NOT goto eval_bitwise_not
if c == EXPRESSION_LOGICAL_NOT goto eval_logical_not
if c == EXPRESSION_CAST goto eval_todo ; @TODO
if c == EXPRESSION_CAST goto eval_cast
if c == EXPRESSION_ADD goto eval_add
if c == EXPRESSION_SUB goto eval_sub
if c == EXPRESSION_MUL goto eval_mul
@ -1137,16 +1158,25 @@ function evaluate_constant_expression
if c == EXPRESSION_LOGICAL_OR goto eval_logical_or
if c == EXPRESSION_CONDITIONAL goto eval_conditional
byte 0xcc
:eval_todo
fputs(2, .str_eval_todo)
exit(1)
:str_eval_todo
string evaluate_constant_expression does not support this kind of expression yet (see @TODOs).
byte 10
token_error(token, .str_eval_bad_exprtype)
:str_eval_bad_exprtype
string Can't evaluate constant expression.
byte 0
:eval_cast
p = types + type
if *1p == TYPE_VOID goto eval_cast_bad_type
if *1p > TYPE_UNSIGNED_LONG goto eval_cast_bad_type
expr += 8
; @NONSTANDARD: we don't support, for example, int x[(int)(float)5];
expr = evaluate_constant_expression(token, expr, p_value)
goto eval_fit_to_type
:eval_cast_bad_type
token_error(token, .str_eval_cast_bad_type)
:str_eval_cast_bad_type
string Bad type for constant cast (note: floating-point casts are not supported even though they are standard).
byte 0
:eval_constant_identifier
; @TODO: enum values
fputs(2, .str_constant_identifier)
@ -1162,45 +1192,45 @@ function evaluate_constant_expression
return expr
:eval_unary_plus
expr += 8
expr = evaluate_constant_expression(expr, p_value)
expr = evaluate_constant_expression(token, expr, p_value)
return expr
:eval_unary_minus
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(token, expr, &a)
*8p_value = 0 - a
goto eval_fit_to_type
:eval_bitwise_not
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(token, expr, &a)
*8p_value = ~a
goto eval_fit_to_type
:eval_logical_not
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(token, expr, &a)
if a == 0 goto eval_value_1
goto eval_value_0
:eval_add
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a + b
goto eval_fit_to_type
:eval_sub
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a - b
goto eval_fit_to_type
:eval_mul
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a * b
goto eval_fit_to_type
:eval_div
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
if *1p == TYPE_UNSIGNED_LONG goto eval_div_unsigned
; division is signed or uses a small type, so we can use 64-bit signed division
*8p_value = a / b
@ -1211,8 +1241,8 @@ function evaluate_constant_expression
goto eval_fit_to_type
:eval_remainder
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
p = types + type
if *1p == TYPE_UNSIGNED_LONG goto eval_rem_unsigned
*8p_value = a % b
@ -1222,14 +1252,14 @@ function evaluate_constant_expression
goto eval_fit_to_type
:eval_lshift
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a < b
goto eval_fit_to_type
:eval_rshift
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
p = types + type
p = *1p
p &= 1 ; signed types are odd
@ -1275,8 +1305,8 @@ function evaluate_constant_expression
goto eval_comparison
:eval_comparison
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
p = types + type
p = *1p
@ -1309,41 +1339,41 @@ function evaluate_constant_expression
goto eval_value_0
:eval_bitwise_and
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a & b
goto eval_fit_to_type
:eval_bitwise_or
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a | b
goto eval_fit_to_type
:eval_bitwise_xor
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
*8p_value = a ^ b
goto eval_fit_to_type
:eval_logical_and
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(token, expr, &a)
if a == 0 goto eval_value_0
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &b)
if b == 0 goto eval_value_0
goto eval_value_1
:eval_logical_or
expr += 8
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(token, expr, &a)
if a != 0 goto eval_value_1
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &b)
if b != 0 goto eval_value_1
goto eval_value_0
:eval_conditional
expr += 8
expr = evaluate_constant_expression(expr, &mask)
expr = evaluate_constant_expression(expr, &a)
expr = evaluate_constant_expression(expr, &b)
expr = evaluate_constant_expression(token, expr, &mask)
expr = evaluate_constant_expression(token, expr, &a)
expr = evaluate_constant_expression(token, expr, &b)
if mask == 0 goto eval_conditional_b
*8p_value = a
goto eval_fit_to_type
@ -1557,6 +1587,7 @@ function operator_precedence
if op == SYMBOL_MINUS goto return_0xe0
if op == SYMBOL_TILDE goto return_0xe0
if op == SYMBOL_NOT goto return_0xe0
if op == SYMBOL_LPAREN goto return_0xe8 ; casts
return 0xffff
@ -1570,6 +1601,7 @@ function unary_op_to_expression_type
if op == SYMBOL_MINUS goto return_EXPRESSION_UNARY_MINUS
if op == SYMBOL_TILDE goto return_EXPRESSION_BITWISE_NOT
if op == SYMBOL_NOT goto return_EXPRESSION_LOGICAL_NOT
if op == SYMBOL_LPAREN goto return_EXPRESSION_CAST
return 0
:return_EXPRESSION_PRE_INCREMENT
@ -1588,7 +1620,8 @@ function unary_op_to_expression_type
return EXPRESSION_BITWISE_NOT
:return_EXPRESSION_LOGICAL_NOT
return EXPRESSION_LOGICAL_NOT
:return_EXPRESSION_CAST
return EXPRESSION_CAST
; is this operator right-associative? most C operators are left associative,
; but += / -= / etc. are not
@ -1755,6 +1788,7 @@ function print_expression
if c == EXPRESSION_UNARY_MINUS goto print_unary_minus
if c == EXPRESSION_BITWISE_NOT goto print_bitwise_not
if c == EXPRESSION_LOGICAL_NOT goto print_logical_not
if c == EXPRESSION_CAST goto print_cast
b = binop_expression_type_to_symbol(c)
if b != 0 goto print_expr_binop
@ -1766,7 +1800,11 @@ function print_expression
string Bad expression passed to print_expression.
byte 10
byte 0
:print_cast
; we've already printed the type
expression += 8
expression = print_expression(expression)
return expression
:print_expr_int
expression += 8
putn(*8expression)

View file

@ -711,6 +711,8 @@ function leftmost_1bit
return 0xd0
:return_0xe0
return 0xe0
:return_0xe8
return 0xe8
:return_0xf0
return 0xf0