Ignore:
Timestamp:
Jun 3, 2015, 3:19:29 PM (9 years ago)
Author:
Rob Schluntz <rschlunt@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, ctor, deferred_resn, demangler, enum, forall-pointer-decay, gc_noraii, jacob/cs343-translation, jenkins-sandbox, master, memory, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, string, with_gc
Children:
4162aea9
Parents:
954463b8
Message:

fix multi-level exit code (labeled break and continue)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MLEMutator.cc

    r954463b8 r27de955  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Rob Schluntz
    12 // Last Modified On : Tue Jun 02 13:43:01 2015
    13 // Update Count     : 92
     12// Last Modified On : Wed Jun 03 15:09:27 2015
     13// Update Count     : 170
    1414//
    1515
     
    1919#include "MLEMutator.h"
    2020#include "SynTree/Statement.h"
     21#include "SynTree/Expression.h"
    2122
    2223namespace ControlStruct {
     
    2627        }
    2728
    28         CompoundStmt* MLEMutator::mutate( CompoundStmt *cmpndStmt ) {
    29                 bool labeledBlock = false;
    30                 if ( !(cmpndStmt->get_labels().empty()) ) {
    31                         labeledBlock = true;
    32                         enclosingBlocks.push_back( Entry( cmpndStmt ) );
    33                 } // if
    34 
    35                 // a child statement may set the break label
    36                 // - if they do, attach it to the next statement
    37                 std::list< Statement * > &kids = cmpndStmt->get_kids();
     29        // break labels have to come after the statement they break out of,
     30        // so mutate a statement, then if they inform us through the breakLabel field
     31        // tha they need a place to jump to on a break statement, add the break label
     32        // to the body of statements
     33        void MLEMutator::fixBlock( std::list< Statement * > &kids ) {
    3834                for ( std::list< Statement * >::iterator k = kids.begin(); k != kids.end(); k++ ) {
    3935                        *k = (*k)->acceptMutator(*this);
     
    5147                        } // if
    5248                } // for
     49        }
     50
     51        CompoundStmt* MLEMutator::mutate( CompoundStmt *cmpndStmt ) {
     52                bool labeledBlock = !(cmpndStmt->get_labels().empty());
     53                if ( labeledBlock ) {
     54                        Label brkLabel = generator->newLabel();
     55                        enclosingBlocks.push_back( Entry( cmpndStmt, brkLabel ) );
     56                } // if
     57
     58                // a child statement may set the break label
     59                // - if they do, attach it to the next statement
     60                std::list< Statement * > &kids = cmpndStmt->get_kids();
     61                fixBlock( kids );
    5362
    5463                if ( labeledBlock ) {
    5564                        assert( ! enclosingBlocks.empty() );
    56                         if ( ! enclosingBlocks.back().get_breakExit().empty() ) {
    57                                 set_breakLabel( enclosingBlocks.back().get_breakExit() );
     65                        if ( ! enclosingBlocks.back().useBreakExit().empty() ) {
     66                                set_breakLabel( enclosingBlocks.back().useBreakExit() );
    5867                        }
    5968                        enclosingBlocks.pop_back();
     
    6372        }
    6473
    65         Statement *MLEMutator::mutate( WhileStmt *whileStmt ) {
    66                 enclosingLoops.push_back( Entry( whileStmt ) );
    67                 whileStmt->set_body ( whileStmt->get_body()->acceptMutator( *this ) );
    68 
     74        template< typename LoopClass >
     75        Statement *MLEMutator::handleLoopStmt( LoopClass *loopStmt ) {
     76                // remember this as the most recent enclosing loop, then mutate
     77                // the body of the loop -- this will do SOMETHING with branch statements
     78                // and will recursively do the same to nested loops
     79                Label brkLabel = generator->newLabel("loopBreak");
     80                Label contLabel = generator->newLabel("loopContinue");
     81                enclosingLoops.push_back( Entry( loopStmt, brkLabel, contLabel ) );
     82                loopStmt->set_body ( loopStmt->get_body()->acceptMutator( *this ) );
     83
     84                // sanity check that the enclosing loops have been popped correctly
    6985                Entry &e = enclosingLoops.back();
    70                 assert ( e == whileStmt );
    71                 whileStmt->set_body( mutateLoop( whileStmt->get_body(), e ) );
     86                assert ( e == loopStmt );
     87
     88                // generate labels as needed
     89                loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) );
    7290                enclosingLoops.pop_back();
    7391
    74                 return whileStmt;
    75         }
    76 
    77         Statement *MLEMutator::mutate( ForStmt *forStmt ) {
    78                 enclosingLoops.push_back( Entry( forStmt ) );
    79                 forStmt->set_body( maybeMutate( forStmt->get_body(), *this ) );
    80 
    81                 Entry &e = enclosingLoops.back();
    82                 assert ( e == forStmt );
    83                 forStmt->set_body( mutateLoop( forStmt->get_body(), e ) );
    84                 enclosingLoops.pop_back();
    85 
    86                 return forStmt;
     92                return loopStmt;
     93        }
     94
     95        Statement *MLEMutator::mutate( CaseStmt *caseStmt ) {
     96                caseStmt->set_condition( maybeMutate( caseStmt->get_condition(), *this ) );
     97                fixBlock( caseStmt->get_statements() );
     98
     99                return caseStmt;
     100        }
     101
     102        template< typename SwitchClass >
     103        Statement *MLEMutator::handleSwitchStmt( SwitchClass *switchStmt ) {
     104                // generate a label for breaking out of a labeled switch
     105                Label brkLabel = generator->newLabel("switchBreak");
     106                enclosingSwitches.push_back( Entry(switchStmt, brkLabel) );
     107                mutateAll( switchStmt->get_branches(), *this );
     108
     109                Entry &e = enclosingSwitches.back();
     110                assert ( e == switchStmt );
     111
     112                // only generate break label if labeled break is used
     113                if (e.isBreakUsed()) {
     114                        // for the purposes of keeping switch statements uniform (i.e. all statements that are
     115                        // direct children of a switch should be CastStmts), append the exit label + break to the
     116                        // last case statement; create a default case if there are no cases
     117                        std::list< Statement * > &branches = switchStmt->get_branches();
     118                        if ( branches.empty() ) {
     119                                branches.push_back( CaseStmt::makeDefault() );
     120                        }
     121
     122                        if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) {
     123                                std::list<Label> temp; temp.push_back( brkLabel );
     124                                c->get_statements().push_back( new BranchStmt( temp, Label(""), BranchStmt::Break ) );
     125                        } else assert(0); // as of this point, all branches of a switch are still CaseStmts
     126                }
     127
     128                assert ( enclosingSwitches.back() == switchStmt );
     129                enclosingSwitches.pop_back();
     130                return switchStmt;
    87131        }
    88132
     
    118162                                        throw SemanticError("The target specified in the exit loop statement does not correspond to an enclosing control structure: " + originalTarget );
    119163
     164                // what about exiting innermost block or switch???
    120165                if ( enclosingLoops.back() == (*check) )
    121166                        return branchStmt;                              // exit the innermost loop (labels unnecessary)
    122167
    123                 Label newLabel;
     168                // branch error checks, get the appropriate label name and create a goto
     169                Label exitLabel;
    124170                switch ( branchStmt->get_type() ) {
    125171                  case BranchStmt::Break:
    126                                 if ( check->get_breakExit() != "" ) {
    127                                         newLabel = check->get_breakExit();
    128                                 } else {
    129                                         newLabel = generator->newLabel();
    130                                         check->set_breakExit( newLabel );
    131                                 } // if
     172                                assert( check->useBreakExit() != "");
     173                                exitLabel = check->useBreakExit();
    132174                                break;
    133175                  case BranchStmt::Continue:
    134                                 if ( check->get_contExit() != "" ) {
    135                                         newLabel = check->get_contExit();
    136                                 } else {
    137                                         newLabel = generator->newLabel();
    138                                         check->set_contExit( newLabel );
    139                                 } // if
     176                                assert( check->useContExit() != "");
     177                                exitLabel = check->useContExit();
    140178                                break;
    141179                  default:
    142                                 return 0;                                       // shouldn't be here
     180                                assert(0);                                      // shouldn't be here
    143181                } // switch
    144182
    145                 return new BranchStmt( std::list<Label>(), newLabel, BranchStmt::Goto );
    146         }
    147 
    148         template< typename SwitchClass >
    149         Statement *handleSwitchStmt( SwitchClass *switchStmt, MLEMutator &mutator ) {
    150                 // set up some aliases so that the rest of the code isn't messy
    151                 typedef MLEMutator::Entry Entry;
    152                 LabelGenerator *generator = mutator.generator;
    153                 std::list< Entry > &enclosingSwitches = mutator.enclosingSwitches;
    154 
    155                 Label brkLabel = generator->newLabel();
    156                 enclosingSwitches.push_back( Entry(switchStmt, "", brkLabel) );
    157                 mutateAll( switchStmt->get_branches(), mutator );
    158                 {
    159                         // check if this is necessary (if there is a break to this point, otherwise do not generate
    160 
    161                         // for the purposes of keeping switch statements uniform (i.e. all statements that are
    162                         // direct children of a switch should be CastStmts), append the exit label + break to the
    163                         // last case statement; create a default case if there are no cases
    164                         std::list< Statement * > &branches = switchStmt->get_branches();
    165                         if ( branches.empty() ) {
    166                                 branches.push_back( CaseStmt::makeDefault() );
    167                         }
    168 
    169                         if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) {
    170                                 std::list<Label> temp; temp.push_back( brkLabel );
    171                                 c->get_statements().push_back( new BranchStmt( temp, Label(""), BranchStmt::Break ) );
    172                         } else assert(0);
    173                 }
    174                 assert ( enclosingSwitches.back() == switchStmt );
    175                 enclosingSwitches.pop_back();
    176                 return switchStmt;
    177         }
    178 
    179         Statement *MLEMutator::mutate( SwitchStmt *switchStmt ) {
    180                 return handleSwitchStmt( switchStmt, *this );
    181         }
    182 
    183         Statement *MLEMutator::mutate( ChooseStmt *switchStmt ) {
    184                 return handleSwitchStmt( switchStmt, *this );           
     183                return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
    185184        }
    186185
     
    193192                } // if
    194193
    195                 Label endLabel = e.get_contExit();
    196 
    197                 if ( e.get_breakExit() != "" ) {
    198                         if ( endLabel == "" ) endLabel = generator->newLabel();
    199                         // check for whether this label is used or not, so as to not generate extraneous gotos
    200                         if (e.breakExitUsed)
    201                                 newBody->get_kids().push_back( new BranchStmt( std::list< Label >(), endLabel, BranchStmt::Goto ) );
    202                         // xxx
    203                         //std::list< Label > ls; ls.push_back( e.get_breakExit() );
    204                         set_breakLabel( e.get_breakExit() );
    205                         //newBody->get_kids().push_back( new BranchStmt( ls, "", BranchStmt::Break ) );
    206                 } // if
    207 
    208                 if ( e.get_breakExit() != "" || e.get_contExit() != "" ) {
    209                         if (dynamic_cast< NullStmt *>( newBody->get_kids().back() ))
    210                                 newBody->get_kids().back()->get_labels().push_back( endLabel );
    211                         else {
    212                                 std::list < Label > ls; ls.push_back( endLabel );
    213                                 newBody->get_kids().push_back( new NullStmt( ls ) );
    214                         } // if
    215                 } // if
     194                // only generate these when needed
     195
     196                if ( e.isContUsed() ) {
     197                        // continue label goes in the body as the last statement
     198                        std::list< Label > labels; labels.push_back( e.useContExit() );
     199                        newBody->get_kids().push_back( new NullStmt( labels ) );                       
     200                }
     201
     202                if ( e.isBreakUsed() ) {
     203                        // break label goes after the loop -- it'll get set by the
     204                        // outer mutator if we do this
     205                        set_breakLabel( e.useBreakExit() );                     
     206                }
    216207
    217208                return newBody;
    218209        }
    219210
    220         //*** Entry's methods - ensure these labels can be set at most once
    221         void MLEMutator::Entry::set_contExit( Label l ) {
    222                 assert ( contExit == "" || contExit == l );
    223                 contExit = l;
    224         }
    225 
    226         void MLEMutator::Entry::set_breakExit( Label l ) {
    227                 assert ( breakExit == "" || breakExit == l );
    228                 breakExit = l;
    229         }
     211        Statement *MLEMutator::mutate( WhileStmt *whileStmt ) {
     212                return handleLoopStmt( whileStmt );
     213        }
     214
     215        Statement *MLEMutator::mutate( ForStmt *forStmt ) {
     216                return handleLoopStmt( forStmt );
     217        }
     218
     219        Statement *MLEMutator::mutate( SwitchStmt *switchStmt ) {
     220                return handleSwitchStmt( switchStmt );
     221        }
     222
     223        Statement *MLEMutator::mutate( ChooseStmt *switchStmt ) {
     224                return handleSwitchStmt( switchStmt );         
     225        }
     226
    230227} // namespace ControlStruct
    231228
Note: See TracChangeset for help on using the changeset viewer.