parse goto, case
This commit is contained in:
parent
dfce9118b9
commit
d75b4154d3
3 changed files with 92 additions and 12 deletions
|
@ -269,6 +269,7 @@
|
||||||
; - STATEMENT_CONTINUE - data1,2,3,4 are unused
|
; - STATEMENT_CONTINUE - data1,2,3,4 are unused
|
||||||
; - STATEMENT_BREAK - data1,2,3,4 are unused
|
; - STATEMENT_BREAK - data1,2,3,4 are unused
|
||||||
; - STATEMENT_RETURN - data1 is a pointer to the expression, or 0 if there is none; data2,3,4 are unused
|
; - STATEMENT_RETURN - data1 is a pointer to the expression, or 0 if there is none; data2,3,4 are unused
|
||||||
|
; - STATEMENT_CASE - data1 is the value; data2,3,4 are unused
|
||||||
#define STATEMENT_EXPRESSION 1
|
#define STATEMENT_EXPRESSION 1
|
||||||
#define STATEMENT_LOCAL_DECLARATION 2
|
#define STATEMENT_LOCAL_DECLARATION 2
|
||||||
#define STATEMENT_LABEL 3
|
#define STATEMENT_LABEL 3
|
||||||
|
@ -282,7 +283,7 @@
|
||||||
#define STATEMENT_CONTINUE 0xb
|
#define STATEMENT_CONTINUE 0xb
|
||||||
#define STATEMENT_BREAK 0xc
|
#define STATEMENT_BREAK 0xc
|
||||||
#define STATEMENT_RETURN 0xd
|
#define STATEMENT_RETURN 0xd
|
||||||
|
#define STATEMENT_CASE 0xe
|
||||||
|
|
||||||
|
|
||||||
:keyword_table
|
:keyword_table
|
||||||
|
@ -507,6 +508,7 @@
|
||||||
byte 0
|
byte 0
|
||||||
byte 255
|
byte 255
|
||||||
|
|
||||||
|
; NB: some of these are only used for nice debug output
|
||||||
:str_missing_closing_paren
|
:str_missing_closing_paren
|
||||||
string Missing closing ).
|
string Missing closing ).
|
||||||
byte 0
|
byte 0
|
||||||
|
@ -747,10 +749,15 @@
|
||||||
:str_union
|
:str_union
|
||||||
string union
|
string union
|
||||||
byte 0
|
byte 0
|
||||||
; NB: some of these are only used for nice debug output
|
|
||||||
:str_typedef
|
:str_typedef
|
||||||
string typedef
|
string typedef
|
||||||
byte 0
|
byte 0
|
||||||
:str_return
|
:str_return
|
||||||
string return
|
string return
|
||||||
byte 0
|
byte 0
|
||||||
|
:str_goto
|
||||||
|
string goto
|
||||||
|
byte 0
|
||||||
|
:str_case
|
||||||
|
string case
|
||||||
|
byte 0
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
int f(void) {
|
int f(void) {
|
||||||
lbl1:break;;;
|
lbl1:break;;goto blah;
|
||||||
|
case -1-3:
|
||||||
continue;a:break;return;return 6+3<<sizeof(int);
|
continue;a:break;return;return 6+3<<sizeof(int);
|
||||||
|
goto lbl1;
|
||||||
|
case 77:;return 92834;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
84
05/parse.b
84
05/parse.b
|
@ -286,6 +286,7 @@ function parse_statement
|
||||||
token = *8p_token
|
token = *8p_token
|
||||||
|
|
||||||
:stmt_label_loop
|
:stmt_label_loop
|
||||||
|
if *1token != TOKEN_IDENTIFIER goto stmt_label_loop_end
|
||||||
; if second token in statement is a colon, this must be a label
|
; if second token in statement is a colon, this must be a label
|
||||||
p = token + 16
|
p = token + 16
|
||||||
if *1p == SYMBOL_COLON goto stmt_label
|
if *1p == SYMBOL_COLON goto stmt_label
|
||||||
|
@ -307,6 +308,8 @@ function parse_statement
|
||||||
if c == KEYWORD_BREAK goto stmt_break
|
if c == KEYWORD_BREAK goto stmt_break
|
||||||
if c == KEYWORD_CONTINUE goto stmt_continue
|
if c == KEYWORD_CONTINUE goto stmt_continue
|
||||||
if c == KEYWORD_RETURN goto stmt_return
|
if c == KEYWORD_RETURN goto stmt_return
|
||||||
|
if c == KEYWORD_GOTO goto stmt_goto
|
||||||
|
if c == KEYWORD_CASE goto stmt_case
|
||||||
|
|
||||||
token_error(token, .str_unrecognized_statement)
|
token_error(token, .str_unrecognized_statement)
|
||||||
:str_unrecognized_statement
|
:str_unrecognized_statement
|
||||||
|
@ -317,10 +320,10 @@ function parse_statement
|
||||||
*8p_out = out
|
*8p_out = out
|
||||||
return
|
return
|
||||||
:stmt_break
|
:stmt_break
|
||||||
|
write_statement_header(out, STATEMENT_BREAK, token)
|
||||||
token += 16
|
token += 16
|
||||||
if *1token != SYMBOL_SEMICOLON goto break_no_semicolon
|
if *1token != SYMBOL_SEMICOLON goto break_no_semicolon
|
||||||
token += 16
|
token += 16
|
||||||
write_statement_header(out, STATEMENT_BREAK, token)
|
|
||||||
out += 40
|
out += 40
|
||||||
goto parse_statement_ret
|
goto parse_statement_ret
|
||||||
:break_no_semicolon
|
:break_no_semicolon
|
||||||
|
@ -329,10 +332,10 @@ function parse_statement
|
||||||
string No semicolon after break.
|
string No semicolon after break.
|
||||||
byte 0
|
byte 0
|
||||||
:stmt_continue
|
:stmt_continue
|
||||||
|
write_statement_header(out, STATEMENT_CONTINUE, token)
|
||||||
token += 16
|
token += 16
|
||||||
if *1token != SYMBOL_SEMICOLON goto continue_no_semicolon
|
if *1token != SYMBOL_SEMICOLON goto continue_no_semicolon
|
||||||
token += 16
|
token += 16
|
||||||
write_statement_header(out, STATEMENT_CONTINUE, token)
|
|
||||||
out += 40
|
out += 40
|
||||||
goto parse_statement_ret
|
goto parse_statement_ret
|
||||||
:continue_no_semicolon
|
:continue_no_semicolon
|
||||||
|
@ -340,6 +343,36 @@ function parse_statement
|
||||||
:str_continue_no_semicolon
|
:str_continue_no_semicolon
|
||||||
string No semicolon after continue.
|
string No semicolon after continue.
|
||||||
byte 0
|
byte 0
|
||||||
|
:stmt_case
|
||||||
|
write_statement_header(out, STATEMENT_CASE, token)
|
||||||
|
token += 16
|
||||||
|
out += 8
|
||||||
|
p = token
|
||||||
|
; @NONSTANDARD
|
||||||
|
; technically (horribly), this is legal C:
|
||||||
|
; switch (x) {
|
||||||
|
; case 1 == 7 ? 5 : 6:
|
||||||
|
; ...
|
||||||
|
; }
|
||||||
|
; we don't handle it properly, even if the conditional is put in parentheses.
|
||||||
|
; at least it will definitely give an error if it encounters something like this.
|
||||||
|
:case_find_colon_loop
|
||||||
|
if *1p == TOKEN_EOF goto case_no_colon
|
||||||
|
if *1p == SYMBOL_COLON goto case_found_colon
|
||||||
|
p += 16
|
||||||
|
goto case_find_colon_loop
|
||||||
|
:case_found_colon
|
||||||
|
c = expressions_end
|
||||||
|
expressions_end = parse_expression(token, p, expressions_end)
|
||||||
|
evaluate_constant_expression(token, c, &n)
|
||||||
|
*8out = n
|
||||||
|
out += 32
|
||||||
|
token = p + 16
|
||||||
|
goto parse_statement_ret
|
||||||
|
:case_no_colon
|
||||||
|
token_error(token, .str_case_no_colon)
|
||||||
|
:str_case_no_colon
|
||||||
|
string No : after case.
|
||||||
:stmt_return
|
:stmt_return
|
||||||
write_statement_header(out, STATEMENT_RETURN, token)
|
write_statement_header(out, STATEMENT_RETURN, token)
|
||||||
out += 8
|
out += 8
|
||||||
|
@ -352,14 +385,37 @@ function parse_statement
|
||||||
:return_no_expr
|
:return_no_expr
|
||||||
out += 32
|
out += 32
|
||||||
goto parse_statement_ret
|
goto parse_statement_ret
|
||||||
|
:stmt_goto
|
||||||
|
write_statement_header(out, STATEMENT_GOTO, token)
|
||||||
|
out += 8
|
||||||
|
token += 16
|
||||||
|
if *1token != TOKEN_IDENTIFIER goto goto_not_ident
|
||||||
|
token += 8
|
||||||
|
*8out = *8token
|
||||||
|
out += 32
|
||||||
|
token += 8
|
||||||
|
if *1token != SYMBOL_SEMICOLON goto goto_no_semicolon
|
||||||
|
token += 16
|
||||||
|
goto parse_statement_ret
|
||||||
|
:goto_not_ident
|
||||||
|
token_error(token, .str_goto_not_ident)
|
||||||
|
:str_goto_not_ident
|
||||||
|
string goto not immediately followed by identifier.
|
||||||
|
byte 0
|
||||||
|
:goto_no_semicolon
|
||||||
|
token_error(token, .str_goto_no_semicolon)
|
||||||
|
:str_goto_no_semicolon
|
||||||
|
string No semicolon after goto.
|
||||||
|
byte 0
|
||||||
:stmt_block
|
:stmt_block
|
||||||
|
write_statement_header(out, STATEMENT_BLOCK, token)
|
||||||
|
out += 8
|
||||||
|
|
||||||
local block_p_out
|
local block_p_out
|
||||||
; find the appropriate statement data to use for this block's body
|
; find the appropriate statement data to use for this block's body
|
||||||
block_p_out = statement_datas_ends
|
block_p_out = statement_datas_ends
|
||||||
block_p_out += parse_stmt_depth < 3
|
block_p_out += parse_stmt_depth < 3
|
||||||
|
|
||||||
write_statement_header(out, STATEMENT_BLOCK, token)
|
|
||||||
out += 8
|
|
||||||
*8out = *8block_p_out
|
*8out = *8block_p_out
|
||||||
out += 32
|
out += 32
|
||||||
|
|
||||||
|
@ -427,11 +483,13 @@ function print_statement_with_depth
|
||||||
dat4 = statement + 32
|
dat4 = statement + 32
|
||||||
dat4 = *8dat4
|
dat4 = *8dat4
|
||||||
|
|
||||||
if c == STATEMENT_LABEL goto print_stmt_label
|
|
||||||
if c == STATEMENT_BLOCK goto print_stmt_block
|
if c == STATEMENT_BLOCK goto print_stmt_block
|
||||||
if c == STATEMENT_CONTINUE goto print_stmt_continue
|
if c == STATEMENT_CONTINUE goto print_stmt_continue
|
||||||
if c == STATEMENT_BREAK goto print_stmt_break
|
if c == STATEMENT_BREAK goto print_stmt_break
|
||||||
if c == STATEMENT_RETURN goto print_stmt_return
|
if c == STATEMENT_RETURN goto print_stmt_return
|
||||||
|
if c == STATEMENT_GOTO goto print_stmt_goto
|
||||||
|
if c == STATEMENT_LABEL goto print_stmt_label
|
||||||
|
if c == STATEMENT_CASE goto print_stmt_case
|
||||||
|
|
||||||
die(.pristmtNI)
|
die(.pristmtNI)
|
||||||
:pristmtNI
|
:pristmtNI
|
||||||
|
@ -480,6 +538,18 @@ function print_statement_with_depth
|
||||||
:print_block_loop_end
|
:print_block_loop_end
|
||||||
putcln('})
|
putcln('})
|
||||||
return
|
return
|
||||||
|
:print_stmt_goto
|
||||||
|
puts(.str_goto)
|
||||||
|
putc(32)
|
||||||
|
puts(dat1)
|
||||||
|
puts(.str_semicolon_newline)
|
||||||
|
return
|
||||||
|
:print_stmt_case
|
||||||
|
puts(.str_case)
|
||||||
|
putc(32)
|
||||||
|
putn_signed(dat1)
|
||||||
|
putcln(':)
|
||||||
|
return
|
||||||
|
|
||||||
; parse a global variable's initializer
|
; parse a global variable's initializer
|
||||||
; e.g. int x[5] = {1+8, 2, 3, 4, 5};
|
; e.g. int x[5] = {1+8, 2, 3, 4, 5};
|
||||||
|
@ -2367,8 +2437,8 @@ function type_alignof
|
||||||
; evaluate an expression which can be the size of an array, e.g.
|
; evaluate an expression which can be the size of an array, e.g.
|
||||||
; enum { A, B, C };
|
; enum { A, B, C };
|
||||||
; int x[A * sizeof(float) + 3 << 5];
|
; int x[A * sizeof(float) + 3 << 5];
|
||||||
; @NONSTANDARD: doesn't handle floats, but really why would you use floats in an array size
|
; @NONSTANDARD: doesn't handle floats. this means you can't do
|
||||||
; e.g. SomeType x[(int)3.3];
|
; e.g. double x[] = {1.5,2.3};
|
||||||
; this is also used for #if evaluation
|
; this is also used for #if evaluation
|
||||||
; token is used for error messages (e.g. if this "constant" expression is *x or something)
|
; token 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)
|
; NOTE: this returns the end of the expression, not the value (which is stored in *8p_value)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue