C++ ANSIC解析器-C编译器-查找开关语句
上下文 我正在写一个ANSIC代码解析器。目标是在c代码中找到有限状态机实现,并通过逆向工程创建关于现有状态和事件传输的文档 我们需要寻找c代码中有限状态机的3种常见实现:使用嵌套的switch语句(状态上的外部级别开关事件上的内部级别开关),2D结构数组,每个结构数组包含一个函数指针和下一个状态(执行转换函数后),函数指针的一维数组和状态的二维数组 主要目标是有限状态机检测C++ ANSIC解析器-C编译器-查找开关语句,c++,parsing,reverse-engineering,C++,Parsing,Reverse Engineering,上下文 我正在写一个ANSIC代码解析器。目标是在c代码中找到有限状态机实现,并通过逆向工程创建关于现有状态和事件传输的文档 我们需要寻找c代码中有限状态机的3种常见实现:使用嵌套的switch语句(状态上的外部级别开关事件上的内部级别开关),2D结构数组,每个结构数组包含一个函数指针和下一个状态(执行转换函数后),函数指针的一维数组和状态的二维数组 主要目标是有限状态机检测 在嵌套开关语句中检测状态机,我在C++中编写了一个C解析器,从C源代码中提取所有的切换语句,并将它们存储在我的代码中存在
在嵌套开关语句中检测状态机,我在C++中编写了一个C解析器,从C源代码中提取所有的切换语句,并将它们存储在我的代码中存在的父-子-兄弟关系。 问题
问题在于我的c解析器中有一个模块,该模块假定从c源代码中提取switch语句,并将其存储在代码中存在的父子兄弟关系中 程序输出 当在89个c源代码文件的列表上运行时,我的程序可以很好地工作并提取许多switch语句,但它似乎会随机中断 debug_output.txt 该文件包含从89个c源代码文件列表中提取的每个switch语句的输出 您将看到,它从一个未知错误中断了大约一半 我的ANSI C开关语句解析器 存在具有此签名的模拟重载函数std::istream&operator>>(std::istream&SwitchStatements&)
std::istream&operator>>(std::istream&is,SwitchStatements*ss)
{
断言(ss!=nullptr);
使用名称空间std;
is.setstate(ios::goodbit);
字符串str;
while(is>>str)
{
if(str.find(“开关”)!=string::npos){
ss->appendBuffer(str);
int括号_计数器=0;
字符c='0';
而((c=is.get())!=EOF){
ss->附加缓冲区(c);
/*错误处理*/
试一试{
如果(括号中的计数器<0)
抛出std::异常{“括号计数器不能小于0”};
如果(c=='}'&&U计数器==0)
抛出std::异常{“错误无法在打开“}之前满足关闭括号要求”;
如果(c==EOF&&U计数器!=0)
抛出std::exception{“error not meeting eof before all closing方括号”};
}
捕获(标准::异常_e){
cerr buffer.substr(这个->buffer.find_first_of('{');
ss_子项>ss_开关)
{
开关语句ss\U开关\U子级(
使_唯一(字符串{ss_switch.buffer})
);
if(!ss_switch_child.buffer.empty()||
!ss\u开关\u子项.getSibling().empty())
儿童。推回(开关儿童);
孩子们,明白了吗;
ss_switch_child.clearAll();
}
兄弟姐妹。推回(开关语句)(
使_唯一(字符串{(*).substr(偏移量)})
));
}
}
…如果你是认真的,你至少需要一个合适的C lexer。显而易见的问题是:你没有正确地跳过字符串文本和注释,它们都可能包含开关,{
或}
并且会破坏你的解析器。file.io链接似乎被破坏了。你为什么要为一个28年历史的过时版本的标准编写解析器?最好为标准C编写一个解析器。而使用状态机来解析C并不是一个好主意。@Olaf,这与使旧代码库现代化所需要做的工作相对应。make我觉得很有道理。
std::istream& operator >> (std::istream& is, SwitchStatements * ss)
{
assert(ss != nullptr);
using namespace std;
is.setstate(ios::goodbit);
string str;
while (is >> str)
{
if (str.find("switch") != string::npos) {
ss->appendBuffer(str);
int bracket_counter = 0;
char c = '0';
while ((c = is.get()) != EOF) {
ss->appendBuffer(c);
/* error handling */
try {
if (bracket_counter < 0)
throw std::exception{ "bracket counter cannot be less than 0" };
if (c == '}' && bracket_counter == 0)
throw std::exception{ "error cannot meet closing bracket before opening" };
if (c == EOF && bracket_counter != 0)
throw std::exception{ "error cannot meet eof before all closing brackets" };
}
catch (std::exception _e) {
cerr << "exception: ";
Beep(750, 1000);
cerr << _e.what() << endl;
cin.get();
cin.clear();
cin.ignore(INT_MAX, '\n');
}
/* end error handling */
if (c == '{')bracket_counter++;
if (c == '}')bracket_counter--;
if (c == '}' && !bracket_counter) {
ss->setOffset(is.tellg());
assert(bracket_counter == 0);
return is;
}
}
}
}
is.setstate(ios::badbit);
return is;
}
SwitchStatements::SwitchStatements(std::unique_ptr<std::string> _considering)
{
using namespace std;
stringstream ss;
ss << *_considering;
ss >> this;
if (ss.good())
{
stringstream ss_child;
string buf_sub = this->buffer.substr(this->buffer.find_first_of('{'));
ss_child << buf_sub;
SwitchStatements ss_switch;
while (ss_child >> ss_switch)
{
SwitchStatements ss_switch_child(
make_unique<string>(string{ ss_switch.buffer })
);
if (!ss_switch_child.buffer.empty() ||
!ss_switch_child.getSibling().empty())
children.push_back(ss_switch_child);
ss_child.clear();
ss_switch_child.clearAll();
}
siblings.push_back(SwitchStatements(
make_unique<string>(string{ (*_considering).substr(offset) })
));
}
}