我正在为项目编写一个编译器前端,我正在尝试理解什么是标记源代码的最佳方法。 我无法在两种方式中做出选择:
1)tokenizer读取所有令牌:
bool Parser::ReadAllTokens()
{
Token token;
while( m_Lexer->ReadToken( &token ) )
{
m_Tokens->push_back( token );
token.Reset(); // reset the token values..
}
return !m_Tokens->empty();
}
然后解析阶段开始,在m _ Tokens
列表上运行。通过这种方式,方法getNextToken(),peekNextToken()和ungetToken()通过迭代器相对容易实现,并且解析代码编写得很清楚(不会被getNextToken()破坏,即:
getNextToken();
useToken();
getNextToken();
peekNextToken();
if( peeked is something )
ungetToken();
..
..
)
2)解析阶段开始,并在需要时创建并使用令牌(代码似乎不那么清楚)
什么是最好的方法??为什么??和效率? 提前感谢您的答案
答案 0 :(得分:3)
传统上,编译器构造类教您在解析时逐个读取令牌。原因在于,在那些日子里,记忆资源稀缺。您可以使用千字节,而不是今天的千兆字节。
话虽如此,我并不是建议您提前阅读所有令牌,然后从您的令牌列表中解析。输入是任意大小的。如果你占用太多内存,系统会变慢。由于看起来你在前瞻中只需要一个令牌,我一次从输入流中读取一个令牌。操作系统将为您缓冲和缓存输入流,因此对于大多数用途来说它足够快。
答案 1 :(得分:2)
最好使用Boost::Spirit之类的东西进行标记。为什么重新发明轮子?
答案 2 :(得分:2)
您的方法(1)通常是过度的 - 在解析之前不需要对整个文件进行标记。
一个好的方法是实现一个缓冲的标记化器,它将在列表中存储poke或unget的标记,并在“get”时使用该列表的元素,或者从文件中读取标记。 list变为空(la FILE *)。
答案 3 :(得分:1)
第一种方法更好,因为您可以在3个月后理解代码......