start parsing binary ops
This commit is contained in:
parent
13363eac1a
commit
e44bc4976a
4 changed files with 178 additions and 3 deletions
|
@ -20,12 +20,14 @@
|
||||||
; b << >>
|
; b << >>
|
||||||
; c + -
|
; c + -
|
||||||
; d * / %
|
; d * / %
|
||||||
|
; e8 cast
|
||||||
; e unary prefixes ++ -- & * + - ~ !
|
; e unary prefixes ++ -- & * + - ~ !
|
||||||
; f . -> () [] postfix ++ --
|
; f . -> () [] postfix ++ --
|
||||||
; highest
|
; highest
|
||||||
; 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
|
||||||
#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
|
||||||
|
@ -37,6 +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
|
||||||
#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
|
||||||
|
@ -70,7 +73,7 @@
|
||||||
#define SYMBOL_LPAREN 242
|
#define SYMBOL_LPAREN 242
|
||||||
#define SYMBOL_RPAREN 243
|
#define SYMBOL_RPAREN 243
|
||||||
#define SYMBOL_SEMICOLON 244
|
#define SYMBOL_SEMICOLON 244
|
||||||
|
#define SYMBOL_DOT 245
|
||||||
|
|
||||||
#define TOKEN_IDENTIFIER 1
|
#define TOKEN_IDENTIFIER 1
|
||||||
#define TOKEN_CONSTANT_FLOAT 2
|
#define TOKEN_CONSTANT_FLOAT 2
|
||||||
|
@ -347,6 +350,9 @@
|
||||||
byte SYMBOL_ARROW
|
byte SYMBOL_ARROW
|
||||||
string ->
|
string ->
|
||||||
byte 0
|
byte 0
|
||||||
|
byte SYMBOL_DOT
|
||||||
|
string .
|
||||||
|
byte 0
|
||||||
byte SYMBOL_DOTDOTDOT
|
byte SYMBOL_DOTDOTDOT
|
||||||
string ...
|
string ...
|
||||||
byte 0
|
byte 0
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
'a'
|
(3+5)*6
|
||||||
|
|
141
05/parse.b
141
05/parse.b
|
@ -7,14 +7,82 @@ function parse_expression
|
||||||
local b
|
local b
|
||||||
local c
|
local c
|
||||||
local p
|
local p
|
||||||
|
local n
|
||||||
|
local best
|
||||||
|
local best_precedence
|
||||||
|
local depth
|
||||||
local value
|
local value
|
||||||
|
:parse_expression_top
|
||||||
|
|
||||||
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
|
||||||
|
if *1tokens != SYMBOL_LPAREN goto parse_expression_not_entirely_in_parens
|
||||||
|
p = tokens_end - 16
|
||||||
|
if *1p != SYMBOL_RPAREN goto parse_expression_not_entirely_in_parens
|
||||||
|
|
||||||
|
depth = 1 ; bracket depth
|
||||||
|
p = tokens + 16
|
||||||
|
a = tokens_end - 16 ; stop point
|
||||||
|
:expr_paren_check_loop
|
||||||
|
if p >= a goto expr_paren_check_loop_end
|
||||||
|
c = *1p
|
||||||
|
p += 16
|
||||||
|
if c == SYMBOL_LPAREN goto expr_paren_check_loop_incdepth
|
||||||
|
if c == SYMBOL_RPAREN goto expr_paren_check_loop_decdepth
|
||||||
|
goto expr_paren_check_loop
|
||||||
|
:expr_paren_check_loop_incdepth
|
||||||
|
depth += 1
|
||||||
|
goto expr_paren_check_loop
|
||||||
|
:expr_paren_check_loop_decdepth
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0 goto parse_expression_not_entirely_in_parens
|
||||||
|
goto expr_paren_check_loop
|
||||||
|
:expr_paren_check_loop_end
|
||||||
|
|
||||||
|
; if we made it this far, the expression is entirely in parenthesis, e.g. (x+2)
|
||||||
|
tokens += 16
|
||||||
|
tokens_end -= 16
|
||||||
|
goto parse_expression_top
|
||||||
|
|
||||||
|
:parse_expression_not_entirely_in_parens
|
||||||
|
|
||||||
|
; look for the operator with the lowest precedence not in brackets
|
||||||
|
depth = 0 ; paren/square bracket depth
|
||||||
|
b = 1 ; first token? -- i.e. is this operator unary
|
||||||
|
p = tokens
|
||||||
|
best = 0
|
||||||
|
best_precedence = 1000
|
||||||
|
:expr_find_operator_loop
|
||||||
|
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
|
||||||
|
a = operator_precedence(c, 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
|
||||||
|
; new best!
|
||||||
|
best = p - 16
|
||||||
|
best_precedence = a
|
||||||
|
goto expr_find_operator_loop
|
||||||
|
|
||||||
|
:expr_findop_incdepth
|
||||||
|
depth += 1
|
||||||
|
goto expr_find_operator_loop
|
||||||
|
:expr_findop_decdepth
|
||||||
|
depth -= 1
|
||||||
|
goto expr_find_operator_loop
|
||||||
|
:expr_find_operator_loop_end
|
||||||
|
putn(*1best)
|
||||||
goto unrecognized_expression
|
goto unrecognized_expression
|
||||||
|
|
||||||
|
|
||||||
:single_token_expression
|
:single_token_expression
|
||||||
in = tokens
|
in = tokens
|
||||||
c = *1in
|
c = *1in
|
||||||
|
@ -86,7 +154,11 @@ function parse_expression
|
||||||
:str_unrecognized_expression
|
:str_unrecognized_expression
|
||||||
string Unrecognized expression.
|
string Unrecognized expression.
|
||||||
byte 0
|
byte 0
|
||||||
|
:expr_too_many_closing_brackets
|
||||||
|
token_error(tokens, .str_too_many_closing_brackets)
|
||||||
|
:str_too_many_closing_brackets
|
||||||
|
string Too many closing brackets.
|
||||||
|
byte 0
|
||||||
:return_type_int
|
:return_type_int
|
||||||
return TYPE_INT
|
return TYPE_INT
|
||||||
:return_type_long
|
:return_type_long
|
||||||
|
@ -99,7 +171,74 @@ function parse_expression
|
||||||
return TYPE_FLOAT
|
return TYPE_FLOAT
|
||||||
:return_type_double
|
:return_type_double
|
||||||
return TYPE_DOUBLE
|
return TYPE_DOUBLE
|
||||||
|
|
||||||
|
; return precedence of given operator, or 0xffff if not an operator
|
||||||
|
function operator_precedence
|
||||||
|
argument op
|
||||||
|
argument is_unary_prefix
|
||||||
|
if is_unary_prefix != 0 goto operator_precedence_unary
|
||||||
|
|
||||||
|
; see "C OPERATOR PRECEDENCE" in constants.b
|
||||||
|
if op == SYMBOL_COMMA goto return_0x10
|
||||||
|
if op == SYMBOL_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_PLUS_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_MINUS_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_TIMES_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_DIV_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_PERCENT_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_LSHIFT_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_RSHIFT_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_AND_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_OR_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_XOR_EQ goto return_0x20
|
||||||
|
if op == SYMBOL_QUESTION goto return_0x30
|
||||||
|
if op == SYMBOL_OR_OR goto return_0x40
|
||||||
|
if op == SYMBOL_AND_AND goto return_0x50
|
||||||
|
if op == SYMBOL_OR goto return_0x60
|
||||||
|
if op == SYMBOL_XOR goto return_0x70
|
||||||
|
if op == SYMBOL_AND goto return_0x80
|
||||||
|
if op == SYMBOL_EQ_EQ goto return_0x90
|
||||||
|
if op == SYMBOL_NOT_EQ goto return_0x90
|
||||||
|
if op == SYMBOL_LT goto return_0xa0
|
||||||
|
if op == SYMBOL_GT goto return_0xa0
|
||||||
|
if op == SYMBOL_LT_EQ goto return_0xa0
|
||||||
|
if op == SYMBOL_GT_EQ goto return_0xa0
|
||||||
|
if op == SYMBOL_LSHIFT goto return_0xb0
|
||||||
|
if op == SYMBOL_RSHIFT goto return_0xb0
|
||||||
|
if op == SYMBOL_PLUS goto return_0xc0
|
||||||
|
if op == SYMBOL_MINUS goto return_0xc0
|
||||||
|
if op == SYMBOL_TIMES goto return_0xd0
|
||||||
|
if op == SYMBOL_DIV goto return_0xd0
|
||||||
|
if op == SYMBOL_PERCENT goto return_0xd0
|
||||||
|
if op == SYMBOL_ARROW goto return_0xf0
|
||||||
|
if op == SYMBOL_DOT goto return_0xf0
|
||||||
|
if op == SYMBOL_LPAREN goto return_0xf0 ; function call
|
||||||
|
if op == SYMBOL_LSQUARE goto return_0xf0 ; subscript
|
||||||
|
if op == SYMBOL_PLUS_PLUS goto return_0xf0
|
||||||
|
if op == SYMBOL_MINUS_MINUS goto return_0xf0
|
||||||
|
|
||||||
|
return 0xffff
|
||||||
|
|
||||||
|
:operator_precedence_unary
|
||||||
|
if op == SYMBOL_PLUS_PLUS goto return_0xe0
|
||||||
|
if op == SYMBOL_MINUS_MINUS goto return_0xe0
|
||||||
|
if op == SYMBOL_AND goto return_0xe0
|
||||||
|
if op == SYMBOL_TIMES goto return_0xe0
|
||||||
|
if op == SYMBOL_PLUS goto return_0xe0
|
||||||
|
if op == SYMBOL_MINUS goto return_0xe0
|
||||||
|
if op == SYMBOL_TILDE goto return_0xe0
|
||||||
|
if op == SYMBOL_NOT goto return_0xe0
|
||||||
|
|
||||||
|
return 0xffff
|
||||||
|
|
||||||
|
; is this operator right-associative? most C operators are left associative,
|
||||||
|
; but += / -= / etc. are not
|
||||||
|
function operator_right_associative
|
||||||
|
argument op
|
||||||
|
if op < SYMBOL_EQ goto return_0
|
||||||
|
if op > SYMBOL_OR_EQ goto return_0
|
||||||
|
goto return_1
|
||||||
|
|
||||||
function int_suffix_to_type
|
function int_suffix_to_type
|
||||||
argument suffix
|
argument suffix
|
||||||
if suffix == NUMBER_SUFFIX_L goto return_type_long
|
if suffix == NUMBER_SUFFIX_L goto return_type_long
|
||||||
|
|
30
05/util.b
30
05/util.b
|
@ -574,6 +574,36 @@ function leftmost_1bit
|
||||||
return 1
|
return 1
|
||||||
:return_minus1
|
:return_minus1
|
||||||
return -1
|
return -1
|
||||||
|
:return_0x10
|
||||||
|
return 0x10
|
||||||
|
:return_0x20
|
||||||
|
return 0x20
|
||||||
|
:return_0x30
|
||||||
|
return 0x30
|
||||||
|
:return_0x40
|
||||||
|
return 0x40
|
||||||
|
:return_0x50
|
||||||
|
return 0x50
|
||||||
|
:return_0x60
|
||||||
|
return 0x60
|
||||||
|
:return_0x70
|
||||||
|
return 0x70
|
||||||
|
:return_0x80
|
||||||
|
return 0x80
|
||||||
|
:return_0x90
|
||||||
|
return 0x90
|
||||||
|
:return_0xa0
|
||||||
|
return 0xa0
|
||||||
|
:return_0xb0
|
||||||
|
return 0xb0
|
||||||
|
:return_0xc0
|
||||||
|
return 0xc0
|
||||||
|
:return_0xd0
|
||||||
|
return 0xd0
|
||||||
|
:return_0xe0
|
||||||
|
return 0xe0
|
||||||
|
:return_0xf0
|
||||||
|
return 0xf0
|
||||||
|
|
||||||
function syscall
|
function syscall
|
||||||
; I've done some testing, and this should be okay even if
|
; I've done some testing, and this should be okay even if
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue