分析示例文本文件并将其拆分

Parsing a sample text file and splitting it up

本文关键字:拆分 文件 文本      更新时间:2023-10-16

我试图浏览一个包含汇编指令的简单文本文件,它看起来像这个

TOP   NOP
VAL   INT 0
TAN   LA 2,1

这只是一个小例子,所以我可以向你展示它是如何工作的。基本上,我将第一个标签放在标签中,然后第二个标签是NOP、INT和LA,并将它们放在操作码中。

之后,我将采用第一个参数(0和2),并将它们放置在arg1中。然而,这就是我的问题所在。对于我现有的代码,当我将参数放入字符串时,我得到的输出是这样的

TOP
0
2

很明显,我只想让最后两个成为唯一的,但我该如何做到这一点,让TOP不会在我的第一次争论中陷入困境?

#include <string>
#include <iostream>
#include <cstdlib>
#include <string.h>
#include <fstream>
#include <stdio.h>
using namespace std;
int main(int argc, char *argv[])
{
// If no extra file is provided then exit the program with error message
if (argc <= 1)
{
cout << "Correct Usage: " << argv[0] << " <Filename>" << endl;
exit (1);
}
// Array to hold the registers and initialize them all to zero
int registers [] = {0,0,0,0,0,0,0,0};
string memory [16000];
string Symtablelab[1000];
int Symtablepos[1000];
string line;
string label;
string opcode;
string arg1;
string arg2;
// Open the file that was input on the command line
ifstream myFile;
myFile.open(argv[1]);
if (!myFile.is_open())
{
cerr << "Cannot open the file." << endl;
}
int counter = 0;
int i = 0;
int j = 0;
while (getline(myFile, line, 'n'))
{
if (line[0] == '#')
{
continue;
}
if (line.length() == 0)
{
continue;
}
if (line[0] != 't' && line[0] != ' ')
{
string delimeters = "t ";
int current;
int next = -1;
current = next + 1;
next = line.find_first_of( delimeters, current);
label = line.substr( current, next - current );
Symtablelab[i] = label;
current = next + 1;
next = line.find_first_of(delimeters, current);
opcode = line.substr(current, next - current);
if (opcode != "WORDS" && opcode != "INT")
{
counter += 3;
}
if (opcode == "INT")
{
counter++;
}
delimeters = ", nt";
current = next + 1;
next = line.find_first_of(delimeters, current);
arg1 = line.substr(current, next-current);
cout << arg1<<endl;
i++;
}
}

使用这种技术有很多弱点,您根本不会检查任何结果。例如,当你说:

current = next + 1;

您应该已经知道,项目之间只有一个分隔符!否则,你应该绕过所有项目,当你说时

next = line.find_first_of(delimeters, current);
<something> = line.substr(current, next - current)

你应该确定find_first_of找到了一些东西,否则它将返回-1,next - current将是负的!

如果我想做这项工作,我使用regex,来自stdboost,使用regex,这项任务很简单,只需使用:

std::matches m;
std::regex rx("\s*(\w+)\s+(\w+)(?:\s+(\d+)\s*(?:,(\d+))?)?");
if (std::regex_match(line, m, rx)) {
// we found a match here
string label = m.str(1);
string opcode = m.str(2);
string arg1 = m.str(3), arg2 = m.str(4)
}

问题是寻找每个后续单词的开头:current = next + 1。您需要查找第一个非分隔符作为单词的开头,并在查找参数之前检查是否位于行的末尾。

添加调试信息后,我看到以下内容:

>> label: start=0 end=3 value="TOP"
>> opcode: start=4 end=4 value=""
>> label: start=0 end=3 value="VAL"
>> opcode: start=4 end=4 value=""
>> label: start=0 end=3 value="TAN"
>> opcode: start=4 end=4 value=""

这告诉我每次操作码的尝试都是在寻找另一个分隔符。

问题是,你只在单词后面增加一个,下一行.substr()会捕获分隔符。

在启动后的查找中,更改:

current = next + 1;

至:

current = line.find_first_not_of(delimeters, next + 1);

这允许它在任何和所有分隔符之后查找下一个单词的开头。

此外,您希望使参数的查找以剩余的行长度为条件,因此将其封装在if(next >0) { ... }中。

这给了我,我的调试和你的原始输出(有条件):

>> label: start=0 end=3 value="TOP"
>> opcode: start=6 end=-1 value="NOP"
>> label: start=0 end=3 value="VAL"
>> opcode: start=6 end=9 value="INT"
>> arg1: start=10 end=-1 value="0"
0
>> label: start=0 end=3 value="TAN"
>> opcode: start=6 end=8 value="LA"
>> arg1: start=9 end=10 value="2"
2

从主循环中重新考虑你的解析/标记,这样你就可以专注于它们。您甚至可能想要获得cppunit(或类似的)来帮助您测试解析函数。在没有这样的情况下,它可以帮助您转到一个地方并插入调试信息,如:

cout << ">> " << whatIsBeingDebugged << ": " << start=" << current 
<< " end=" << next << " value= "" << value << """ << endl;

制作一个强大的词法分析器和解析器是许多库(lex和yacc、flex和bison等)的主题,可以是正则表达式等其他库的应用,甚至是整个大学课程。这是工作。但是,只要有条理、彻底并孤立地测试工件,例如使用cppunit(或类似的)进行单元测试。