$search
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