@@ -26,6 +26,12 @@ int break_exit_idx = 0;
26
26
basic_block_t * continue_bb [MAX_NESTING ];
27
27
int continue_pos_idx = 0 ;
28
28
29
+ /* Label utilities */
30
+ label_t labels [MAX_LABELS ];
31
+ int label_idx = 0 ;
32
+ basic_block_t * backpatch_bb [MAX_LABELS ];
33
+ int backpatch_bb_idx = 0 ;
34
+
29
35
/* stack of the operands of 3AC */
30
36
var_t * operand_stack [MAX_OPERAND_STACK_SIZE ];
31
37
int operand_stack_idx = 0 ;
@@ -40,12 +46,30 @@ void parse_array_init(var_t *var,
40
46
basic_block_t * * bb ,
41
47
bool emit_code );
42
48
49
+
50
+ label_t * find_label (char * name )
51
+ {
52
+ for (int i = 0 ; i < label_idx ; i ++ ) {
53
+ if (!strcmp (name , labels [i ].label_name ))
54
+ return & labels [i ];
55
+ }
56
+ return NULL ;
57
+ }
58
+
59
+ void add_label (char * name , basic_block_t * bb )
60
+ {
61
+ label_t * l = & labels [label_idx ++ ];
62
+ strncpy (l -> label_name , name , MAX_ID_LEN );
63
+ l -> bb = bb ;
64
+ }
65
+
43
66
char * gen_name_to (char * buf )
44
67
{
45
68
sprintf (buf , ".t%d" , global_var_idx ++ );
46
69
return buf ;
47
70
}
48
71
72
+
49
73
var_t * require_var (block_t * blk )
50
74
{
51
75
var_list_t * var_list = & blk -> locals ;
@@ -997,6 +1021,60 @@ basic_block_t *handle_while_statement(block_t *parent, basic_block_t *bb)
997
1021
return else_ ;
998
1022
}
999
1023
1024
+
1025
+
1026
+ basic_block_t * handle_goto_statement (block_t * parent , basic_block_t * bb )
1027
+ {
1028
+ /* Since a goto splits the current program into two basic blocks and makes
1029
+ * the subsequent basic block unreachable, this causes problems for later
1030
+ * CFG operations. Therefore, we create a fake if that always executes to
1031
+ * wrap the goto, and connect the unreachable basic block to the else
1032
+ * branch. Finally, return this else block.
1033
+ *
1034
+ * after:
1035
+ * code1;
1036
+ * goto label;
1037
+ * code2;
1038
+ *
1039
+ * before:
1040
+ * code1;
1041
+ * if (1) goto label;
1042
+ * code2;
1043
+ */
1044
+
1045
+ char token [MAX_ID_LEN ];
1046
+ if (lex_peek (T_identifier , token )) {
1047
+ lex_expect (T_identifier );
1048
+ lex_expect (T_semicolon );
1049
+
1050
+ basic_block_t * fake_if = bb_create (parent );
1051
+ bb_connect (bb , fake_if , NEXT );
1052
+ var_t * val = require_var (parent );
1053
+ gen_name_to (val -> var_name );
1054
+ val -> init_val = 1 ;
1055
+ add_insn (parent , fake_if , OP_load_constant , val , NULL , NULL , 0 , NULL );
1056
+ add_insn (parent , fake_if , OP_branch , NULL , val , NULL , 0 , NULL );
1057
+
1058
+ basic_block_t * then_ = bb_create (parent );
1059
+ basic_block_t * else_ = bb_create (parent );
1060
+ bb_connect (fake_if , then_ , THEN );
1061
+ bb_connect (fake_if , else_ , ELSE );
1062
+
1063
+ label_t * label = find_label (token );
1064
+ add_insn (parent , then_ , OP_jump , NULL , NULL , NULL , 0 , token );
1065
+ if (label ) {
1066
+ label -> used = true;
1067
+ bb_connect (then_ , label -> bb , NEXT );
1068
+ } else {
1069
+ backpatch_bb [backpatch_bb_idx ++ ] = then_ ;
1070
+ }
1071
+ return else_ ;
1072
+ } else {
1073
+ error ("Expected identifier after 'goto'" );
1074
+ return NULL ;
1075
+ }
1076
+ }
1077
+
1000
1078
basic_block_t * handle_struct_variable_decl (block_t * parent ,
1001
1079
basic_block_t * bb ,
1002
1080
char * token )
@@ -4169,6 +4247,9 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
4169
4247
return do_while_end ;
4170
4248
}
4171
4249
4250
+ if (lex_accept (T_goto ))
4251
+ return handle_goto_statement (parent , bb );
4252
+
4172
4253
/* empty statement */
4173
4254
if (lex_accept (T_semicolon ))
4174
4255
return bb ;
@@ -4753,6 +4834,22 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
4753
4834
return bb ;
4754
4835
}
4755
4836
4837
+ if (lex_peek (T_identifier , token )) {
4838
+ lex_accept (T_identifier );
4839
+ if (lex_accept (T_colon )) {
4840
+ label_t * l = find_label (token );
4841
+ if (l ) {
4842
+ error ("label redefinition" );
4843
+ return NULL ;
4844
+ }
4845
+ basic_block_t * n = bb_create (parent );
4846
+ bb_connect (bb , n , NEXT );
4847
+ add_label (token , n );
4848
+ add_insn (parent , n , OP_label , NULL , NULL , NULL , 0 , token );
4849
+ return n ;
4850
+ }
4851
+ }
4852
+
4756
4853
error ("Unrecognized statement token" );
4757
4854
return NULL ;
4758
4855
}
@@ -4794,6 +4891,27 @@ void read_func_body(func_t *func)
4794
4891
basic_block_t * body = read_code_block (func , NULL , NULL , func -> bbs );
4795
4892
if (body )
4796
4893
bb_connect (body , func -> exit , NEXT );
4894
+
4895
+ for (int i = 0 ; i < backpatch_bb_idx ; i ++ ) {
4896
+ basic_block_t * bb = backpatch_bb [i ];
4897
+ insn_t * g = bb -> insn_list .tail ;
4898
+ label_t * label = find_label (g -> str );
4899
+ if (!label ) {
4900
+ error ("goto label undefined" );
4901
+ } else {
4902
+ label -> used = true;
4903
+ bb_connect (bb , label -> bb , NEXT );
4904
+ }
4905
+ }
4906
+
4907
+ for (int i = 0 ; i < label_idx ; i ++ ) {
4908
+ label_t * label = & labels [i ];
4909
+ if (!label -> used )
4910
+ printf ("Warning: unused label %s\n" , label -> label_name );
4911
+ }
4912
+
4913
+ backpatch_bb_idx = 0 ;
4914
+ label_idx = 0 ;
4797
4915
}
4798
4916
4799
4917
/* if first token is type */
0 commit comments