1

我有一个基本的标记化结构/算法。这很复杂,我希望我能简单地澄清一下,让您了解我设计中的“缺陷”。

类 ParserState

// bool functions return false if getline() or stream extraction '>>' fails
static bool nextLine(); // reads and tokenizes next line from file and puts it in m_buffer
static bool nextToken(); // gets next token from m_buffer, via fetchToken(), and puts it in m_token
static bool fetchToken( std::string &token ); // procures next token from file/buffer

static size_t m_lineNumber;
static std::ifstream m_fstream;
static std::string m_buffer;
static std::string m_token;

此设置的原因是如果发生语法错误,则能够报告行号。根据解析器的阶段/状态,我的程序中会发生不同的事情,这个 ParserState 的子类使用m_tokennextToken继续。 fetchToken调用nextLineifm_buffer为空,并将下一个标记放入其参数中:

istringstream stream;

do // read new line until valid token can be extracted
{
    Debug(5) << "m_buffer contains: " << m_buffer << "\n";
    stream.str( m_buffer );

    if( stream >> token )
    {
        Debug(5) << "Token extracted: " << token << "\n";
        m_token = token;
        return true; // return when token found
    }
    stream.clear();
} while( nextLine() );
// if no tokens can be extracted from the whole file, return false
return false;

问题是从 m_buffer 中删除的令牌没有被删除,并且每次调用都会读取相同的令牌nextToken()。问题是m_buffer可以修改,因此istringstream::str在循环中调用。但这是我的问题的原因,据我所知,它无法解决,因此我的问题是:如何让stream >> token从字符串流内部指向的字符串中删除某些内容?也许我不需要使用a stringstream,而是在这种情况下使用更基本的东西(比如找到第一个空格并从字符串中删除第一个标记)?

谢谢十亿!

PS:任何改变我的函数/类结构的建议都是可以的,只要它们允许跟踪行号(所以没有完整的文件读入m_buffer和类成员istringstream,这是我在想要行号错误报告之前所拥有的)。

4

3 回答 3

1

为什么不简单地制作m_bufferastd::istringstream而不是 a std::string?您将删除一个临时变量并获得所需的效果。每当您更改m_buffer语句时,例如

m_buffer = ...

改为这样写:

m_buffer.str(...);
于 2010-11-07T20:55:30.287 回答
0

处理行号报告的常用方案是一次读取一行,就像你一样,增加行数,然后当你的标记器开始构建一个标记时,它会拍摄行号的快照并将其存储到标记数据结构(通常包含行号、标记类型和标记值(如果有))。

这将行读取与令牌构建分离,而不会丢失行号。这也意味着你可以有很多标记,它们都可以有行号(包括不同的行号),一个标记可以从一行开始并在另一行结束,等等。

于 2010-11-08T00:39:09.790 回答
0

为了避免多次读取同一个令牌,我认为您必须在streamusing中获得位置,tellg然后使用它来恢复它seekg(这些方法在此处描述)。然而std::istringstream,在这里使用看起来对我来说有点矫枉过正。我宁愿m_buffer直接合作。

于 2010-11-07T21:03:27.457 回答