LUA调试环境(二)


QQ: 282397369

今天在已有基础上继续
做一个功能,可以考虑通用与专用需求。我现在做的这个功能,只是先给自己用,所以很多地方可以特殊处理,能满足自用即可,最主要的是时间上紧迫,项目交付在即,不能花大量时间去研究别人或第三方的细节。那就拿来主要功能,改造下集成到系统之中。

运行模式

有编程N年的经历,自然知道IDE的模式,虽然术语不准确,但自己明白含义。
运行这块,在自用的需求情况下,可简化成全速运行、调试运行,后者再划分成运行到断点、单步运行。至于运行到某一行,好象需求不大,也就不考虑。而单步运行,直接阉割成运行到下一调用。
直接定义一下

enum NDebugPauseType {
	dptNextBreakpoint = 1,		// 下一断点
	dptNextCall = 2,			// 下一调用
	dptNone = -1				// 无需暂停
};

这里调用的原因在于,使用环境是C++与LUA的集成调试,至于在LUA内部的运行,暂可以不管,只关心二者之间的交互。这些交互都是通过各种函数调用实现的,可认为是调用组控制。
所以,断点也应该定义设置在各函数调用处,纯LUA的流程处先不处理。
这样做的原因,也是在于没有下功夫去研究LUA的流程控制,即在LUA内部跑的时候,还没有想办法去暂停等控制运行操作。

断点确认

在上面调用级控制前提下,确认断点就比较方便了。

bool __fastcall TCbwSynEditor::IsBreakpointLine(TDrLUA * lua) {
	lua->RefreshDebugInfo();
	DebugLuaObject = lua;
	UnicodeString fileName = lua->CurrentFileName;
	int lineNumber = lua->CurrentLine;
	bool needPauseFlag = false;
	if(dptNextBreakpoint == DebugPauseType) {
		TBreakPoints * destItems = NULL;
		CBW_ITERATOR(vector<TBreakPoints *>, FBreakpoints) {
			if(ExtractFileName((*it)->fileName) == ExtractFileName(fileName))
				destItems = *it;
		}
		if(destItems)
			CBW_ITERATOR(vector<int>, destItems->lineNumbers)
				if(*it == lineNumber)
					needPauseFlag = true;
	}
	if(dptNextCall == DebugPauseType)
		needPauseFlag = true;
	return needPauseFlag;
}

其中,获取LUA的调试信息,直接调用LUA的调试信息lua_getinfo即可。

运行控制

发现满足断点条件后,当然是需要控制处理。说控制有点过份了,因为就是暂停处理。

基本准备工作

采用Windows内核事件对象就OK。实现几个函数供业务调用:

void __fastcall TCbwSynEditor::DebugEvent_Init() {
	hDebugEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
}

void __fastcall TCbwSynEditor::DebugEvent_Deinit() {
	CloseHandle(hDebugEvent);
}

void __fastcall TCbwSynEditor::DebugEvent_Wait() {
	IsDebugPaused = true;
	ResetEvent(hDebugEvent);
	WaitForSingleObject(hDebugEvent, INFINITE);
}

void __fastcall TCbwSynEditor::DebugEvent_Next() {
	SetEvent(hDebugEvent);
}

控制

所谓控制也就是在几个适宜环节条件下,调用上述方法
简单地说,在每次调试运行之前,初始化DebugEvent_Init。完成后,清理DebugEvent_Deinit。发现满足条件,自动等待DebugEvent_Wait。用户干预,比如按F9运行到下一断点,F8运行到下一调用,都是DebugEvent_Next。
唯一需要注意的一点就是,因为调试会可能导致长时间等待,所以不能放在主线程。用一个简单的多线程即可。

class TDebugThread : public TThread {
private:
	TDrLUA * FLuaObject;
	UnicodeString FFunctionName;
	void __fastcall Execute();

public:
	__fastcall TDebugThread(TForm * ownerForm, TDrLUA * lua, UnicodeString functionName);
};


__fastcall TDebugThread::TDebugThread(TDrLUA * lua, UnicodeString functionName) : TThread(true) {
	FreeOnTerminate = true;
	FLuaObject = lua;
	FFunctionName = functionName;
	Suspended = false;
}

void __fastcall TDebugThread::Execute() {
	THelper::Debug::AddLog("Execute::");
	FLuaObject->IsLogging_Script = true;
	TScriptManager::GetInstance()->RunFunction(FLuaObject, FFunctionName);
}

再加上界面按钮,运行后,可以达到预期的断点暂停、继续、中止效果。
在这里插入图片描述

扫描二维码关注公众号,回复: 10451652 查看本文章

调试信息获取

作为调试工作,上面做的都是铺垫,最终还是需要在暂停的时候,获取相应的调试信息。
这个没法绕过,老老实实地看LUA文档。
试了几次,发现LUA脚本可以输出调试信息,采用debug.xxx即可。那就先实现一个LUA函数,以供C++调用获取。这样,在断点暂停的时候,调用该函数则得到相应的调试信息。类似于

[C]: in function 'Log'
D:\ExenObj\Exe\XE5\Debug\Logic_233.logic:285: in function 'test'
D:\ExenObj\Exe\XE5\Debug\Logic_233.logic:258: in function 'test1'
VarInFun2
(*temporary) = 37035
(*temporary) = 24690
VarInFun3
param = this is a test
param2 = and second value
x = 12345
y = 24690
z = 304798050
VarInFun4

剩下的事,就是解析这些信息,然后展示出来。图快,就直接用了个TTreeView进行显示,刚好还可以把函数调用关系展示出来。
在这里插入图片描述
现在工作完成了80%。还需要做的事就是易用处理,包括且不限于点击某变量时,直接定位到源文件相应行、对于特殊类型变量,如图像、XML文档等,以更直观方式进行展现。
明天完成。

发布了9 篇原创文章 · 获赞 2 · 访问量 547

猜你喜欢

转载自blog.csdn.net/drgraph/article/details/104461154