00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "nel/ai/script/code_branche_run_debug.h"
00026 #include "nel/ai/script/varstack.h"
00027
00028 #ifdef NL_DEBUG
00029 #ifdef NL_OS_WINDOWS
00030 #include "windows.h"
00031 #endif
00032 #endif
00033
00034 namespace NLAISCRIPT
00035 {
00036
00037
00038
00039
00040 void CCodeBrancheRunDebug::initCBRD()
00041 {
00042 _LineInSourceCodeArray = new int[_Count];
00043 for(sint32 i = 0 ;i < _Count; i ++)
00044 {
00045 _LineInSourceCodeArray[i] = 0;
00046 }
00047 }
00048
00049 CCodeBrancheRunDebug::CCodeBrancheRunDebug(sint32 N,const IOpCode &op):
00050 CCodeBrancheRun(N, op), _SourceCode(NULL)
00051 {
00052 initCBRD();
00053 }
00054
00055 CCodeBrancheRunDebug::CCodeBrancheRunDebug(sint32 N, IScriptDebugSource* sourceCode):
00056 CCodeBrancheRun(N),
00057 _SourceCode(sourceCode)
00058 {
00059 _SourceCode->incRef();
00060 initCBRD();
00061 }
00062
00063 CCodeBrancheRunDebug::CCodeBrancheRunDebug(const tListCode &l):
00064 CCodeBrancheRun(l),
00065 _SourceCode(NULL)
00066 {
00067 initCBRD();
00068 }
00069
00070 CCodeBrancheRunDebug::CCodeBrancheRunDebug(const CCodeBrancheRunDebug &l):
00071 CCodeBrancheRun(l),
00072 _LineInSourceCodeArray(NULL),
00073 _SourceCode(l._SourceCode)
00074 {
00075 _SourceCode->incRef();
00076 initCBRD();
00077 for(sint32 i = 0 ;i < _Count; i ++)
00078 {
00079 _LineInSourceCodeArray[i] = l._LineInSourceCodeArray[i];
00080 }
00081 }
00082
00083 CCodeBrancheRunDebug::~CCodeBrancheRunDebug()
00084 {
00085 delete []_LineInSourceCodeArray;
00086 if (_SourceCode) _SourceCode->release();
00087 }
00088
00089 const NLAIC::IBasicType* CCodeBrancheRunDebug::clone() const
00090 {
00091 NLAIC::IBasicType *x = new CCodeBrancheRunDebug(*this);
00092 return x;
00093 }
00094
00095 const NLAIC::IBasicType *CCodeBrancheRunDebug::newInstance() const
00096 {
00097 NLAIC::IBasicType *x = new CCodeBrancheRunDebug(1,CHaltOpCode());
00098 return x;
00099 }
00100
00101 void CCodeBrancheRunDebug::save(NLMISC::IStream &os)
00102 {
00103 CCodeBrancheRun::save(os);
00104
00105 for(int i = 0 ;i < _Count; i ++)
00106 {
00107 sint32 n = _LineInSourceCodeArray[i];
00108 os.serial( n );
00109 }
00110 _SourceCode->save(os);
00111
00112 }
00113
00114 void CCodeBrancheRunDebug::load(NLMISC::IStream &is)
00115 {
00116 int i;
00117 CCodeBrancheRun::load(is);
00118 delete[] _LineInSourceCodeArray;
00119 _LineInSourceCodeArray = new int[_Count];
00120 for(i = 0 ;i < _Count; i ++)
00121 {
00122 sint32 n;
00123 is.serial( n );
00124 _LineInSourceCodeArray[i] = (int)n;
00125 }
00126 _SourceCode->load(is);
00127 }
00128
00129 const NLAIAGENT::IObjectIA::CProcessResult& CCodeBrancheRunDebug::run(NLAIAGENT::IObjectIA &self)
00130 {
00131 CStackPointer stack,heap;
00132 CCodeContext p(stack,heap,this,&self,InputOutput);
00133 CVarPStack::_LocalTableRef = &heap[0];
00134 stack --;
00135
00136 run(p);
00137
00138 stack -= (sint32)stack;
00139 heap -= (sint32)heap;
00140 return _RunState;
00141 }
00142
00143 const NLAIAGENT::IObjectIA::CProcessResult &CCodeBrancheRunDebug::run(CCodeContext &p)
00144 {
00145 NLAIAGENT::TProcessStatement i = NLAIAGENT::processIdle;
00146
00147 p.ContextDebug.Active = true;
00148 p.ContextDebug.callStackPush(this);
00149
00150 _RunState.Result = NULL;
00151 while(i != NLAIAGENT::processEnd)
00152 {
00153 i = runOpCode(p);
00154 }
00155
00156 _RunState.ResultState = NLAIAGENT::processIdle;
00157 return _RunState;
00158 }
00159 #ifdef NL_DEBUG
00160 extern bool NL_AI_DEBUG_SERVER;
00161 #endif
00162 NLAIAGENT::TProcessStatement CCodeBrancheRunDebug::runOpCode(CCodeContext &p)
00163 {
00164 std::string buf;
00165 p.ContextDebug.Active = true;
00166
00167 IOpCode &op = nextCode();
00168
00169 #ifdef NL_DEBUG
00170 if(NL_AI_DEBUG_SERVER)
00171 {
00172 std::string chaine;
00173 op.getDebugResult(chaine,p);
00174 #ifdef NL_OS_WINDOWS
00175 OutputDebugString(chaine.c_str());
00176 OutputDebugString("\n");
00177 #endif
00178 }
00179 #endif
00180 if (_LineInSourceCodeArray[_Ip-1] != 0)
00181 {
00182 fixContextDebugMode(p);
00183
00184
00185 if ( p.ContextDebug.getDebugMode() == stepByStepMode
00186 && p.ContextDebug.getCallStackTopIndex() == p.ContextDebug.getStepIndex())
00187 {
00188 printCurrentSourceCodeLine();
00189
00190 bool executOpcode = false;
00191
00192 while (!executOpcode)
00193 {
00194
00195 InputOutput->Echo("(db) ");
00196 buf = InputOutput->InPut();
00197 executOpcode = readCommandLine(p, buf.c_str());
00198 if (0 != buf.c_str()[0]) p.ContextDebug.setLastCommandLine(buf.c_str());
00199 }
00200 }
00201 }
00202
00203 if (p.ContextDebug.getDebugMode() == stopMode)
00204 {
00205 return NLAIAGENT::processEnd;
00206 }
00207 else
00208 {
00209 return op.runOpCode(p);
00210 }
00211 }
00212
00213 void CCodeBrancheRunDebug::getDebugResult(std::string &str,CCodeContext &p) const
00214 {
00215 _TableCode[_Ip]->getDebugResult(str,p);
00216 }
00217
00218 const NLAIC::CIdentType& CCodeBrancheRunDebug::getType() const
00219 {
00220 return IdCodeBrancheRunDebug;
00221 }
00222
00223 void CCodeBrancheRunDebug::initCode(const tListCode &l)
00224 {
00225 del();
00226 _Count = l.size();
00227
00228 tListCode::const_iterator i;
00229 _TableCode = new IOpCode * [l.size()];
00230 i = l.begin();
00231 sint32 k = 0;
00232 while(i != l.end())
00233 {
00234 _TableCode[k ++] = (IOpCode *)*i++;
00235 }
00236 }
00237
00238 void CCodeBrancheRunDebug::initCode(const CCodeBrancheRunDebug &l)
00239 {
00240 del();
00241
00242 _Ip = 0;
00243 _Count = l._Count;
00244
00245 _TableCode = new IOpCode * [_Count];
00246 for(sint32 i = 0; i < _Count;i ++)
00247 {
00248 _TableCode[i] = (IOpCode *)l._TableCode[i]->clone();
00249 }
00250 }
00251
00252 void CCodeBrancheRunDebug::setLineCode(int ligne, int index)
00253 {
00254 _LineInSourceCodeArray[index] = ligne;
00255 }
00256
00257 std::string CCodeBrancheRunDebug::getSourceFileName() const
00258 {
00259 return _SourceCode->getSourceName().c_str();
00260 }
00261
00262 void CCodeBrancheRunDebug::fixContextDebugMode(CCodeContext &P) const
00263 {
00264
00265 if ( P.ContextDebug.getBreakPointValue(_LineInSourceCodeArray[_Ip-1],getSourceFileName().c_str())
00266 || P.ContextDebug.getDebugMode() == stepInMode
00267 || P.ContextDebug.getDebugMode() == stepOutMode && (P.ContextDebug.getCallStackTopIndex() < P.ContextDebug.getStepIndex())
00268 || P.ContextDebug.getDebugMode() == stepByStepMode && P.ContextDebug.getCallStackTopIndex() < P.ContextDebug.getStepIndex())
00269 {
00270 P.ContextDebug.setDebugMode(stepByStepMode);
00271 P.ContextDebug.setStepIndex(P.ContextDebug.getCallStackTopIndex());
00272 }
00273 }
00274
00275 void CCodeBrancheRunDebug::printSourceCodeLine(int first, int last) const
00276 {
00277 sint32 i, j, k, size, lineNumber;
00278 const char* buf;
00279 char* lineTxt;
00280 std::string code;
00281
00282 lineNumber = this->getCurrentSourceCodeLineNumber();
00283 code = " ";
00284 code += _SourceCode->getSourceBuffer();
00285 code +="\n";
00286 size = code.size();
00287 buf = code.c_str();
00288
00289
00290 if (first > last) last = first;
00291
00292
00293 i = 0;
00294 j = 0;
00295 k = 0;
00296 lineTxt = new char[1024];
00297
00298
00299 while (k != first && j < size)
00300 {
00301 j++;
00302 i = j;
00303 while (buf[j] != '\n')
00304 {
00305 j++;
00306 }
00307 k++;
00308 }
00309
00310
00311 while (k != last+1 && j < size)
00312 {
00313 strncpy (lineTxt, buf+i,j-i);
00314 lineTxt[j-i] = 0;
00315
00316
00317 if ( k == lineNumber)
00318 {
00319 InputOutput->Echo("%d ->\t %s\n", k, lineTxt);
00320 }
00321 else
00322 {
00323 InputOutput->Echo("%d \t %s\n", k, lineTxt);
00324 }
00325
00326 j++;
00327 i = j;
00328 while (buf[j] != '\n')
00329 {
00330 j++;
00331 }
00332 k++;
00333 }
00334 delete[] lineTxt;
00335 }
00336
00337 void CCodeBrancheRunDebug::printCurrentSourceCodeLine() const
00338 {
00339 uint16 lineNumber = getCurrentSourceCodeLineNumber();
00340 printSourceCodeLine(lineNumber, lineNumber);
00341 }
00342
00343 uint16 CCodeBrancheRunDebug::getCurrentSourceCodeLineNumber() const
00344 {
00345 if (_Ip ==0)
00346 return 0;
00347
00348 if (_LineInSourceCodeArray[_Ip-1] != 0)
00349 {
00350 return (_LineInSourceCodeArray[_Ip-1]);
00351 }
00352 else
00353 {
00354 sint32 i = 2;
00355 while (_LineInSourceCodeArray[_Ip-i] == 0)
00356 {
00357 i++;
00358 }
00359 return _LineInSourceCodeArray[_Ip-i];
00360 }
00361 }
00362
00363 void CCodeBrancheRunDebug::printVariable (CCodeContext &P, const char* c) const
00364 {
00365 sint32 begin;
00366 const NLAIAGENT::IObjectIA* base;
00367 const NLAIAGENT::IVarName* ivn;
00368 NLAIAGENT::CStringType* st;
00369 NLAIAGENT::CStringVarName* svn;
00370 char* buf = new char[1024*8];
00371 char* bufA = new char[1024*8];
00372 char* bufX = new char[1024*8];
00373 int i;
00374 int j;
00375 char* dotPos;
00376 buf[0] = 0;
00377 bufA[0] = 0;
00378 bufX[0] = 0;
00379
00380
00381 strcpy (buf, c);
00382 dotPos = strchr(buf,'.');
00383 if(dotPos != NULL)
00384 {
00385 strcpy(bufX, dotPos+1);
00386 strchr(buf,'.')[0]= '\0';
00387 }
00388
00389
00390 begin = (int)P.ContextDebug.HeapDebug;
00391 for (i = begin; i>=0; i--)
00392 {
00393 base = P.ContextDebug.HeapDebug[i];
00394 if (base)
00395 {
00396 if (base->getType() == NLAIAGENT::CStringType::IdStringType)
00397 {
00398 st = (NLAIAGENT::CStringType*) base;
00399 ivn = &(st->getStr());
00400 if (ivn->getType() == NLAIAGENT::CStringVarName::IdStringVarName)
00401 {
00402 svn = (NLAIAGENT::CStringVarName*) ivn;
00403 if (strcmp(svn->getString(), buf) == 0)
00404 {
00405 break;
00406 }
00407 }
00408 }
00409 }
00410 }
00411
00412 base = NULL;
00413 if (i>=0)
00414 {
00415
00416 base = P.Heap[i];
00417 }
00418 else
00419 {
00420 j = P.Self->getStaticMemberIndex(NLAIAGENT::CStringVarName(buf));
00421 if (j >= 0)
00422 {
00423
00424 base = P.Self->getStaticMember(j);
00425 }
00426 }
00427
00428 if (base != NULL)
00429 {
00430
00431 if (bufX[0] == 0)
00432 {
00433
00434 std::string buf;
00435 base->getDebugString(buf);
00436 InputOutput->Echo("%s\n",buf.c_str());
00437 }
00438 else
00439 {
00440
00441 dotPos = strchr(bufX,'.');
00442 while (dotPos != NULL)
00443 {
00444 strcpy(buf,bufX);
00445 strcpy(bufX, dotPos+1);
00446 strcpy(bufA,buf);
00447 strchr(bufA,'.')[0]= '\0';
00448 j = base->getStaticMemberIndex(NLAIAGENT::CStringVarName(bufA));
00449 if (j >= 0)
00450 {
00451 base = base->getStaticMember(j);
00452 }
00453 dotPos = strchr(bufX,'.');
00454 }
00455 j = base->getStaticMemberIndex(NLAIAGENT::CStringVarName(bufX));
00456 if (j >= 0)
00457 {
00458 std::string buf;
00459 base->getStaticMember(j)->getDebugString(buf);
00460 InputOutput->Echo("%s\n",buf.c_str());
00461 }
00462 }
00463 }
00464
00465 delete[] buf;
00466 delete[] bufA;
00467 delete[] bufX;
00468 }
00469 void CCodeBrancheRunDebug::printArgs (CCodeContext &P) const
00470 {
00471 if (P.Param.size() >0 )
00472 {
00473 NLAIAGENT::CIteratorContener Ita = ((NLAIAGENT::CGroupType *) P.ContextDebug.Param.back())->getIterator();
00474 NLAIAGENT::CIteratorContener Itb = ((NLAIAGENT::CGroupType *) P.Param.back())->getIterator();;
00475 while(!Ita.isInEnd())
00476 {
00477 std::string buf;
00478 Ita++;
00479 NLAIAGENT::CStringType *p = (NLAIAGENT::CStringType *)Itb++;
00480 p->getDebugString(buf);
00481
00482 }
00483 }
00484 }
00485
00486 bool CCodeBrancheRunDebug::readCommandLine(CCodeContext &P, const char* buf)
00487 {
00488 char* sourceFileName;
00489 char* varName;
00490 uint32 lineNumber;
00491 sint32 first, last;
00492 bool ret = false;
00493
00494 switch (buf[0])
00495 {
00496 case 'p' :
00497
00498 varName = new char[1024];
00499 sscanf(buf+1, "%s", varName);
00500 printVariable(P,varName);
00501 delete[] varName;
00502 break;
00503 case 'w' :
00504
00505 P.ContextDebug.callStackPrint(InputOutput);
00506 break;
00507 case 'u' :
00508
00509 P.ContextDebug.stepIndexUp();
00510 break;
00511 case 'd' :
00512
00513 P.ContextDebug.stepIndexDown();
00514 break;
00515 case 'l' :
00516
00517 first = last = 0;
00518 sscanf(buf+1, "%d %d",&first, &last);
00519 if (0 == first) first = this->getCurrentSourceCodeLineNumber() - 6;
00520 if (0 > first) first = 0;
00521 if (0 == last) last = first + 11;
00522 printSourceCodeLine(first, last);
00523 break;
00524 case 'b' :
00525
00526 sourceFileName = new char[1024];
00527 sourceFileName[0] = 0;
00528 lineNumber = 0;
00529 sscanf(buf+1,"%d %s",&lineNumber,sourceFileName);
00530 if (0 == lineNumber)
00531 {
00532 P.ContextDebug.printActiveBeaks(InputOutput);
00533 }
00534 else
00535 {
00536 if (sourceFileName[0])
00537 {
00538 P.ContextDebug.addBreakPoint((uint16)lineNumber,sourceFileName);
00539 }
00540 else
00541 {
00542 P.ContextDebug.addBreakPoint((uint16)lineNumber,getSourceFileName().c_str());
00543 }
00544 }
00545 delete[] sourceFileName;
00546 break;
00547 case 'e' :
00548
00549 sourceFileName = new char[1024];
00550 sourceFileName[0] = 0;
00551 sscanf(buf+1,"%d %s",&lineNumber,sourceFileName);
00552 if (sourceFileName[0])
00553 {
00554 P.ContextDebug.eraseBreakPoint((uint16)lineNumber,sourceFileName);
00555 }
00556 else
00557 {
00558 P.ContextDebug.eraseBreakPoint((uint16)lineNumber,getSourceFileName().c_str());
00559 }
00560 delete[] sourceFileName;
00561 break;
00562 case 's' :
00563
00564 P.ContextDebug.setDebugMode(stepInMode);
00565 ret = true;
00566 break;
00567 case 'n' :
00568
00569 P.ContextDebug.setDebugMode(stepByStepMode);
00570 ret = true;
00571 break;
00572 case 'r' :
00573
00574 P.ContextDebug.setDebugMode(stepOutMode);
00575 ret = true;
00576 break;
00577 case 'c' :
00578
00579 P.ContextDebug.setDebugMode(runMode);
00580 ret = true;
00581 break;
00582 case 'a' :
00583
00584 printArgs(P);
00585 break;
00586 case 'q' :
00587
00588 P.ContextDebug.setDebugMode(stopMode);
00589 ret = true;
00590 break;
00591 case 0 :
00592
00593 ret = this->readCommandLine(P, P.ContextDebug.getLastCommandLine());
00594 break;
00595 case 'h' :
00596
00597
00598 InputOutput->Echo("p(rint) expr.\t| Inspect variables / attributes.\n");
00599 InputOutput->Echo("w(here)\t\t| Dump the call stack.\n");
00600 InputOutput->Echo("u(p)\t\t| Travel up (to newer) frames in the call stack.\n");
00601 InputOutput->Echo("d(own)\t\t| Travel down (to older) frames in the call stack.\n");
00602 InputOutput->Echo("l(ist) f?, l?\t| List the current context's source code file.\n");
00603 InputOutput->Echo("b(reak) line?\t| Set more breakpoints on line numbers, or list active breaks.\n");
00604 InputOutput->Echo("e(rase) line?\t| Erase a specific breakpoint (or all of them)\n");
00605 InputOutput->Echo("s(tep)\t\t| Run the next line and stop; stop in called functions.\n");
00606 InputOutput->Echo("n(ext)\t\t| Run the next line and stop, don't stop in functions it calls.\n");
00607 InputOutput->Echo("r(eturn)\t| Continue silently until the current function returns.\n");
00608 InputOutput->Echo("c(ontinue)\t| Continue programm execution until breakpoint, or exit.\n");
00609 InputOutput->Echo("a(rgs)\t\t| Print arguments passed to the current context's function.\n");
00610 InputOutput->Echo("q(uit)\t\t| Quit the debugger; also terminates the code being debugged.\n");
00611 InputOutput->Echo("<enter-key>\t| Repeat the last command.\n");
00612 InputOutput->Echo("h(elp) command ?| Get command help; you can forget the rest if you remember 'h'.\n");
00613 break;
00614 }
00615
00616 return ret;
00617 }
00618 }