【问题标题】:Tokenizer efficiency question分词器效率问题
【发布时间】:2011-01-19 13:03:13
【问题描述】:

我正在为一个项目编写一个编译器前端,并试图了解对源代码进行标记的最佳方法是什么。 我无法在两种方式之间进行选择:

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

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

【问题讨论】:

    标签: c++ parsing compiler-construction tokenize


    【解决方案1】:

    传统上,编译器构造类会教您在解析时一一阅读标记。其原因是,在过去,内存资源稀缺。您可以使用千字节,而不是像今天这样的千兆字节。

    话虽如此,我并不是建议您提前阅读所有令牌,然后从您的令牌列表中解析。输入是任意大小。如果你占用太多内存,系统会变慢。由于看起来您在前瞻中只需要一个令牌,因此我会从输入流中一次读取一个。操作系统将为您缓冲和缓存输入流,因此对于大多数用途来说足够快。

    【讨论】:

      【解决方案2】:

      最好使用Boost::Spirit 之类的东西来标记化。为什么要重新发明轮子?

      【讨论】:

        【解决方案3】:

        您的方法 (1) 通常是多余的 - 在解析整个文件之前不需要标记整个文件。

        一个好的方法是实现一个缓冲的标记器,它将存储在一个列表中被戳或取消的标记,并在“get”时消耗这个列表的元素,或者在列表为空(a la FILE*)。

        【讨论】:

          【解决方案4】:

          第一种方法更好,3个月后你也能看懂代码...

          【讨论】:

          • 实际解析器的差异很小或没有差异,词法分析器会稍微复杂一些。勉强。使用缓冲流对任何程序员来说都不应该是一个谜,因此 peek() (或任何你的流机制的首选名称)应该很容易记住,即使是几年后......
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-01
          • 1970-01-01
          • 1970-01-01
          • 2013-06-15
          相关资源
          最近更新 更多