source: src/ControlStruct/MLEMutator.cc @ d939274

aaron-thesisarm-ehcleanup-dtorsctordeferred_resndemanglerenumforall-pointer-decaygc_noraiijacob/cs343-translationjenkins-sandboxmemorynew-astnew-ast-unique-exprnew-envno_listpersistent-indexerresolv-newstringwith_gc
Last change on this file since d939274 was d939274, checked in by Rob Schluntz <rschlunt@…>, 7 years ago

documentation, reformatting, operator+ for iterators

  • Property mode set to 100644
File size: 8.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// MLEMutator.cc --
8//
9// Author           : Rodolfo G. Esteves
10// Created On       : Mon May 18 07:44:20 2015
11// Last Modified By : Rob Schluntz
12// Last Modified On : Tue Jun 02 13:43:01 2015
13// Update Count     : 92
14//
15
16#include <cassert>
17#include <algorithm>
18
19#include "MLEMutator.h"
20#include "SynTree/Statement.h"
21
22namespace ControlStruct {
23        MLEMutator::~MLEMutator() {
24                delete targetTable;
25                targetTable = 0;
26        }
27
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();
38                for ( std::list< Statement * >::iterator k = kids.begin(); k != kids.end(); k++ ) {
39                        *k = (*k)->acceptMutator(*this);
40
41                        if ( ! get_breakLabel().empty() ) {
42                                std::list< Statement * >::iterator next = k+1;
43                                if ( next == kids.end() ) {
44                                        std::list<Label> ls; ls.push_back( get_breakLabel() );
45                                        kids.push_back( new NullStmt( ls ) );
46                                } else {
47                                        (*next)->get_labels().push_back( get_breakLabel() );
48                                }
49
50                                set_breakLabel("");
51                        } // if
52                } // for
53
54                if ( labeledBlock ) {
55                        assert( ! enclosingBlocks.empty() );
56                        if ( ! enclosingBlocks.back().get_breakExit().empty() ) {
57                                set_breakLabel( enclosingBlocks.back().get_breakExit() );
58                        }
59                        enclosingBlocks.pop_back();
60                } // if
61
62                return cmpndStmt;
63        }
64
65        Statement *MLEMutator::mutate( WhileStmt *whileStmt ) {
66                enclosingLoops.push_back( Entry( whileStmt ) );
67                whileStmt->set_body ( whileStmt->get_body()->acceptMutator( *this ) );
68
69                Entry &e = enclosingLoops.back();
70                assert ( e == whileStmt );
71                whileStmt->set_body( mutateLoop( whileStmt->get_body(), e ) );
72                enclosingLoops.pop_back();
73
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;
87        }
88
89        Statement *MLEMutator::mutate( BranchStmt *branchStmt ) throw ( SemanticError ) {
90                std::string originalTarget = branchStmt->get_originalTarget();
91
92                if ( branchStmt->get_type() == BranchStmt::Goto )
93                        return branchStmt;
94
95                // test if continue target is a loop
96                if ( branchStmt->get_type() == BranchStmt::Continue) {
97                        if ( enclosingLoops.empty() ) {
98                                throw SemanticError( "'continue' outside a loop" );
99                        } else if ( std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) == enclosingLoops.end() ) {
100                                throw SemanticError( "'continue' target label must be an enclosing loop: " + originalTarget );
101                        }
102                }
103
104                if ( branchStmt->get_type() == BranchStmt::Break && (enclosingLoops.empty() && enclosingSwitches.empty() && enclosingBlocks.empty() ) )
105                        throw SemanticError( "'break' outside a loop or switch" );
106
107                if ( branchStmt->get_target() == "" ) return branchStmt;
108
109                if ( targetTable->find( branchStmt->get_target() ) == targetTable->end() )
110                        throw SemanticError("The label defined in the exit loop statement does not exist: " + originalTarget );  // shouldn't happen (since that's already checked)
111
112                std::list< Entry >::iterator check;
113                if ( ( check = std::find( enclosingLoops.begin(), enclosingLoops.end(), (*targetTable)[branchStmt->get_target()] ) ) == enclosingLoops.end() )
114                        // not in loop, checking if in block
115                        if ( (check = std::find( enclosingBlocks.begin(), enclosingBlocks.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingBlocks.end() )
116                                // neither in loop nor in block, checking if in switch/choose
117                                if ( (check = std::find( enclosingSwitches.begin(), enclosingSwitches.end(), (*targetTable)[branchStmt->get_target()] )) == enclosingSwitches.end() )
118                                        throw SemanticError("The target specified in the exit loop statement does not correspond to an enclosing control structure: " + originalTarget );
119
120                if ( enclosingLoops.back() == (*check) )
121                        return branchStmt;                              // exit the innermost loop (labels unnecessary)
122
123                Label newLabel;
124                switch ( branchStmt->get_type() ) {
125                  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
132                                break;
133                  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
140                                break;
141                  default:
142                                return 0;                                       // shouldn't be here
143                } // switch
144
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 );           
185        }
186
187        Statement *MLEMutator::mutateLoop( Statement *bodyLoop, Entry &e ) {
188                // ensure loop body is a block
189                CompoundStmt *newBody;
190                if ( ! (newBody = dynamic_cast<CompoundStmt *>( bodyLoop )) ) {
191                        newBody = new CompoundStmt( std::list< Label >() );
192                        newBody->get_kids().push_back( bodyLoop );
193                } // if
194
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
216
217                return newBody;
218        }
219
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        }
230} // namespace ControlStruct
231
232// Local Variables: //
233// tab-width: 4 //
234// mode: c++ //
235// compile-command: "make install" //
236// End: //
Note: See TracBrowser for help on using the repository browser.