我有一个基本的标记化结构/算法。它非常复杂,我希望我能够简单地澄清它,以启发你的设计中的“缺陷”。
class 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_token
和nextToken
继续。如果fetchToken
为空,则nextLine
调用m_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
从字符串流内部指向的字符串中删除某些内容?也许我需要不使用stringstream
,但在这种情况下更基本的东西(比如找到第一个空格并从字符串中剪切第一个标记)?
感谢十亿!
PS:任何改变我的函数/类结构的建议都可以,只要它们允许跟踪行号(因此没有完整的文件读入m_buffer
和类成员istringstream
,是我之前想要的行号错误报告)。
答案 0 :(得分:1)
为什么不简单地将m_buffer
设为std::istringstream
而不是std::string
?您将删除临时变量以及获得所需的效果。每当您在
m_buffer
时
m_buffer = ...
改为写这个:
m_buffer.str(...);
答案 1 :(得分:0)
为避免多次阅读同一令牌,我认为您必须使用stream
在tellg
中获取该位置,然后使用seekg
将其恢复(这些方法已在{{3}中进行了描述})。但是在这里使用std::istringstream
看起来像是一种矫枉过正。我宁愿直接与m_buffer
合作。
答案 2 :(得分:0)
处理行号报告的常用方案是按时读取第一行,增加行数,然后当您的标记生成器开始构建标记时,它会获取行号的快照,将其存储到令牌数据结构中(通常包含行号,令牌类型和令牌值,如果有的话)。
这会在不丢失行号的情况下将行读取与令牌构建分离。这也意味着你可以有很多令牌,它们都可以有行号(包括不同的行号),令牌可以从一行开始,然后在另一行上完成,等等。