Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MLEMutator.cc

    re39aa0f r994ec2c  
    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"
    3029
    3130namespace ControlStruct {
     
    3433                targetTable = 0;
    3534        }
    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,
     35
     36        // break labels have to come after the statement they break out of,
    4137        // so mutate a statement, then if they inform us through the breakLabel field
    42         // tha they need a place to jump to on a break statement, add the break label
     38        // tha they need a place to jump to on a break statement, add the break label 
    4339        // to the body of statements
    4440        void MLEMutator::fixBlock( std::list< Statement * > &kids ) {
     
    4844                        if ( ! get_breakLabel().empty() ) {
    4945                                std::list< Statement * >::iterator next = k+1;
    50                                 std::list<Label> ls; ls.push_back( get_breakLabel() );
    51                                 kids.insert( next, new NullStmt( ls ) );
     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
    5253                                set_breakLabel("");
    5354                        } // if
     
    5960                if ( labeledBlock ) {
    6061                        Label brkLabel = generator->newLabel("blockBreak");
    61                         enclosingControlStructures.push_back( Entry( cmpndStmt, brkLabel ) );
     62                        enclosingBlocks.push_back( Entry( cmpndStmt, brkLabel ) );
    6263                } // if
    6364
     
    6869
    6970                if ( labeledBlock ) {
    70                         assert( ! enclosingControlStructures.empty() );
    71                         if ( ! enclosingControlStructures.back().useBreakExit().empty() ) {
    72                                 set_breakLabel( enclosingControlStructures.back().useBreakExit() );
     71                        assert( ! enclosingBlocks.empty() );
     72                        if ( ! enclosingBlocks.back().useBreakExit().empty() ) {
     73                                set_breakLabel( enclosingBlocks.back().useBreakExit() );
    7374                        }
    74                         enclosingControlStructures.pop_back();
     75                        enclosingBlocks.pop_back();
    7576                } // if
    7677
     
    8081        template< typename LoopClass >
    8182        Statement *MLEMutator::handleLoopStmt( LoopClass *loopStmt ) {
    82                 // remember this as the most recent enclosing loop, then mutate
     83                // remember this as the most recent enclosing loop, then mutate 
    8384                // the body of the loop -- this will determine whether brkLabel
    8485                // and contLabel are used with branch statements
     
    8687                Label brkLabel = generator->newLabel("loopBreak");
    8788                Label contLabel = generator->newLabel("loopContinue");
    88                 enclosingControlStructures.push_back( Entry( loopStmt, brkLabel, contLabel ) );
     89                enclosingLoops.push_back( Entry( loopStmt, brkLabel, contLabel ) );
    8990                loopStmt->set_body ( loopStmt->get_body()->acceptMutator( *this ) );
    9091
    9192                // sanity check that the enclosing loops have been popped correctly
    92                 Entry &e = enclosingControlStructures.back();
     93                Entry &e = enclosingLoops.back();
    9394                assert ( e == loopStmt );
    9495
     
    9697                // two labels, if they are used.
    9798                loopStmt->set_body( mutateLoop( loopStmt->get_body(), e ) );
    98                 enclosingControlStructures.pop_back();
     99                enclosingLoops.pop_back();
    99100
    100101                return loopStmt;
     
    110111        template< typename SwitchClass >
    111112        Statement *MLEMutator::handleSwitchStmt( SwitchClass *switchStmt ) {
    112                 // generate a label for breaking out of a labeled switch
     113                // generate a label for breaking out of a labeled switch 
    113114                Label brkLabel = generator->newLabel("switchBreak");
    114                 enclosingControlStructures.push_back( Entry(switchStmt, brkLabel) );
    115                 mutateAll( switchStmt->get_branches(), *this );
    116 
    117                 Entry &e = enclosingControlStructures.back();
     115                enclosingSwitches.push_back( Entry(switchStmt, brkLabel) );
     116                mutateAll( switchStmt->get_branches(), *this ); 
     117
     118                Entry &e = enclosingSwitches.back();
    118119                assert ( e == switchStmt );
    119120
    120121                // only generate break label if labeled break is used
    121122                if (e.isBreakUsed()) {
    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
     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 
    124125                        // last case statement; create a default case if there are no cases
    125126                        std::list< Statement * > &branches = switchStmt->get_branches();
     
    130131                        if ( CaseStmt * c = dynamic_cast< CaseStmt * >( branches.back() ) ) {
    131132                                std::list<Label> temp; temp.push_back( brkLabel );
    132                                 c->get_statements().push_back( new BranchStmt( temp, Label("brkLabel"), BranchStmt::Break ) );
     133                                c->get_statements().push_back( new BranchStmt( temp, Label(""), BranchStmt::Break ) );
    133134                        } else assert(0); // as of this point, all branches of a switch are still CaseStmts
    134135                }
    135136
    136                 assert ( enclosingControlStructures.back() == switchStmt );
    137                 enclosingControlStructures.pop_back();
     137                assert ( enclosingSwitches.back() == switchStmt );
     138                enclosingSwitches.pop_back();
    138139                return switchStmt;
    139140        }
     
    142143                std::string originalTarget = branchStmt->get_originalTarget();
    143144
    144                 std::list< Entry >::reverse_iterator targetEntry;
    145                 if ( branchStmt->get_type() == BranchStmt::Goto ) {
     145                if ( branchStmt->get_type() == BranchStmt::Goto )
    146146                        return branchStmt;
    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()] );
     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 );
    154154                        }
    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() ) {
     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() )
    166163                        throw SemanticError("The label defined in the exit loop statement does not exist: " + originalTarget );  // shouldn't happen (since that's already checked)
    167                 }
    168 
    169                 // xxx - possibly remove this
     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
    170173                // what about exiting innermost block or switch???
    171                 // if ( enclosingControlStructures.back() == (*targetEntry) )
    172                 //      return branchStmt;                              // exit the innermost loop (labels unnecessary)
     174                if ( enclosingLoops.back() == (*check) )
     175                        return branchStmt;                              // exit the innermost loop (labels unnecessary)
    173176
    174177                // branch error checks, get the appropriate label name and create a goto
     
    176179                switch ( branchStmt->get_type() ) {
    177180                  case BranchStmt::Break:
    178                                 assert( targetEntry->useBreakExit() != "");
    179                                 exitLabel = targetEntry->useBreakExit();
     181                                assert( check->useBreakExit() != "");
     182                                exitLabel = check->useBreakExit();
    180183                                break;
    181184                  case BranchStmt::Continue:
    182                                 assert( targetEntry->useContExit() != "");
    183                                 exitLabel = targetEntry->useContExit();
     185                                assert( check->useContExit() != "");
     186                                exitLabel = check->useContExit();
    184187                                break;
    185188                  default:
     
    187190                } // switch
    188191
    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                 }
     192                return new BranchStmt( std::list<Label>(), exitLabel, BranchStmt::Goto );
    199193        }
    200194
     
    212206                        // continue label goes in the body as the last statement
    213207                        std::list< Label > labels; labels.push_back( e.useContExit() );
    214                         newBody->get_kids().push_back( new NullStmt( labels ) );
     208                        newBody->get_kids().push_back( new NullStmt( labels ) );                       
    215209                }
    216210
    217211                if ( e.isBreakUsed() ) {
    218                         // break label goes after the loop -- it'll get set by the
     212                        // break label goes after the loop -- it'll get set by the 
    219213                        // outer mutator if we do this
    220                         set_breakLabel( e.useBreakExit() );
     214                        set_breakLabel( e.useBreakExit() );                     
    221215                }
    222216
     
    237231
    238232        Statement *MLEMutator::mutate( ChooseStmt *switchStmt ) {
    239                 return handleSwitchStmt( switchStmt );
     233                return handleSwitchStmt( switchStmt );         
    240234        }
    241235
Note: See TracChangeset for help on using the changeset viewer.