构造LR(0)文法的Action表和GOTO表

1 实验目的

构造LR(0)文法的Action表和GOTO表

2 实验要求

  1. 用C++ 实现;

  2. 编程构造如下LR(0)文法的Action表和GOTO表,文法G[S]:

(0) S->E (1)E->aA (2) E->bB (3) A->cA (4) A->d (5) B->cB (6)B->d

  1. Action表和GOTO表输出到output.txt文件。

  2. 提供名为LR0.exe的执行文件实现上述功能,还需提供源文件以及名为设计说明.doc的说明文件。

3 结果展示

在这里插入图片描述

4 设计思路

4.1 总体思路

根据现有的文法,推导出如下图所示的DFA。

在这里插入图片描述

如何生成这样的DFA图,则使用数据结构的图结构,并使用邻接表的形式来构图。

在根据以上DFA图,顺序遍历各个状态(in),构造出LR(0)分析表,即ACTION和GOTO表

4.2详细思路

4.2.1构建增广文法

本实验所提供的文法如下:

(0) S->E

(1)E->aA

(2) E->bB

(3) A->cA

(4) A->d

(5) B->cB

(6)B->d

已经满足增广文法的需要,直接在程序中使用

4.2.2状态数据结构的确立

自定义数据结构item代表DFA图中的状态(如i0),拥有如下成员函数

set<string> production; //状态包含的产生式
arc_item *next;         //指向连接的那个状态
int id;                 //状态号
int state = -1;         //状态,用于判断是否进行规约或转移

使用set数据结构来存储产生式,可以不用考虑生成的产生式重复的情况。

state则用于生成action和GOTO表时,判断这个状态是否为移进还是规约还是直接接受。

state=0时,产生式为S’->S.型则置ACTION[k, #]为“接受”,简记为“acc”;

state>0时,产生式为A->α.型,对任何终结符a, 置ACTION[k, a]为“用产生式A->α进行归约”,简记为“rj”,且state值对应j,用j号文法进行规约。

其余情况state=-1时,产生式形如Aα->.aβ,为移进情况。

4.2.3状态的闭包计算

在这里插入图片描述

即为“.”后的字母如果为非终结符,则将该非终结符所能推导的产生式加入到该状态中,且将“.”加入到“->”后。

如初态为
I0:S->.E

闭包运算后为

I0: S->.E
E->.aA
E->.bB

4.2.4 构造LR(0)FSM的所有状态

在这里插入图片描述

即为

遍历当前的所有状态,再遍历当前状态Im的所有产生式,若“.”不在产生式的最后,

则将“.”向后移动一位,被跳过的字符为a,这样生成的一个新的产生式A,再生成一个新的状态In,将新生成的产生式A加入到这个新的状态In中,再对这个状态进行一次闭包计算。将这个In加入到状态集中,且状态不能重复。这样完成后,在状态Im状态In连接一条边a,即为状态Im接受a字符后转移到状态In

重复上述操作,直到状态机的数量不再增大。

代码实现

//状态集构造
void structure() 
{
    bool done = 0; //构造是否完成
    int i = 0;
    while (done == 0 || i <= items.size() - 1)
    {

        set<string>::iterator j;
        done = 1;
        for (j = items[i].production.begin(); j != items[i].production.end(); j++) // 产生式的遍历
        {
            string tmp = *j;
            int index = tmp.find('.');
            if (index == tmp.length() - 1) //'.'已经在最后了
                continue;

            char trans = tmp[index + 1]; //转移状态所需的字符
            move_point(tmp);
            item new_item = item(tmp);
            new_item.revise();

            bool same = false;
            int n; //用于标记已存在的状态
            for (int k = 0; k < items.size(); k++)
            {
                if (new_item == items[k])
                {
                    same = true;
                    n = k;
                    break;
                }
            }
            if (same == true) //已经存在该状态集
            {
                t_id--;
                arc_item *edge = new arc_item();
                edge->next = items[i].next;
                edge->id = items[n].id;
                edge->weight = trans;

                item &p_item = const_cast<item &>(items[i]); //由于在set中元素为const无法修改,需要使用const_cast来进行类型修改

                p_item.next = edge; //将边接入
            }
            else
            {
                items.push_back(new_item);
                done = 0; //有新的状态集,需要继续进行构造
                //使用插头法接入边节点
                arc_item *edge = new arc_item();
                edge->next = items[i].next;
                edge->id = new_item.id;
                edge->weight = trans;

                item &p_item = const_cast<item &>(items[i]); //由于在set中元素为const无法修改,需要使用const_cast来进行类型修改

                p_item.next = edge; //将边接入
            }
        }
        i++;
    }

构建完成后,DFA图即构造完成。

通过断点可查询到图的情况,如下图
在这里插入图片描述

得到的DFA图如下

在这里插入图片描述

4.2.5绘制action goto表

构建一个二维数组,根据DFA图和各个状态state的值来确定内容,最后按格式输出即可。

5 算法亮点

​ 由于在LR(0)FSM的构造中需要反复判断有没有重复,比如新生成的产生式是否与原来的重复,新生成的状态有没有重复,故使用set数据结构来储存,这样新产生式就可以直接加入,让set自行判断是否需要新增这个产生式。

​ 采用了邻接表图的形式来构造DFA,十分直观便于理解和操作。

点我查看详细代码!!.

扩展:
在这里插入图片描述

  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
构造 LR(0) 自动机的流程如下: 1. 对于文法的每个产生式,添加一个初始状态 S,并在该状态中添加一个新的项目,该项目的形式为 “S → •A”,其中 A 是产生式的右侧第一个符号。 2. 对于每个状态和每个项目,计算可扩展的下一个符号集合。如果该符号是非终结符,则对于非终结符的每个产生式,添加一个新的项目,该项目的形式为 “A → •B”,其中 B 是产生式的右侧第一个符号。如果该符号是终结符,则将该项目移动到该状态的下一个状态。 3. 重复执行步骤 2,直到没有新的项目可以添加。 4. 对于每个状态,将其所有项目按照点号后面的符号进行分组,生成新的状态。如果一个组中包含多个相同的项目,则将它们合并为一个项目。 5. 对于每个状态,计算该状态的可规约符号。如果一个项目的点号在产生式的末尾,则该项目是可规约的,规约该项目的符号为产生式左侧的非终结符。 6. 将所有状态和转移添加到 LR(0) 自动机中。 7. 构造 ACTION GOTO 。对于每个状态和每个终结符,如果该状态包含一个项目形如 “A → α•aβ”,则在 ACTION 中将该状态和终结符 a 相关联,并将该终结符的动作设置为 “shift” 加上下一个状态的编号。对于每个状态和每个可规约符号,如果该状态包含一个项目形如 “A → α•”,则在 ACTION 中将该状态和可规约符号相关联,并将该符号的动作设置为 “reduce” 加上产生式的编号。对于每个状态和每个非终结符,如果该状态可以通过非终结符进行转移,则在 GOTO 中将该状态和非终结符相关联,并将该非终结符的转移设置为下一个状态的编号。 8. 如果文法是 SLR(1) 或 LR(1) 文法,则自动机构造完成。如果文法不是 SLR(1) 或 LR(1) 文法,则需要进行相应的冲突解决。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值