summaryrefslogtreecommitdiff
path: root/05
diff options
context:
space:
mode:
Diffstat (limited to '05')
-rw-r--r--05/constants.b11
-rw-r--r--05/main.c5
-rw-r--r--05/parse.b88
3 files changed, 92 insertions, 12 deletions
diff --git a/05/constants.b b/05/constants.b
index 68481a1..ca3bda9 100644
--- a/05/constants.b
+++ b/05/constants.b
@@ -269,6 +269,7 @@
; - STATEMENT_CONTINUE - 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_CASE - data1 is the value; data2,3,4 are unused
#define STATEMENT_EXPRESSION 1
#define STATEMENT_LOCAL_DECLARATION 2
#define STATEMENT_LABEL 3
@@ -282,7 +283,7 @@
#define STATEMENT_CONTINUE 0xb
#define STATEMENT_BREAK 0xc
#define STATEMENT_RETURN 0xd
-
+#define STATEMENT_CASE 0xe
:keyword_table
@@ -507,6 +508,7 @@
byte 0
byte 255
+; NB: some of these are only used for nice debug output
:str_missing_closing_paren
string Missing closing ).
byte 0
@@ -747,10 +749,15 @@
:str_union
string union
byte 0
-; NB: some of these are only used for nice debug output
:str_typedef
string typedef
byte 0
:str_return
string return
byte 0
+:str_goto
+ string goto
+ byte 0
+:str_case
+ string case
+ byte 0
diff --git a/05/main.c b/05/main.c
index 3fed294..17e960f 100644
--- a/05/main.c
+++ b/05/main.c
@@ -1,6 +1,9 @@
int f(void) {
- lbl1:break;;;
+ lbl1:break;;goto blah;
+ case -1-3:
continue;a:break;return;return 6+3<<sizeof(int);
+ goto lbl1;
+ case 77:;return 92834;
}
diff --git a/05/parse.b b/05/parse.b
index 3136017..0dc2033 100644
--- a/05/parse.b
+++ b/05/parse.b
@@ -286,6 +286,7 @@ function parse_statement
token = *8p_token
: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
p = token + 16
if *1p == SYMBOL_COLON goto stmt_label
@@ -307,6 +308,8 @@ function parse_statement
if c == KEYWORD_BREAK goto stmt_break
if c == KEYWORD_CONTINUE goto stmt_continue
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)
:str_unrecognized_statement
@@ -317,10 +320,10 @@ function parse_statement
*8p_out = out
return
:stmt_break
+ write_statement_header(out, STATEMENT_BREAK, token)
token += 16
if *1token != SYMBOL_SEMICOLON goto break_no_semicolon
token += 16
- write_statement_header(out, STATEMENT_BREAK, token)
out += 40
goto parse_statement_ret
:break_no_semicolon
@@ -329,10 +332,10 @@ function parse_statement
string No semicolon after break.
byte 0
:stmt_continue
+ write_statement_header(out, STATEMENT_CONTINUE, token)
token += 16
if *1token != SYMBOL_SEMICOLON goto continue_no_semicolon
token += 16
- write_statement_header(out, STATEMENT_CONTINUE, token)
out += 40
goto parse_statement_ret
:continue_no_semicolon
@@ -340,6 +343,36 @@ function parse_statement
:str_continue_no_semicolon
string No semicolon after continue.
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
write_statement_header(out, STATEMENT_RETURN, token)
out += 8
@@ -352,14 +385,37 @@ function parse_statement
:return_no_expr
out += 32
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
+ write_statement_header(out, STATEMENT_BLOCK, token)
+ out += 8
+
local block_p_out
; find the appropriate statement data to use for this block's body
block_p_out = statement_datas_ends
block_p_out += parse_stmt_depth < 3
- write_statement_header(out, STATEMENT_BLOCK, token)
- out += 8
*8out = *8block_p_out
out += 32
@@ -394,7 +450,7 @@ function parse_statement
; empty statement, e.g. while(something)-> ; <-
token += 16 ; skip semicolon
goto parse_statement_ret
-
+
function print_statement
argument statement
print_statement_with_depth(statement, 0)
@@ -427,11 +483,13 @@ function print_statement_with_depth
dat4 = statement + 32
dat4 = *8dat4
- if c == STATEMENT_LABEL goto print_stmt_label
if c == STATEMENT_BLOCK goto print_stmt_block
if c == STATEMENT_CONTINUE goto print_stmt_continue
if c == STATEMENT_BREAK goto print_stmt_break
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)
:pristmtNI
@@ -480,7 +538,19 @@ function print_statement_with_depth
:print_block_loop_end
putcln('})
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
; e.g. int x[5] = {1+8, 2, 3, 4, 5};
; advances *p_token to the token right after the initializer
@@ -2367,8 +2437,8 @@ function type_alignof
; evaluate an expression which can be the size of an array, e.g.
; enum { A, B, C };
; int x[A * sizeof(float) + 3 << 5];
-; @NONSTANDARD: doesn't handle floats, but really why would you use floats in an array size
-; e.g. SomeType x[(int)3.3];
+; @NONSTANDARD: doesn't handle floats. this means you can't do
+; e.g. double x[] = {1.5,2.3};
; this is also used for #if evaluation
; 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)