@@ -26,6 +26,12 @@ int break_exit_idx = 0;
2626basic_block_t * continue_bb [MAX_NESTING ];
2727int continue_pos_idx = 0 ;
2828
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+
2935/* stack of the operands of 3AC */
3036var_t * operand_stack [MAX_OPERAND_STACK_SIZE ];
3137int operand_stack_idx = 0 ;
@@ -40,6 +46,26 @@ void parse_array_init(var_t *var,
4046 basic_block_t * * bb ,
4147 bool emit_code );
4248
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+ if (label_idx > MAX_LABELS - 1 )
62+ error ("Too many labels in function" );
63+
64+ label_t * l = & labels [label_idx ++ ];
65+ strncpy (l -> label_name , name , MAX_ID_LEN );
66+ l -> bb = bb ;
67+ }
68+
4369char * gen_name_to (char * buf )
4470{
4571 sprintf (buf , ".t%d" , global_var_idx ++ );
@@ -997,6 +1023,61 @@ basic_block_t *handle_while_statement(block_t *parent, basic_block_t *bb)
9971023 return else_ ;
9981024}
9991025
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+ * a = b + c;
1036+ * goto label;
1037+ * c *= d;
1038+ *
1039+ * before:
1040+ * a = b + c;
1041+ * if (1)
1042+ * goto label;
1043+ * c *= d;
1044+ */
1045+
1046+ char token [MAX_ID_LEN ];
1047+ if (!lex_peek (T_identifier , token ))
1048+ error ("Expected identifier after 'goto'" );
1049+
1050+ lex_expect (T_identifier );
1051+ lex_expect (T_semicolon );
1052+
1053+ basic_block_t * fake_if = bb_create (parent );
1054+ bb_connect (bb , fake_if , NEXT );
1055+ var_t * val = require_var (parent );
1056+ gen_name_to (val -> var_name );
1057+ val -> init_val = 1 ;
1058+ add_insn (parent , fake_if , OP_load_constant , val , NULL , NULL , 0 , NULL );
1059+ add_insn (parent , fake_if , OP_branch , NULL , val , NULL , 0 , NULL );
1060+
1061+ basic_block_t * then_ = bb_create (parent );
1062+ basic_block_t * else_ = bb_create (parent );
1063+ bb_connect (fake_if , then_ , THEN );
1064+ bb_connect (fake_if , else_ , ELSE );
1065+
1066+ add_insn (parent , then_ , OP_jump , NULL , NULL , NULL , 0 , token );
1067+ label_t * label = find_label (token );
1068+ if (label ) {
1069+ label -> used = true;
1070+ bb_connect (then_ , label -> bb , NEXT );
1071+ return else_ ;
1072+ }
1073+
1074+ if (backpatch_bb_idx > MAX_LABELS - 1 )
1075+ error ("Too many forward-referenced labels" );
1076+
1077+ backpatch_bb [backpatch_bb_idx ++ ] = then_ ;
1078+ return else_ ;
1079+ }
1080+
10001081basic_block_t * handle_struct_variable_decl (block_t * parent ,
10011082 basic_block_t * bb ,
10021083 char * token )
@@ -4169,6 +4250,9 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
41694250 return do_while_end ;
41704251 }
41714252
4253+ if (lex_accept (T_goto ))
4254+ return handle_goto_statement (parent , bb );
4255+
41724256 /* empty statement */
41734257 if (lex_accept (T_semicolon ))
41744258 return bb ;
@@ -4753,6 +4837,21 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
47534837 return bb ;
47544838 }
47554839
4840+ if (lex_peek (T_identifier , token )) {
4841+ lex_accept (T_identifier );
4842+ if (lex_accept (T_colon )) {
4843+ label_t * l = find_label (token );
4844+ if (l )
4845+ error ("label redefinition" );
4846+
4847+ basic_block_t * n = bb_create (parent );
4848+ bb_connect (bb , n , NEXT );
4849+ add_label (token , n );
4850+ add_insn (parent , n , OP_label , NULL , NULL , NULL , 0 , token );
4851+ return n ;
4852+ }
4853+ }
4854+
47564855 error ("Unrecognized statement token" );
47574856 return NULL ;
47584857}
@@ -4794,6 +4893,28 @@ void read_func_body(func_t *func)
47944893 basic_block_t * body = read_code_block (func , NULL , NULL , func -> bbs );
47954894 if (body )
47964895 bb_connect (body , func -> exit , NEXT );
4896+
4897+ for (int i = 0 ; i < backpatch_bb_idx ; i ++ ) {
4898+ basic_block_t * bb = backpatch_bb [i ];
4899+ insn_t * g = bb -> insn_list .tail ;
4900+ label_t * label = find_label (g -> str );
4901+ if (!label )
4902+ error ("goto label undefined" );
4903+
4904+ label -> used = true;
4905+ bb_connect (bb , label -> bb , NEXT );
4906+ }
4907+
4908+ for (int i = 0 ; i < label_idx ; i ++ ) {
4909+ label_t * label = & labels [i ];
4910+ if (label -> used )
4911+ continue ;
4912+
4913+ printf ("Warning: unused label %s\n" , label -> label_name );
4914+ }
4915+
4916+ backpatch_bb_idx = 0 ;
4917+ label_idx = 0 ;
47974918}
47984919
47994920/* if first token is type */
0 commit comments