@@ -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,23 @@ 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+     label_t  * l  =  & labels [label_idx ++ ];
62+     strncpy (l -> label_name , name , MAX_ID_LEN );
63+     l -> bb  =  bb ;
64+ }
65+ 
4366char  * gen_name_to (char  * buf )
4467{
4568    sprintf (buf , ".t%d" , global_var_idx ++ );
@@ -997,6 +1020,59 @@ basic_block_t *handle_while_statement(block_t *parent, basic_block_t *bb)
9971020    return  else_ ;
9981021}
9991022
1023+ basic_block_t  * handle_goto_statement (block_t  * parent , basic_block_t  * bb )
1024+ {
1025+     /* Since a goto splits the current program into two basic blocks and makes 
1026+      * the subsequent basic block unreachable, this causes problems for later 
1027+      * CFG operations. Therefore, we create a fake if that always executes to 
1028+      * wrap the goto, and connect the unreachable basic block to the else 
1029+      * branch. Finally, return this else block. 
1030+      * 
1031+      * after: 
1032+      * code1; 
1033+      * goto label; 
1034+      * code2; 
1035+      * 
1036+      * before: 
1037+      * code1; 
1038+      * if (1) goto label; 
1039+      * code2; 
1040+      */ 
1041+ 
1042+     char  token [MAX_ID_LEN ];
1043+     if  (!lex_peek (T_identifier , token )) {
1044+         error ("Expected identifier after 'goto'" );
1045+         return  NULL ;
1046+     }
1047+ 
1048+     lex_expect (T_identifier );
1049+     lex_expect (T_semicolon );
1050+ 
1051+     basic_block_t  * fake_if  =  bb_create (parent );
1052+     bb_connect (bb , fake_if , NEXT );
1053+     var_t  * val  =  require_var (parent );
1054+     gen_name_to (val -> var_name );
1055+     val -> init_val  =  1 ;
1056+     add_insn (parent , fake_if , OP_load_constant , val , NULL , NULL , 0 , NULL );
1057+     add_insn (parent , fake_if , OP_branch , NULL , val , NULL , 0 , NULL );
1058+ 
1059+     basic_block_t  * then_  =  bb_create (parent );
1060+     basic_block_t  * else_  =  bb_create (parent );
1061+     bb_connect (fake_if , then_ , THEN );
1062+     bb_connect (fake_if , else_ , ELSE );
1063+ 
1064+     add_insn (parent , then_ , OP_jump , NULL , NULL , NULL , 0 , token );
1065+     label_t  * label  =  find_label (token );
1066+     if  (label ) {
1067+         label -> used  =  true;
1068+         bb_connect (then_ , label -> bb , NEXT );
1069+         return  else_ 
1070+     }
1071+ 
1072+     backpatch_bb [backpatch_bb_idx ++ ] =  then_ ;
1073+     return  else_ ;
1074+ }
1075+ 
10001076basic_block_t  * handle_struct_variable_decl (block_t  * parent ,
10011077                                           basic_block_t  * bb ,
10021078                                           char  * token )
@@ -4169,6 +4245,9 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
41694245        return  do_while_end ;
41704246    }
41714247
4248+     if  (lex_accept (T_goto ))
4249+         return  handle_goto_statement (parent , bb );
4250+ 
41724251    /* empty statement */ 
41734252    if  (lex_accept (T_semicolon ))
41744253        return  bb ;
@@ -4753,6 +4832,22 @@ basic_block_t *read_body_statement(block_t *parent, basic_block_t *bb)
47534832        return  bb ;
47544833    }
47554834
4835+     if  (lex_peek (T_identifier , token )) {
4836+         lex_accept (T_identifier );
4837+         if  (lex_accept (T_colon )) {
4838+             label_t  * l  =  find_label (token );
4839+             if  (l ) {
4840+                 error ("label redefinition" );
4841+                 return  NULL ;
4842+             }
4843+             basic_block_t  * n  =  bb_create (parent );
4844+             bb_connect (bb , n , NEXT );
4845+             add_label (token , n );
4846+             add_insn (parent , n , OP_label , NULL , NULL , NULL , 0 , token );
4847+             return  n ;
4848+         }
4849+     }
4850+ 
47564851    error ("Unrecognized statement token" );
47574852    return  NULL ;
47584853}
@@ -4794,6 +4889,27 @@ void read_func_body(func_t *func)
47944889    basic_block_t  * body  =  read_code_block (func , NULL , NULL , func -> bbs );
47954890    if  (body )
47964891        bb_connect (body , func -> exit , NEXT );
4892+ 
4893+     for  (int  i  =  0 ; i  <  backpatch_bb_idx ; i ++ ) {
4894+         basic_block_t  * bb  =  backpatch_bb [i ];
4895+         insn_t  * g  =  bb -> insn_list .tail ;
4896+         label_t  * label  =  find_label (g -> str );
4897+         if  (!label ) {
4898+             error ("goto label undefined" );
4899+         } else  {
4900+             label -> used  =  true;
4901+             bb_connect (bb , label -> bb , NEXT );
4902+         }
4903+     }
4904+ 
4905+     for  (int  i  =  0 ; i  <  label_idx ; i ++ ) {
4906+         label_t  * label  =  & labels [i ];
4907+         if  (!label -> used )
4908+             printf ("Warning: unused label %s\n" , label -> label_name );
4909+     }
4910+ 
4911+     backpatch_bb_idx  =  0 ;
4912+     label_idx  =  0 ;
47974913}
47984914
47994915/* if first token is type */ 
0 commit comments