编译原理——基于LR(1)的语法检查器(二)

本文详细介绍了如何构造LR(1)项集族,涉及计算FIRST集合、项集闭包、GOTO函数及SETS函数的实现。通过对编译原理的理解,阐述了在实际编程中如何处理文法符号的转换,并强调了数据结构选择在实现过程中的关键作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造LR(1)项集族

  在龙书的P167中为我们提供了为某一个文法G’构造LR(1)项集族的完整算法,照搬如下:

SetOfItems CLOSURE(I) {
    repeat
        for(I中的每个项[A->α·Bβ,a])
            for(G'中的每个产生式B->γ)
                for(FIRST(βa)每个终结符号b)
                    将[B->·γ,b]加入到集合I中;
    until 不能向I中加入更多的项;
    return I;
}

SetOfItems GOTO(I,X) {
    将J初始化为空集;
    for(I中的每个项[A->α·Xβ,a])
        将项[A->αX·β,a]加入到集合J中;
    return CLOSURE(J);
}

void items(G') {
    将C初始化为{CLOSURE}({[S'->·S,$]});
    repeat
        for(C中的每个项集I)
            for(每个文法符号X)
                if(GOTO(I,X)非空且不在C中)
                    将GOTO(I,X)加入C中;
    until 不再有新的项集加入到C中;
}

  上述的代码只是从理论角度提供的可行的算法,而具体怎么写还要根据我们的实现来进行修改。上边的item便是计算LR(1)项集族的主要函数,它会分别调用CLOSURE函数计算一个内核项所产生的项集,之后调用GOTO函数计算一个项集在遇到一个终结符或者非终结符时所产生的内核项。(内核项的概念十分重要,内核项是指包括初始项S'->·S以及点不在最左端的所有项,一个项集其实只用内核项表示就足够了,两个项集如果内核项一样,那这两个项集一定是相同的。)

计算FIRST(βa)

  注意到函数CLOSURE在使用时调用了一个并未在算法中出现的函数FIRST,函数FIRST(α)被定义为可从α推导得到的串的首符号的集合,其中α是任意的文法符号串。虽然龙书中没有给出伪代码的算法,但是计算的规则已经表达得很清楚了:
1. 如果X是一个终结符号,那么FIRST(X)=X

  1. 如果X是一个非终结符号,且X->Y1Y2···Yk是一个产生式,其中k≥1,那么如果对于某个i,a在FIRST(Yi)中且ε在所有的FIRST(Y1)、FIRST(Y2)、···、FIRST(Yi-1)中,就把a加入到FIRST(X)=X中。

  2. 如果X->ε是一个产生式,那么将ε加入到FIRST(X)中。

      那么我们现在就按照上述的方式给出一个FIRST(α)的具体实现:

typedef struct _used
{
    int use[100];
    int num;
}used;


void count_first(element *e, element **first_elements, used *is_used)
{
    item *temp;
    if (!e)
        return;
    for (int i = 0; i < is_used->num; i++)
    {
        if (e->is_terminator&&e->type.t_index == is_used->use[i])
            return;
        else if (!e->is_terminator&&e->type.pro->p_index == is_used->use[i])
            return;
    }

    if (e->is_terminator)
    {
        is_used->use[is_used->num++] = e->type.t_index;
        add_e2e(e, first_elements);
    } else
    {
        is_used->use[is_used->num++] = e->type.pro->p_index;
        temp = e->type.pro->items;
        for (; temp; temp = temp->next)
        {
            if (temp->ele->is_terminator&&a
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值