2011-01-19 103 views
4

我正在为一个项目编写一个编译器前端,我试图理解什么是标记源代码的最佳方法。 我不能两种方式之间进行选择:Tokenizer效率问题

1)分词器读取的所有令牌:

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)解析阶段开始,并在需要的时候,在创建和使用令牌(代码似乎不是那么清楚)

什么是最好的方法?为什么??和效率? 在此先感谢您的答案

回答

3

传统上,编译器构造类将教会您在解析时逐个读取令牌。原因是,在那些日子里,内存资源非常稀少。你有你的处置千字节,而不是今天你做的千兆字节。尽管如此,我并不是故意建议您事先阅读所有的令牌,然后从令牌列表中解析出来。输入具有任意大小。如果你的内存太多,系统会变慢。由于它看起来只需要一个令牌,所以我一次只能从输入流中读取一个令牌。操作系统会为你缓冲和缓存输入流,所以它对于大多数目的来说足够快。

2

最好使用类似Boost::Spirit这样的标记。为什么重新发明轮子?

+2

因为它适用于考试:P – Salv0 2011-01-19 13:30:27

1

第一种方法是更好的,你可以接着也明白3个月后...(1)一般矫枉过正

+0

实际解析器几乎没有差异,词法分析器稍微复杂一些。轻微。对于任何程序员来说,使用缓冲流不应该是一个谜,因此peek()(或者任何你的流机制的首选名字)应该很容易记住,甚至几年之后...... – 2011-01-19 18:04:06

2

你的方法的代码 - 它不需要来标记整个文件之前解析它。

一个好的方法是实现一个缓冲的标记器,它将存储在列表中的戳记或未存取的标记,以及在获取或从文件中读取标记时使用该列表的元素该列表变空(a FILE *)。