0

我正在尝试浏览一个带有汇编指令的简单文本文件,它看起来像这样

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 = ", \n\t";
        current = next + 1;
        next = line.find_first_of(delimeters, current);
        arg1 = line.substr(current, next-current);

        cout << arg1<<endl;

        i++;
    }
}
4

2 回答 2

2

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

current = next + 1;

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

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

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

如果我想做这项工作,我使用regex,或者std使用boost正则表达式,这个任务是小菜一碟,只需使用:

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)
}
于 2012-09-16T21:03:49.523 回答
1

问题是寻找每个后续单词的开头: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 (或类似的)进行单元测试。

于 2012-09-16T20:48:30.927 回答