Go to the documentation of this file.00001 #include <sstream>
00002 #include "ThymioIntermediateRepresentation.h"
00003
00004 namespace Aseba
00005 {
00006
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
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
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
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) )
00351 text += L"call sound.system(7)\n";
00352 else if( button->isClicked(1) )
00353 text += L"call sound.system(6)\n";
00354 else
00355 text += L"call sound.system(4)\n";
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
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 };