CONTEXT
我正在编写ANSI C代码解析器。目标是在c代码中找到有限状态机实现并进行逆向工程以创建有关现有状态和事件传输的文档。
我们需要查找c代码中有限状态机的3种常见实现:使用嵌套的switch语句(事件上状态内层开关上的外层开关),每个包含函数指针的结构的2D数组和下一个状态(执行转换函数后),一维函数指针数组和二维状态数组。
主要目标是有限状态机检测。
要在嵌套的switch语句中检测状态机,我在c ++中编写ac解析器,从c源代码中提取所有switch语句,并将它们存储在我的代码中存在的parent-child-sibling关系中。
问题
问题在于我的c解析器中的模块,它假设从c源代码中提取switch语句并将其存储在我的代码中存在的parent-child-sibling关系中。
计划输出
当在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)
{
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::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) })
));
}
}