自上而下的递归下降解析:依靠尾声优化

Top Down Recursive Descent Parsing : Relying on tail call optimization

本文关键字:依靠 声优 优化 递归 自上而下      更新时间:2023-10-16

我正在构建一个递归下降解析器,我有两个规则,这些规则构建了一个列表:

ValueList  -> TOKEN_IDENTIFER TOKEN_QUOTE ValueListP
ValueListP -> ValueList
           |  %EPSILON%

现在,我知道您可以轻松地将这两个规则优化为单个规则,但我也知道编译器可以并且将在看到它的位置执行尾部调用优化。这是我当前的代码:

void Parser::grammarValueList( std::deque<std::unique_ptr<ValueNode>>& arg1 )                                                                                                                                                                 
{                                                                                                                                                                                                                                             
    std::string var1 = m_currentToken.getValue().string;                                                                                                                                                                                  
    if( acceptToken( Token::Type::TOKEN_IDENTIFIER ) )                                                                                                                                                                                    
    {                                                                                                                                                                                                                                     
            std::string var2 = m_currentToken.getValue().string;                                                                                                                                                                          
            if( acceptToken( Token::Type::TOKEN_QUOTE ) )                                                                                                                                                                                 
            {                                                                                                                                                                                                                             
                    arg1.push_back( std::unique_ptr<ValueNode>( new ValueNode( var1, var2 ) ) );                                                                                                                                          
                    if( peekValueListP() )                                                                                                                                                                                                
                    {                                                                                                                                                                                                                     
                            return grammarValueListP( arg1 );                                                                                                                                                                             
                    }                                                                                                                                                                                                                     
            }                                                                                                                                                                                                                             
    }                                                                                                                                                                                                                                     
    throw ParseException( "Error: did not expect "" + m_currentToken.toString() + """ );                                                                                                                                                
}
void Parser::grammarValueListP( std::deque<std::unique_ptr<ValueNode>>& arg1 )                                                                                                                                                                
{                                                                                                                                                                                                                                             
    if( peekValueList() )                                                                                                                                                                                                                 
    {                                                                                                                                                                                                                                     
            return grammarValueList( arg1 );                                                                                                                                                                                              
    }                                                                                                                                                                                                                                     
    else                                                                                                                                                                                                                                  
    {                                                                                                                                                                                                                                     
            return;                                                                                                                                                                                                                       
    }                                                                                                                                                                                                                                     
    throw ParseException( "Error: did not expect "" + m_currentToken.toString() + """ );                                                                                                                                                
}

所以我有两个问题:

1)我提供的代码杠杆尾部调用优化吗?

2)即使一块代码确实利用了尾巴调用优化,我们作为程序员是否应该在微不足道的情况下试图使我们的自我(删除递归并用循环替换)?

不,grammarValueList不执行尾声。

问题是std::string型的局部变量有两个局部变量,该变量具有非平凡的破坏者。这些破坏者必须在方法返回之前调用,这是在调用grammarValueListP之后的。因此,呼叫grammarValueListP不在尾部位置。

当然,有可能访问破坏者定义的优化器可能会发现,可以过早地破坏var1var2而不会改变函数的可见行为(假设可能;它取决于;它取决于;部分关于ValueNode构造函数内部发生的事情)。但是我不认为大多数C 实现都试图优化尾巴调用。

就个人而言,我会使用一个循环,因为即使您设法消除了Destructor呼叫,编译器仍然找不到TCO。从这个显然很简单的例子中可以看出,C 中的尾巴通常并不像它们在表面上那样琐碎,而且令人惊讶的是说服优化者生产一个。