ThymioIRVisitors.cpp
Go to the documentation of this file.
00001 #include <sstream>
00002 #include "ThymioIntermediateRepresentation.h"
00003 
00004 namespace Aseba
00005 {
00006         // Visitor base //
00007         void ThymioIRVisitor::visit(ThymioIRButton *button)
00008         {
00009                 errorCode = THYMIO_NO_ERROR;
00010         }
00011 
00012         void ThymioIRVisitor::visit(ThymioIRButtonSet *buttonSet)
00013         {
00014                 errorCode = THYMIO_NO_ERROR;
00015         }
00016 
00017         ThymioIRErrorCode ThymioIRVisitor::getErrorCode() const
00018         {
00019                 return errorCode;
00020         }
00021         
00022         bool ThymioIRVisitor::isSuccessful() const
00023         {
00024                 return ( errorCode == THYMIO_NO_ERROR ? true : false );
00025         }
00026 
00027         wstring ThymioIRVisitor::toWstring(int val)
00028         {
00029                 wstringstream streamVal;
00030                 streamVal << val;
00031                 
00032                 return streamVal.str(); 
00033         }
00034 
00035         // Type Checker //      
00036         ThymioIRTypeChecker::~ThymioIRTypeChecker()
00037         {
00038                 clear();
00039         }
00040         
00041         void ThymioIRTypeChecker::reset()
00042         {
00043                 clear();
00044         }
00045         
00046         void ThymioIRTypeChecker::clear()
00047         {
00048                 moveHash.clear();
00049                 colorHash.clear();
00050                 circleHash.clear();
00051                 soundHash.clear();
00052                 memoryHash.clear();
00053                 
00054                 tapSeenActions.clear();
00055                 clapSeenActions.clear();
00056                 
00057                 activeActionName = THYMIO_BUTTONS_IR;
00058         }
00059 
00060         void ThymioIRTypeChecker::visit(ThymioIRButton *button)
00061         {
00062                 if( button == 0 ) return;
00063 
00064                 errorCode = THYMIO_NO_ERROR;
00065                 
00066                 multimap<wstring, ThymioIRButton*> *currentHash;
00067                 multimap<wstring, ThymioIRButton*> tempHash;
00068                 
00069                 switch( activeActionName )
00070                 {
00071                 case THYMIO_MOVE_IR:
00072                         currentHash = &moveHash;
00073                         tempHash = moveHash;
00074                         break;
00075                 case THYMIO_COLOR_IR:
00076                         currentHash = &colorHash;
00077                         tempHash = colorHash;
00078                         break;
00079                 case THYMIO_CIRCLE_IR:
00080                         currentHash = &circleHash;
00081                         tempHash = circleHash;
00082                         break;
00083                 case THYMIO_SOUND_IR:
00084                         currentHash = &soundHash;
00085                         tempHash = soundHash;
00086                         break;
00087                 case THYMIO_MEMORY_IR:
00088                         currentHash = &memoryHash;
00089                         tempHash = memoryHash;
00090                         break;
00091                 default:
00092                         return;
00093                         break;
00094                 }
00095 
00096                 currentHash->clear();
00097         
00098                 for(multimap<wstring, ThymioIRButton*>::iterator itr = tempHash.begin();
00099                         itr != tempHash.end(); ++itr)
00100                 {
00101                         if( itr->second != button )
00102                                 currentHash->insert(*itr);
00103                 }
00104 
00105                 wstring buttonname = button->getBasename() + L"_" + toWstring(button->getMemoryState());;
00106                 for(int i=0; i<button->size(); i++)
00107                 {       
00108                         if( button->isClicked(i) > 0 )
00109                         {
00110                                 buttonname += L"_";
00111                                 buttonname += toWstring(i);
00112                                 buttonname += L"_";
00113                                 buttonname += toWstring(button->isClicked(i));
00114                         }
00115                 }
00116 
00117                 pair< multimap<wstring, ThymioIRButton*>::iterator,
00118                           multimap<wstring, ThymioIRButton*>::iterator > ret;
00119                 ret = currentHash->equal_range(buttonname);             
00120 
00121                 for(multimap<wstring, ThymioIRButton*>::iterator itr = ret.first; 
00122                         itr != ret.second; ++itr )                              
00123                         if( itr->second != button )
00124                                 errorCode = THYMIO_EVENT_MULTISET;
00125                                 
00126                 currentHash->insert( pair<wstring, ThymioIRButton*>(buttonname, button) );
00127                 tempHash.clear();
00128         }
00129 
00130         void ThymioIRTypeChecker::visit(ThymioIRButtonSet *buttonSet)
00131         {
00132                 if( !buttonSet->hasEventButton() || !buttonSet->hasActionButton() ) return;
00133                                 
00134                 errorCode = THYMIO_NO_ERROR;
00135 
00136                 activeActionName = buttonSet->getActionButton()->getName();
00137 
00138                 visit(buttonSet->getEventButton());                     
00139         }
00140 
00141         // Syntax Checker //
00142         void ThymioIRSyntaxChecker::visit(ThymioIRButton *button)
00143         {
00144                 errorCode = THYMIO_NO_ERROR;
00145         }
00146         
00147         void ThymioIRSyntaxChecker::visit(ThymioIRButtonSet *buttonSet)
00148         {
00149                 errorCode = THYMIO_NO_ERROR;            
00150                 
00151                 if( !(buttonSet->hasEventButton()) )
00152                 {
00153                         if( buttonSet->hasActionButton() )
00154                                 errorCode = THYMIO_MISSING_EVENT;
00155                 } 
00156                 else if( !(buttonSet->hasActionButton()) )
00157                         errorCode = THYMIO_MISSING_ACTION;
00158                 else
00159                         visit(buttonSet->getEventButton());
00160         }
00161 
00162         // Code Generator //
00163         ThymioIRCodeGenerator::ThymioIRCodeGenerator() : 
00164                 ThymioIRVisitor(),
00165                 generatedCode(),
00166                 currentBlock(0),
00167                 inIfBlock(false),
00168                 buttonToCodeMap()
00169         {
00170                 reset();
00171                 
00172                 directions.push_back(L"forward");
00173                 directions.push_back(L"left");
00174                 directions.push_back(L"backward");
00175                 directions.push_back(L"right");
00176                 directions.push_back(L"center");
00177         }
00178         
00179         ThymioIRCodeGenerator::~ThymioIRCodeGenerator()
00180         {
00181                 clear();
00182                 directions.clear();
00183         }
00184         
00185         void ThymioIRCodeGenerator::clear()
00186         {
00187                 editor.clear();
00188                 generatedCode.clear();
00189                 inIfBlock = false;
00190         }
00191         
00192         void ThymioIRCodeGenerator::reset() 
00193         {
00194                 editor[THYMIO_BUTTONS_IR] = make_pair(-1,0);
00195                 editor[THYMIO_PROX_IR] = make_pair(-1,0);
00196                 editor[THYMIO_TAP_IR] = make_pair(-1,0);
00197                 editor[THYMIO_CLAP_IR] = make_pair(-1,0);
00198                 generatedCode.clear();
00199                 inIfBlock = false;
00200                 buttonToCodeMap.clear();
00201         }       
00202 
00203         int ThymioIRCodeGenerator::buttonToCode(int id) const
00204         {
00205                 if( errorCode != THYMIO_NO_ERROR )
00206                         return -1;
00207 
00208                 return (id < (int)buttonToCodeMap.size() ? buttonToCodeMap[id] : -1);
00209         }
00210 
00211         void ThymioIRCodeGenerator::visit(ThymioIRButton *button)
00212         {
00213                 if( button == 0 ) return;
00214                 
00215                 wstring text;
00216 
00217                 if( button->isEventButton() )
00218                 {
00219                         bool flag=false;
00220                         if( button->isSet() )
00221                         {
00222                                 text = L"\tif ";
00223                                 switch( button->getName() )
00224                                 {
00225                                 case THYMIO_BUTTONS_IR:
00226                                         for(int i=0; i<5; ++i)
00227                                         {
00228                                                 if(button->isClicked(i) > 0)
00229                                                 {
00230                                                         text += (flag ? L" and " : L"");
00231                                                         text += L"button.";
00232                                                         text += directions[i];
00233                                                         text += L" == 1";
00234                                                         flag = true;
00235                                                 }
00236                                         }
00237                                         break;
00238                                 case THYMIO_PROX_IR:
00239                                         for(int i=0; i<button->size(); ++i)
00240                                         {
00241                                                 if(button->isClicked(i) == 1)
00242                                                 {
00243                                                         text += (flag ? L" and " : L"");
00244                                                         text += L"prox.horizontal[";
00245                                                         text += toWstring(i);
00246                                                         text += L"] < 400";
00247                                                         flag = true;
00248                                                 } 
00249                                                 else if(button->isClicked(i) == 2)
00250                                                 {
00251                                                         text += (flag ? L" and " : L"");
00252                                                         text += L"prox.horizontal[";
00253                                                         text += toWstring(i);
00254                                                         text += L"] > 500";
00255                                                         flag = true;
00256                                                 } 
00257                                         }
00258                                         break;
00259                                 case THYMIO_PROX_GROUND_IR:
00260                                         for(int i=0; i<button->size(); ++i)
00261                                         {
00262                                                 if(button->isClicked(i) == 1)
00263                                                 {
00264                                                         text += (flag ? L" and " : L"");
00265                                                         text += L"prox.ground.reflected[";
00266                                                         text += toWstring(i);
00267                                                         text += L"] < 150";
00268                                                         flag = true;
00269                                                 }
00270                                                 else if(button->isClicked(i) == 2)
00271                                                 {
00272                                                         text += (flag ? L" and " : L"");
00273                                                         text += L"prox.ground.reflected[";
00274                                                         text += toWstring(i);
00275                                                         text += L"] > 300";
00276                                                         flag = true;
00277                                                 }
00278                                         }
00279                                         break;
00280                                 case THYMIO_TAP_IR:
00281                                 case THYMIO_CLAP_IR:
00282                                 default:
00283                                         errorCode = THYMIO_INVALID_CODE;
00284                                         break;
00285                                 }
00286                                 
00287                                 if( button->getMemoryState() > 0 )
00288                                 {
00289                                         text += L" and (state & ";
00290                                         text += toWstring(button->getMemoryState());
00291                                         text += L") == ";
00292                                         text += toWstring(button->getMemoryState());
00293                                 }
00294                                 
00295                                 text += L" then\n";
00296                                 inIfBlock = true;
00297                                 
00298                                 generatedCode[currentBlock] = text;
00299                         }
00300                         else 
00301                         {
00302                                 if( button->getMemoryState() > 0 )
00303                                 {
00304                                         text += L"\tif (state & ";
00305                                         text += toWstring(button->getMemoryState());
00306                                         text += L") == ";
00307                                         text += toWstring(button->getMemoryState());
00308                                         text += L" then\n";
00309                                         
00310                                         generatedCode[currentBlock] = text;
00311                                         inIfBlock = true;
00312                                 }
00313                                 else
00314                                         inIfBlock = false;
00315                         }
00316                 }
00317                 else
00318                 {
00319                         text = (inIfBlock ? L"\t\t" : L"\t");
00320                         int val=0;
00321                         switch( button->getName() )
00322                         {
00323                         case THYMIO_MOVE_IR:
00324                                 text += L"motor.left.target = ";
00325                                 text += toWstring(button->isClicked(0));
00326                                 text += (inIfBlock ? L"\n\t\t" : L"\n\t");
00327                                 text += L"motor.right.target = ";
00328                                 text += toWstring(button->isClicked(1));
00329                                 text += L"\n";                          
00330                                 break;
00331                         case THYMIO_COLOR_IR:
00332                                 text += L"call leds.top(";
00333                                 text += toWstring(button->isClicked(0));
00334                                 text += L",";
00335                                 text += toWstring(button->isClicked(1));
00336                                 text += L",";                                                           
00337                                 text += toWstring(button->isClicked(2));
00338                                 text += L")\n";
00339                                 break;
00340                         case THYMIO_CIRCLE_IR:
00341                                 text += L"call leds.circle(";
00342                                 for(int i=0; i < button->size(); ++i)
00343                                 {
00344                                         text += toWstring((32*button->isClicked(i))/(button->getNumStates()-1)); 
00345                                         text += L",";
00346                                 }
00347                                 text.replace(text.length()-1, 2,L")\n");
00348                                 break;
00349                         case THYMIO_SOUND_IR:
00350                                 if( button->isClicked(0) ) // friendly
00351                                         text += L"call sound.system(7)\n";
00352                                 else if( button->isClicked(1) ) // okay
00353                                         text += L"call sound.system(6)\n";
00354                                 else
00355                                         text += L"call sound.system(4)\n"; // scared
00356                                 break;
00357                         case THYMIO_MEMORY_IR:
00358                                 text += L"new_state = ";
00359                                 for(int i=0; i<button->size(); ++i)
00360                                         val += (button->isClicked(i)*(0x01<<i));
00361                                 text += toWstring(val);
00362                                 text += L"\n";
00363                                 break;
00364                         default:
00365                                 errorCode = THYMIO_INVALID_CODE;
00366                                 break;
00367                         }
00368                         text += (inIfBlock ? L"\tend\n" : L"");
00369                         inIfBlock = false;
00370                 
00371                         generatedCode[currentBlock].append(text);
00372                 }
00373         
00374         }
00375 
00376         void ThymioIRCodeGenerator::visit(ThymioIRButtonSet *buttonSet)
00377         {
00378                 if( !buttonSet->hasEventButton() || !buttonSet->hasActionButton() ) 
00379                 {
00380                         buttonToCodeMap.push_back(-1);
00381                         return;
00382                 }
00383                 
00384                 errorCode = THYMIO_NO_ERROR;
00385                 
00386                 if( generatedCode.empty() )
00387                 {
00388                         if( buttonSet->getEventButton()->getMemoryState() >= 0 )
00389                                 generatedCode.push_back(L"var state = 0\nvar new_state = 0\n");
00390                         generatedCode.push_back(L"call sound.system(-1)\ncall leds.temperature(0,0)\ncall leds.top(0,0,0)\ncall leds.circle(0,0,0,0,0,0,0,0)\n");
00391                 }
00392                 
00393                 ThymioIRButtonName name = buttonSet->getEventButton()->getName();
00394                 if( name == THYMIO_PROX_GROUND_IR )
00395                         name = THYMIO_PROX_IR;
00396                 
00397                 int block = editor[name].first;
00398                 int size = editor[name].second;
00399                 bool mflag = (buttonSet->getEventButton()->getMemoryState() >= 0 ? true : false);
00400                         
00401                 if( block < 0 )
00402                 {
00403                         block = generatedCode.size();
00404                         
00405                         switch(name) 
00406                         {
00407                         case THYMIO_BUTTONS_IR:
00408                                 generatedCode.push_back(L"\nonevent buttons\n");
00409                                 size++;
00410                                 break;
00411                         case THYMIO_PROX_IR:
00412                                 generatedCode.push_back(L"\nonevent prox\n");
00413                                 size++;
00414                                 break;
00415                         case THYMIO_TAP_IR:
00416                                 generatedCode.push_back(L"\nonevent tap\n");
00417                                 size++;
00418                                 break;
00419                         case THYMIO_CLAP_IR:
00420                                 if( generatedCode.empty() || generatedCode[0].find(L"var new_state = 0\n") == wstring::npos )
00421                                 {
00422                                         generatedCode.insert(generatedCode.begin(),L"mic.threshold = 250\n");
00423                                         for(map<ThymioIRButtonName, pair<int, int> >::iterator itr = editor.begin();
00424                                                 itr != editor.end(); ++itr)
00425                                                 if( (itr->second).first >= 0 )
00426                                                         (itr->second).first++;
00427 
00428                                         for(int i=0; i<(int)buttonToCodeMap.size(); i++)
00429                                                 if( buttonToCodeMap[i]>=0 ) 
00430                                                         buttonToCodeMap[i]++;
00431 
00432                                         block += 1;                             
00433                                 }
00434                                 else
00435                                         generatedCode[0].append(L"\nmic.threshold = 250\n");
00436 
00437                                 generatedCode.push_back(L"\nonevent mic\n");
00438                                 size++;
00439                                 break;  
00440                         default:
00441                                 errorCode = THYMIO_INVALID_CODE;
00442                                 return;
00443                                 break;
00444                         }
00445 
00446                         if(mflag)
00447                         {
00448                                 generatedCode.push_back(L"\n\tstate = new_state\n\tcall leds.temperature(((state>>0) & 1)*10+((state>>1) & 1)*22,((state>>2) & 1)*10+((state>>3) & 1)*22)\n");
00449                                 editor[name] = make_pair(block, size+1);
00450                         }
00451                         else
00452                                 editor[name] = make_pair(block, size);
00453 
00454                         currentBlock = block + size;
00455                         generatedCode.insert(generatedCode.begin() + currentBlock, L"");
00456                         buttonToCodeMap.push_back(currentBlock);
00457                 }
00458                 else
00459                 {
00460                         currentBlock = (mflag ? block + size : block + size + 1);
00461                         editor[name].second++;
00462                         for(map<ThymioIRButtonName, pair<int, int> >::iterator itr = editor.begin(); itr != editor.end(); ++itr)
00463                                 if( (itr->second).first > block )
00464                                         (itr->second).first++;
00465 
00466                         if( !mflag && !buttonSet->getEventButton()->isSet() )
00467                         {
00468                                 // find where "if" block starts for the current event
00469                                 for(unsigned int i=0; i<buttonToCodeMap.size(); i++)
00470                                         if( buttonToCodeMap[i] >= block && buttonToCodeMap[i] < currentBlock &&
00471                                                 generatedCode[buttonToCodeMap[i]].find(L"if ") != wstring::npos )                               
00472                                                 currentBlock = buttonToCodeMap[i];
00473                         }
00474                         
00475                         for( unsigned int i=0; i<buttonToCodeMap.size(); i++)
00476                                 if(buttonToCodeMap[i] >= currentBlock)
00477                                         buttonToCodeMap[i]++;
00478                                 
00479                         generatedCode.insert(generatedCode.begin() + currentBlock, L"");
00480                         buttonToCodeMap.push_back(currentBlock);
00481                 }
00482 
00483                 
00484                 visit(buttonSet->getEventButton());
00485                 visit(buttonSet->getActionButton());
00486         }
00487 
00488 }; // Aseba


aseba
Author(s): Stéphane Magnenat
autogenerated on Thu Jan 2 2014 11:17:17