Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MLEMutator.cc

    r994ec2c re39aa0f  
    55// file "LICENCE" distributed with Cforall.
    66//
    7 // MLEMutator.cc -- 
     7// MLEMutator.cc --
    88//
    99// Author           : Rodolfo G. Esteves
     
    1414//
    1515
    16 // NOTE: There are two known subtle differences from the code that uC++ 
     16// NOTE: There are two known subtle differences from the code that uC++
    1717// generates for the same input
    1818// -CFA puts the break label inside at the end of a switch, uC++ puts it after
     
    2727#include "SynTree/Statement.h"
    2828#include "SynTree/Expression.h"
     29#include "SynTree/Attribute.h"
    2930
    3031namespace ControlStruct {
     
    3334                targetTable = 0;
    3435        }
    35 
    36         // break labels have to come after the statement they break out of,
     36        namespace {
     37                Statement * isLoop( Statement * stmt ) { return dynamic_cast< WhileStmt * >( stmt ) ? stmt : dynamic_cast< ForStmt * >( stmt ) ? stmt : 0; }
     38        }
     39
     40        // break labels have to come after the statement they break out of,
    3741        // so mutate a statement, then if they inform us through the breakLabel field
    38         // tha they need a place to jump to on a break statement, add the break label 
     42        // tha they need a place to jump to on a break statement, add the break label
    3943        // to the body of statements
    4044        void MLEMutator::fixBlock( std::list< Statement * > &kids ) {
     
    4448                        if ( ! get_breakLabel().empty() ) {
    4549                                std::list< Statement * >::iterator next = k+1;
    46                                 if ( next == kids.end() ) {
    47                                         std::list<Label> ls; ls.push_back( get_breakLabel() );
    48                                         kids.push_back( new NullStmt( ls ) );
    49                                 } else {
    50                                         (*next)->get_labels().push_back( get_breakLabel() );
    51                                 }
    52 
     50                                std::list<Label> ls; ls.push_back( get_breakLabel() );
     51                                kids.insert( next, new NullStmt( ls ) );
    5352                                set_breakLabel("");
    5453                        } // if
     
    6059                if ( labeledBlock ) {
    6160                        Label brkLabel = generator->newLabel("blockBreak");
    62                         enclosingBlocks.push_back( Entry( cmpndStmt, brkLabel ) );
     61                        enclosingControlStructures.push_back( Entry( cmpndStmt, brkLabel ) );
    6362                } // if
    6463
     
    6968
    7069                if ( labeledBlock ) {
    71                         assert( ! enclosingBlocks.empty() );
    72                         if ( ! enclosingBlocks.back().useBreakExit().empty() ) {
    73                                 set_breakLabel( enclosingBlocks.back().useBreakExit() );
    74                         }
    75                         enclosingBlocks.pop_back();
     70                        assert( ! enclosingControlStructures.empty() );
     71                        if ( ! enclosingControlStructures.back().useBreakExit().empty() ) {
     72                                set_breakLabel( enclosingControlStructures.back().useBreakExit() );
     73                        }
     74                        enclosingControlStructures.pop_back();
    7675                } // if
    7776
     
    8180        template< typename LoopClass >
    8281        Statement *MLEMutator::handleLoopStmt( LoopClass *loopStmt ) {
    83                 // remember this as the most recent enclosing loop, then mutate 
     82                // remember this as the most recent enclosing loop, then mutate
    8483                // the body of the loop -- this will determine whether brkLabel
    8584                // and contLabel are used with branch statements
     
    8786                Label brkLabel = generator->newLabel("loopBreak");
    8887                Label contLabel = generator->newLabel("loopContinue");
    89                 enclosingLoops.push_back( Entry( loopStmt, brkLabel, contLabel ) );
     88                enclosingControlStructures.push_back( Entry( loopStmt, brkLabel, contLabel ) );
    9089                loopStmt->set_body ( loopStmt->get_body()->acceptMutator( *this ) );
    9190
    9291                // sanity check that the enclosing loops have been popped correctly
    93                 Entry &e = enclosingLoops.back();
     92                Entry &e = enclosingControlStructures.back();
    9493                assert ( e == loopStmt );
    9594
     
    9796                // two labels, if they are used.
    9897                loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) );
    99                 enclosingLoops.pop_back();
     98                enclosingControlStructures.pop_back();
    10099
    101100                return loopStmt;
     
    111110        template< typename SwitchClass >
    112111        Statement *MLEMutator::handleSwitchStmt( SwitchClass *switchStmt ) {
    113                 // generate a label for breaking out of a labeled switch 
     112                // generate a label for breaking out of a labeled switch
    114113                Label brkLabel = generator->newLabel("switchBreak");
    115                 enclosingSwitches.push_back( Entry(switchStmt, brkLabel) );
    116                 mutateAll( switchStmt->get_branches(), *this ); 
    117 
    118                 Entry &e = enclosingSwitches.back();
     114                enclosingControlStructures.push_back( Entry(switchStmt, brkLabel) );
     115                mutateAll( switchStmt->get_branches(), *this );
     116
     117                Entry &e = enclosingControlStructures.back();
    119118                assert ( e == switchStmt );
    120119
    121120                // only generate break label if labeled break is used
    122121                if (e.isBreakUsed()) {
    123                         // for the purposes of keeping switch statements uniform (i.e. all statements that are 
    124                         // direct children of a switch should be CastStmts), append the exit label + break to the 
     122                        // for the purposes of keeping switch statements uniform (i.e. all statements that are
     123                        // direct children of a switch should be CastStmts), append the exit label + break to the
    125124                        // last case statement; create a default case if there are no cases
    126125                        std::list< Statement * > &branches = switchStmt->get_branches();
     
    131130                        if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) {
    132131                                std::list<Label> temp; temp.push_back( brkLabel );
    133                                 c->get_statements().push_back( new BranchStmt( temp, Label(""), BranchStmt::Break ) );
     132                                c->get_statements().push_back( new BranchStmt( temp, Label("brkLabel"), BranchStmt::Break ) );
    134133                        } else assert(0); // as of this point, all branches of a switch are still CaseStmts
    135134                }
    136135
    137                 assert ( enclosingSwitches.back() == switchStmt );
    138                 enclosingSwitches.pop_back();
     136                assert ( enclosingControlStructures.back() == switchStmt );
     137                enclosingControlStructures.pop_back();
    139138                return switchStmt;
    140139        }
     
    143142                std::string originalTarget = branchStmt->get_originalTarget();
    144143
    145                 if ( branchStmt->get_type() == BranchStmt::Goto )
     144                std::list< Entry >::reverse_iterator targetEntry;
     145                if ( branchStmt->get_type() == BranchStmt::Goto ) {
    146146                        return branchStmt;
    147 
    148                 // test if continue target is a loop
    149                 if ( branchStmt->get_type() == BranchStmt::Continue) {
    150                         if ( enclosingLoops.empty() ) {
    151                                 throw SemanticError( "'continue' outside a loop" );
    152                         } else if ( branchStmt->get_target() != "" && std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) == enclosingLoops.end() ) {
    153                                 throw SemanticError( "'continue' target label must be an enclosing loop: " + originalTarget );
    154                         }
    155                 }
    156 
    157                 if ( branchStmt->get_type() == BranchStmt::Break && (enclosingLoops.empty() && enclosingSwitches.empty() && enclosingBlocks.empty() ) )
    158                         throw SemanticError( "'break' outside a loop or switch" );
    159 
    160                 if ( branchStmt->get_target() == "" ) return branchStmt;
    161 
    162                 if ( targetTable->find( branchStmt->get_target() ) == targetTable->end() )
     147                } else if ( branchStmt->get_type() == BranchStmt::Continue) {
     148                        // continue target must be a loop
     149                        if ( branchStmt->get_target() == "" ) {
     150                                targetEntry = std::find_if( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), [](Entry &e) { return isLoop( e.get_controlStructure() ); } );
     151                        } else {
     152                                // labelled continue - lookup label in table ot find attached control structure
     153                                targetEntry = std::find( enclosingControlStructures.rbegin(), enclosingControlStructures.rend(), (*targetTable)[branchStmt->get_target()] );
     154                        }
     155                        if ( targetEntry == enclosingControlStructures.rend() || ! isLoop( targetEntry->get_controlStructure() ) ) {
     156                                throw SemanticError( "'continue' target must be an enclosing loop: " + originalTarget );
     157                        }
     158                } else if ( branchStmt->get_type() == BranchStmt::Break ) {
     159                        if ( enclosingControlStructures.empty() ) throw SemanticError( "'break' outside a loop, switch, or labelled block" );
     160                        targetEntry = enclosingControlStructures.rbegin();
     161                } else {
     162                        assert( false );
     163                }
     164
     165                if ( branchStmt->get_target() != "" && targetTable->find( branchStmt->get_target() ) == targetTable->end() ) {
    163166                        throw SemanticError("The label defined in the exit loop statement does not exist: " + originalTarget );  // shouldn't happen (since that's already checked)
    164 
    165                 std::list< Entry >::iterator check;
    166                 if ( ( check = std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) ) == enclosingLoops.end() )
    167                         // not in loop, checking if in block
    168                         if ( (check = std::find( enclosingBlocks.begin(), enclosingBlocks.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingBlocks.end() )
    169                                 // neither in loop nor in block, checking if in switch/choose
    170                                 if ( (check = std::find( enclosingSwitches.begin(), enclosingSwitches.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingSwitches.end() )
    171                                         throw SemanticError("The target specified in the exit loop statement does not correspond to an enclosing control structure: " + originalTarget );
    172 
     167                }
     168
     169                // xxx - possibly remove this
    173170                // what about exiting innermost block or switch???
    174                 if ( enclosingLoops.back() == (*check) )
    175                         return branchStmt;                              // exit the innermost loop (labels unnecessary)
     171                // if ( enclosingControlStructures.back() == (*targetEntry) )
     172                //      return branchStmt;                              // exit the innermost loop (labels unnecessary)
    176173
    177174                // branch error checks, get the appropriate label name and create a goto
     
    179176                switch ( branchStmt->get_type() ) {
    180177                  case BranchStmt::Break:
    181                                 assert( check->useBreakExit() != "");
    182                                 exitLabel = check->useBreakExit();
     178                                assert( targetEntry->useBreakExit() != "");
     179                                exitLabel = targetEntry->useBreakExit();
    183180                                break;
    184181                  case BranchStmt::Continue:
    185                                 assert( check->useContExit() != "");
    186                                 exitLabel = check->useContExit();
     182                                assert( targetEntry->useContExit() != "");
     183                                exitLabel = targetEntry->useContExit();
    187184                                break;
    188185                  default:
     
    190187                } // switch
    191188
    192                 return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
     189                if ( branchStmt->get_target() == "" && branchStmt->get_type() != BranchStmt::Continue ) {
     190                        // unlabelled break/continue - can keep branch as break/continue for extra semantic information, but add
     191                        // exitLabel as its destination so that label passes can easily determine where the break/continue goes to
     192                        branchStmt->set_target( exitLabel );
     193                        return branchStmt;
     194                } else {
     195                        // labelled break/continue - can't easily emulate this with break and continue, so transform into a goto
     196                        delete branchStmt;
     197                        return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
     198                }
    193199        }
    194200
     
    206212                        // continue label goes in the body as the last statement
    207213                        std::list< Label > labels; labels.push_back( e.useContExit() );
    208                         newBody->get_kids().push_back( new NullStmt( labels ) );                       
     214                        newBody->get_kids().push_back( new NullStmt( labels ) );
    209215                }
    210216
    211217                if ( e.isBreakUsed() ) {
    212                         // break label goes after the loop -- it'll get set by the 
     218                        // break label goes after the loop -- it'll get set by the
    213219                        // outer mutator if we do this
    214                         set_breakLabel( e.useBreakExit() );                     
     220                        set_breakLabel( e.useBreakExit() );
    215221                }
    216222
     
    231237
    232238        Statement *MLEMutator::mutate( ChooseStmt *switchStmt ) {
    233                 return handleSwitchStmt( switchStmt );         
     239                return handleSwitchStmt( switchStmt );
    234240        }
    235241
Note: See TracChangeset for help on using the changeset viewer.