布尔表达式的LR翻译器

自动微分原理与PyTorch梯度机制深度解析 自动微分(AD)是现代深度学习框架的底层核心机制,它既非符号微分的表达式膨胀,也非数值微分的精度妥协,而是基于计算图与链式法则的高效、精确梯度计算范式。其原理在于将任意可编程函数分解为原子运算节点,前向执行并构建依赖关系,反向按拓扑序累积局部梯度,实现O(1)时间复杂度与机器精度级准确率。这一技术支撑了PyTorch的autograd、TensorFlow的GradientTape等关键能力,直接决定混合精度训练中GradScaler的有效性、自定义算子的可微分性以及分布式训练的梯度一致性。本文深入剖析反向 阅读详情

布尔表达式的LR翻译器

1引言

编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法分析、语法制导翻译、中间代码生成、存储管理、代码优化和目标代码生成。 编译原理是计算机专业设置的一门重要的专业课程这门课在理论、技术、方法上都对学生提供了系统而有效的训练,有利于提高软件人员的素质和能力。

所谓LR(K)分析,是指从左至右扫描和自底向上的语法分析,且在分析的每一步,只须根据分析栈当前已移进和归约出的全部文法符号,并至多再向前查看K个输入符号,就能确定相对于某一产生式左左部符号的句柄是否已在分析栈的顶部形成,从而也就可以确定当前所应采取的分析动作(是移进还是按某一产生式进行归约等)。

2需求分析

已知有如下的布尔表达式文法:

B ®B and T | T

               T®T or F | F

               F®notF|true|false |(B)|i rop i

利用LR分析法编制、调试其语法及语义分析程序,生成的中间代码为四元式。编制好分析程序后计若干用例,上机测试并通过所设计的分析程序。

布尔表达式的LR分析分为扩展文法,构造识别活动前缀的DFA图,判断有误冲突,若有冲突,则消除冲突和构造LR分析表等步骤。

l  首先要拓广文法:

非二义性文法如下:

   (0)  B’ ® B               

   (1)  B ® B and T

   (2)  B ® T

    (3)  T  ® T or F

     (4) T ® F

    (5)  F ® not F

(6)  F ®  ( B )

(7)  F ®  true

(8)  F ®  false

(9)  F ®  i rop i

l  构造识别活动前缀的DFA图

l  判断有无冲突

LR(0)分析时有移进—规约冲突,但冲突可以由SLR(1)分析解决。

l  构造LR分析表

 

状态

Si

ACTION

GOTO

and

or

not

true

false

(

)

i

rop

#

B

T

F

0

S4

S5

S6

S7

S8

1

2

3

1

S9

R2

ACC

2

R2

S10

R2

R2

3

R4

R4

R4

R4

4

S4

S5

S6

S7

S8

11

5

R7

R7

R7

R7

6

R8

R8

R8

R8

7

S4

S5

S6

S7

S8

12

2

3

8

S13

9

S4

S5

S6

S7

S8

14

3

10

S4

S5

S6

S7

S8

15

11

R5

R5

R5

R5

12

S9

S16

13

R3

S17

14

R1

S10

R1

R1

15

R3

R3

R3

R3

16

R6

R6

R6

R6

17

R9

R9

R9

R9

3总体设计及开发工具的选择

3.1设计分析

        编译器设计的编译程序涉及到编译五个阶段中的三个,即词法分析器、语法分析器和中间代码生成器。编译程序的输出结果为中间代码即逆波兰式。整个编译程序分为三部分:词法分析部分、语法分析处理及逆波兰式生成部分、输出显示部分。

        编译程序需要在单词级别上来分析和翻译源程序,所以首先要识别出单词,而词法分析部分的任务是:从左至右扫描源程序的字符串,按照词法规则(正则文法规则)识别出一个个正确的单词,并转换成该单词相应的二元式(种别码、属性值)交给语法分析使用。因此,词法分析是编译的基础。执行词法分析的程序称为词法分析器。

语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作。

语法分析中主要以二元式作为输入部分,所以输出显示部分的任务是将二元式通过LR分析表对语法分析处理过程进行控制,使逆波兰式翻译的工作有条不紊的进行,同时识别语法分析中的语法错误。

3.2设计原理

3.2.1词法分析

词法分析是编制一个读单词的过程,从输入的源程序中,识别出各个具有独立意义的单词,即基本保留字、标识符、常数、运算符、分隔符五大类。并依次输出各个单词的内部编码及单词符号自身值。程序语言的单词符号一般分为五种:关键字(保留字/基本字)、标识符、常数、运算符、界限符。

词法分析的功能是输入源程序,输出单词符号。词法分析的单词符号常常表示成二元式(单词种别码,单词符号的属性值)。

词法分析器的设计方法有如下四个步骤:

1、写出该语言的词法规则。

2、把词法规则转换为相应的状态转换图。

3、把各转换图的初态连在一起,构成识别该语言的自动机。

4、设计扫描器;把扫描器作为语法分析的一个过程,当语法分析需要一个单词时,就调用扫描器。扫描器从初态出发,当识别一个单词后便进入终态,送出二元式

3.2.2语法分析

语法分析是编译程序的核心部分,其主要任务是确定语法结构,检查语法错误,报告错误的性质和位置,并进行适当的纠错工作.法分析的方法有多种多样,常用的方法有递归子程序方法、运算符优先数法、状态矩阵法、LL(K)方法和LR(K)方法。归纳起来,大体上可分为两大类,即自顶向下分析方法和自底向上分析方法. Syntax进行语法分析。对于语法分析,这里采用LR(1)分析法,判断程序是否满足规定的结构.构造LR(1)分析程序,利用它进行语法分析,判断给出的符号串是否为该文法识别的句子,了解LR(K)分析方法是严格的从左向右扫描,和自底向上的语法分析方法。

3.2.3中间代码生成

进入编译程序的第三阶段:中间代码产生阶段。为了使编译程序有较高的目标程序质量,或要求从编译程序逻辑结构上把与机器无关和与机器有关的工作明显的分开来时,许多编译程序都采用了某种复杂性介于源程序语言和机器语言之间的中间语言。常用的几种中间语言有: 逆波兰式、四元式、三元式、树表示。本课程设计主要实现逆波兰式的生成。

逆波兰式定义: 将运算对象写在前面,而把运算符号写在后面。用这种表示法表示的表达式也称做后缀式。逆波兰式的特点在于运算对象顺序不变,运算符号位置反映运算顺序。采用逆波兰式可以很好的表示简单算术表达式,其优点在于易于计算机处理表达式。

3.3开发工具

Windows环境下使用Visualstudio2012

4设计原则

算法是对问题求解过程的一种描述,是为解决一个或一类问题给出的一个确定的、有限长的操作序列。严格说来,一个算法必须满足以下五个重要特性:

l  有穷性:对于任意一组合法的输入值,在执行有穷步骤之后一定能结束。

l  确定性:对于每种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径。 

l  可行性:算法中的所有操作都必须足够基本,都可以通过已经实现的基本操作运算有限次实现之。

l  有输入:作为算法加工对象的量值,通常体现为算法中的一组变量。但有些算法的字面上可以没有输入,实际上已被嵌入算法之中。

l  有输出:它是一组与“输入”有确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法的功能。

  在设计算法时,通常应考虑以下原则:首先说设计的算法必须是“正确的”,其次应有很好的“可读性”,还必须具有“健壮性”,最后应考虑所设计的算法具有“高效率与低存储量”。

  所谓算法是正确的,除了应该满足算法说明中写明的"功能"之外,应对各组典型的带有苛刻条件的输入数据得出正确的结果。在算法是正确的前提下,算法的可读性是摆在第一位的,这在当今大型软件需要多人合作完成的环境下是换重要的,另一方面,晦涩难读的程序易于隐藏错误而难以调试。算法的效率指的是算法的执行时间,算法的存储量指的是算法执行过程中所需最大存储空间。

算法是程序设计的另一个不可缺的要素,因此在讨论数据结构的同时免不了要讨论相应的算法。这里有两重意思,即算法中的操作步骤为有限个,且每个步骤都能在有限时间内完成。确定性表现在对算法中每一步的描述都没有二义性,只要输入相同,初始状态相同,则无论执行多少遍,所得结果都应该相同。

5数据结构与模块说明

5.1ACTION表和GOTO表

在程序中,我们使用两个二维数组存储SLR分析表,并初始化,初始化SLR表,其中action表中:100表示acc,除了100以外整数表示移进状态;负数表示用对应产生式进行规约。

int action[18][10]={ { 0   , 0   ,4  ,5    , 6   ,7  , 0   , 8   ,0   , 0},//0

                                  {9  , 0   ,0  ,0    ,0   ,0  ,-2   , 0   ,0   ,100},//1

                               {-2 ,10  ,0  ,0    , 0   ,0  ,-2   ,0   , 0   ,-2},//2

                                  {-4  ,-4   ,0  ,0    , 0   ,0  ,-4   , 0   ,0   , -4},//3

                                  {0  , 0   ,4  ,5    ,6   ,7  ,0   , 8   ,0   , 0},//4

                                  {-7  ,-7   ,0  ,0    , 0   ,0  ,-7   , 0   ,0   , -7},//5

                                  {-8  ,-8   ,0  ,0    , 0   ,0  ,-8   , 0   ,0   , -8},//6

                                  {0  , 0   ,4  ,5    ,6   ,7  ,0   , 8   ,0   , 0},//7

                                  {0  , 0   ,0  ,0    ,0   ,0  ,0   , 0   ,13  , 0},//8

                                  {0  , 0   ,4  ,5    ,6   ,7  ,0   , 8   ,0   , 0},//9

                                  {0  , 0   ,4  ,5    ,6   ,7  ,0   , 8   ,0   , 0},//10

                               {-5 ,-5   ,0  ,0    , 0   ,0  ,-5   ,0   , 0   ,-5},//11

                                  {9  , 0   ,0  ,0    ,0   ,0  ,16  , 0   , 0   , 0},//12

                                  {0  , 0   ,0  ,0    ,0   ,0  ,0   ,17  ,0   , 0},//13

                                  {-1  ,10  ,0  ,0    , 0   ,0  ,-1   , 0   ,0   , -1},//14

                                  {-3  ,-3   ,0  ,0    , 0   ,0  ,-3   , 0   ,0   , -3},//15

                                  {-6  ,-6   ,0  ,0    , 0   ,0  ,-6   , 0   ,0   , -6},//16

                                  {-9  ,-9   ,0  ,0    , 0   ,0  ,-9   , 0   ,0   , -9}};//17

int gotol[18][3]={  {1  ,2    , 3},{0   ,0    , 0},{0   ,0    , 0},{0   ,0    , 0},       {0   ,0    ,11},

                                  {0   ,0    , 0},{0   ,0    ,0},{12 ,2    ,3},{0   ,0    ,0},{0   ,14  , 3},

                                 {0   ,0    ,15},{0  ,0    , 0},{0   ,0    , 0},{0   ,0    , 0},{0   ,0    , 0},

                                  {0   ,0    ,0},{0   ,0    ,0},{0   ,0    ,0}};

5.2存储符号和产生式的数组

用三个数组来存储和符号以及产生式相关的信息:endls数组存储终结符、noends数组存储非终结符、products数组存储产生式信息。

//终结符集合

stringendls[10]={"and","or","not","true","false","(",")", "i","rop","#" };

//非终结符集合

stringnoends[3]={"B","T","F"};

//产生式集合

stringproducts[10]={"B","B and T", "T","T orF","F","not F","( B )","true","false","i rop i"};

5.3状态栈和符号栈

我们用类来模拟状态栈和符号栈。

这是状态栈:

      classstatestack

{

       private:

              int*base;//栈底指针

              int*top;//栈顶指针

              intsize;//栈内元素个数

              intstacksize;//栈的大小

       public:

              statestack()

              {

                     size=0;

                     stacksize=20;

                     base=newint[stacksize];;

                     top=base;     

              }

              intgetTop()//获取栈顶的元素。

              {

                     if(base==top)

                     {

                            return-1; 

                     }

                     else

                     {

                            return*(top-1);

                     }

              } 

              boolstatePush(int elem)//元素入栈

              {

                     ++size;

                     (*top)=elem;

                     ++top;

                     returntrue;

              }

              voidstatePop(int time)//元素出栈

              {

                     for(inti=0;i<time;i++)

                     {

                            --top;

                            --size;

                     }

              }

              voidprintState()//输出栈内的所有元素

              {

                     stringstr=" ";

                     int*pre;

                     for(pre=base;pre<top;pre++)

                     {

                            if(*pre>9)

                            {

                                   charch1=(*pre/10)+48;

                                   charch2=(*pre%10)+48;

                       str+=ch1;

                                   str+=ch2;

                            }

                            else

                            {

                    char ch=*pre+48;

                                str+=ch;

                            }           

                     }

                     cout<<setw(15)<<setiosflags(ios_base::left)<<str;

              }

};

这是符号栈:

    classsymbolstack

{

       private:

              string*base;

              string*top;

              intsize;

              intstacksize;

       public:

              symbolstack()

              {

                     size=0;

                     stacksize=20;

                     base=newstring[stacksize];;

                     top=base;

              }    

              stringgetTop()//获取栈顶的元素。

              {

                     if(base==top)

                     {

                            return" "; 

                     }

                     else

                     {

                            return*(top-1);

                     }

              } 

              //元素入栈

              boolsymbolPush(string elem)

              {

                     ++size;

                     *top=elem;

                     ++top;

                     returntrue;

              }

              //元素出栈

              voidsymbolPop(int time)

              {

                     for(inti=0;i<time;i++)

                     {

                            --top;

                            --size;

                     }

              }

              //输出栈内的所有元素

              voidprintSymbol()

              {

                     stringstr=" ";

                     string*pre;

                     for(pre=base;pre<top;pre++)

                     {

                      str+=*pre;

                     }

                     cout<<setw(15)<<setiosflags(ios_base::left)<<str;

              }

};

6算法设计

6.1词法分析算法描述

6.1.1词法分析流程图

6.1.2词法分析算法

     用该函数将布尔表达式分开,并存储在vector中。

//将字符串按空格分开,并存入vector中。

       vector<string> separatestrEX(stringstr)

       {

              vector<string> vec;

              int pos=0;

              for(int i=0;i<str.size();++i)

           {  

                     if(isspace(str[i]))//如果当前字符是空格

                     {

                            vec.push_back(str.substr(pos,i-pos));//复制起始位置为pos且长度为i-pos的字符串。

                            pos=i+1;

                     }

              }

              vec.push_back(str.substr(pos,str.size()-pos));

              return vec;

       }

6.2语法分析算法代码描述

6.2.1语法分析算法流程图

6.2.2语法分析算法

用actionGoto函数对每个符号进行分析:

void actionGoto(string str,string str1)

       {                   

                  int x=state.getTop();//当前栈顶状态

                     inty=strtoInt(str);//当前将要输入的字符

                     if(action[x][y]>0&&judgeSymbol(str)&&(str!="#"))//移进

                     {

                            printfInfoEX(step,state,symbol,str1,"移入"+str);

                            state.statePush(action[x][y]);

                            symbol.symbolPush(str);  

                            ++step;

                     }

                     if(action[x][y]<0&&judgeSymbol(str))//规约

                     {

                            intz=-action[x][y];//用-action[x][y]对应的产生式规约

                            stringlenstr=products[z];//生成需要规约的产生式

                            intn=calculatenum(lenstr);//计算产生式的长度,进行规约

                            intc=chooseNoEnds(z);

                            stringch=noends[c];//生成规约后的非终结符

                            createforchief(n,lenstr,ch);//生成四元式

                            printfInfoEX(step,state,symbol,str1,"规约"+noends[c]+"->"+products[z]);

                            state.statePop(n);

                            symbol.symbolPop(n);

                            intm=state.getTop();//获取规约后的栈顶状态

                            if(gotol[m][c]>0)

                            {

                                   intg=gotol[m][c];

                                   state.statePush(g);

                                   symbol.symbolPush(ch);

                            }

                ++step;

                            actionGoto(str,str1);

                     }

                     if((action[x][y]==100)&&(str=="#"))

                     {

                            printfInfoEX(step,state,symbol,str1,"分析完成");

                     }

       }

如下是strtoInt函数的代码:

//将终结符和非终结符转换为action和gotol表中对应的列号

       intstrtoInt(string str)

       {

              if(str=="and")

                     return0;

              if(str=="or")

                     return1;

              if(str=="not")

                     return2;

              if(str=="true")

                     return3;

              if(str=="false")

                     return4;

              if(str=="(")

                     return5;

              if(str==")")

                     return6;

              if(str=="i")

                     return7;

              if(str=="rop")

                     return8;

              if(str=="#")

                     return9;

              if(str=="B")

                     return0;

              if(str=="T")

                     return1;

              if(str=="F")

                     return2;

       }

如下是judgeSymbol函数的代码:

//判断字符是终结符还是非终结符

    booljudgeSymbol(string str)

    {

           for(int i = 0;i<10; i++)

           {

                  if(endls[i]==str)

                         returntrue;  

           }

                         returnfalse;

    }

如下是chooseNoEnds函数的代码:

//根据产生式选择非终结符

       intchooseNoEnds(int num)

       {

              if(num==1||num==2)

                     return0;//选择“B”

              if(num==3||num==4)

                     return1;//选择“T”

           return 2;//选择“F”

       }

如下是calculatenum函数的代码:

       //计算字符串中元素的个数

       intcalculatenum(string str)

       {

              intnum=0;

              for(inti=0;i<str.size();++i)

              {

                     if(isgraph(str[i]))

                            continue;

                     else

                     {

                            ++num;

                     }

              }

              ++num;

       return num;

       }    

6.3中间代码的生成

该函数负责生成中间代码:

//生成四元式

       voidcreateforchief(int num,string lenstr,string ch)

       {

              vector<string>strs=separatestrEX(lenstr);

              vector<string>::iteratoriter=strs.begin();

              stringstr=" ";

       string l1="(";

              stringl2=")";

              stringl3=",";

              if(num==1)

              {

                     stringl0="=";

                     stringarg1=*iter;

                     str=l1+l0+l3+arg1+l3+"_"+l3+ch+l2;

              }

              if(num==2)

              {

                     stringop=*iter;

                     stringarg1=*(iter+1);

                     str=l1+op+l3+arg1+l3+"_"+l3+ch+l2;

              }

              if(num==3)

              {

                     stringarg1=*iter;

                     stringop=*(iter+1);

                     stringarg2=*(iter+2);

                     if(arg1=="(")

                     {

                         string l0="=";

                            str=l1+l0+l3+op+l3+"_"+l3+ch+l2;

                     }

                     else

                     {

                            str=l1+op+l3+arg1+l3+arg2+l3+ch+l2;

                     }           

}

              fors.push_back(str);

       }

       //输出四元式

       voidprintForsInfo()

       {

              printInfo("中间代码四元式为");

              vector<string>::iteratorit=fors.begin();

              for(it;it<fors.end();it++)

              {

                     cout<<*it<<endl;

              }

       }

7软件调试

在整个编译器设计过程中,遇到了很多意想不到的困难,其主要原因是对各个部分要实现的功能考虑不够周全。通过反复查找资料,以及向同学请教,才得以完成。在布尔表达式翻译器的设计过程中,在语法分析器设计过程中,程序相当复杂,需要利用到大量的编译原理,以及数据结构中的相关算法。其中在分析表的构造时遇到了非常大的困难,对输入字符串的移进和归约冲突得不到很好的处理,造成了调试的困难。经过我的努力,通过多次调试,最终构造出来分析表并调试成功。

在调试的过程中,出现了如下的问题:

l  因为函数较多,所以在编程的过程中,多次将函数名写错。

l  因为在分析和翻译的过程中,关系较为复杂,所以多次搞混关系。

l  ACTION表计算错误。

l  进栈和出栈的元素关系弄错了。

    当然,错误不止这些,但从这次课设,我觉得自己在某些方面仍有所欠缺,从现在开始,我会继续呢里,在今后的学习中,必须多编写程序,使逻辑思维和动手能力有所提高,努力学好编程。

8软件的测试方法和结果

l 输入字符串为:i rop  i  #

l 输入字符串为:true or  false  and  (  i  rop  i  )  #

9源码展示

#include<iostream>
#include<string>
#include<vector>
#include<iomanip> 
using namespace std;
                              //and	or	not	true false(	  )	  i	 rop   # 
           int action[18][10]={ { 0	, 0	 ,4	,5	, 6	 ,7	, 0	, 8	, 0	,  0},//0
				{ 9	, 0	 ,0	,0	, 0	 ,0	,-2	, 0	, 0	,100},//1
				{-2	,10	 ,0	,0	, 0	 ,0	,-2	, 0	, 0	, -2},//2
				{-4	,-4	 ,0	,0	, 0	 ,0	,-4	, 0	, 0	, -4},//3
				{ 0	, 0	 ,4	,5	, 6	 ,7	, 0	, 8	, 0	,  0},//4
				{-7	,-7	 ,0	,0	, 0	 ,0	,-7	, 0	, 0	, -7},//5
				{-8	,-8	 ,0	,0	, 0	 ,0	,-8	, 0	, 0	, -8},//6
				{ 0	, 0	 ,4	,5	, 6	 ,7	, 0	, 8	, 0	,  0},//7
				{ 0	, 0	 ,0	,0	, 0	 ,0	, 0	, 0	,13	,  0},//8
				{ 0	, 0	 ,4	,5	, 6	 ,7	, 0	, 8	, 0	,  0},//9
				{ 0	, 0	 ,4	,5	, 6	 ,7	, 0	, 8	, 0	,  0},//10
				{-5	,-5	 ,0	,0	, 0	 ,0	,-5	, 0	, 0	, -5},//11
				{ 9	, 0	 ,0	,0	, 0	 ,0	,16	, 0	, 0	,  0},//12
				{ 0	, 0	 ,0	,0	, 0	 ,0	, 0	,17	, 0	,  0},//13
				{-1	,10  ,0	,0	, 0	 ,0	,-1	, 0	, 0	, -1},//14
				{-3	,-3	 ,0	,0	, 0	 ,0	,-3	, 0	, 0	, -3},//15
				{-6	,-6	 ,0	,0	, 0	 ,0	,-6	, 0	, 0	, -6},//16
				{-9	,-9	 ,0	,0	, 0	 ,0	,-9	, 0	, 0	, -9}};//17

                               //B   T    F
           int gotol[18][3]={   {1	,2	, 3},//0
				{0	,0	, 0},//1
				{0	,0	, 0},//2
				{0	,0	, 0},//3
				{0	,0	,11},//4
				{0	,0	, 0},//5
				{0	,0	, 0},//6
				{12	,2	, 3},//7
				{0	,0	, 0},//8
				{0	,14	, 3},//9
                                {0	,0	,15},//10
				{0	,0	, 0},//11
				{0	,0	, 0},//12
                                {0	,0	, 0},//13
				{0	,0	, 0},//14
				{0	,0	, 0},//15
				{0	,0	, 0},//16
                                {0	,0	, 0}};//17

//终结符集合
string endls[10]={"and","or","not","true","false", "(",")", "i","rop","#" };
//非终结符集合
string noends[3]={"B","T","F"};
//产生式集合
string products[10]={"B","B and T", "T","T or F","F","not F","( B )","true", "false","i rop i"};
//栈类
class statestack
{	
	private:
		int *base;//栈底指针
		int *top;//栈顶指针
		int size;//栈内元素个数
		int stacksize;//栈的大小
	public:
		statestack()
		{
			size=0;
			stacksize=20;
			base=new int[stacksize];;
			top=base;	
		}
		int getTop()//获取栈顶的元素。
		{
			if(base==top)
			{
				return -1;  
			}
			else
			{
				return *(top-1);
			}
		}  
		bool statePush(int elem)//元素入栈
		{
			++size;
			(*top)=elem;
			++top;
			return true;
		}
		void statePop(int time)//元素出栈
		{
			for(int i=0;i<time;i++)
			{
				--top;
				--size;
			}
		}
		void printState()//输出栈内的所有元素
		{
			string str=" ";
			int *pre;
			for(pre=base;pre<top;pre++)
			{
				if(*pre>9)
				{
					char ch1=(*pre/10)+48;
					char ch2=(*pre%10)+48;
	                str+=ch1;
					str+=ch2;
				}
				else
				{
                    char ch=*pre+48;
				    str+=ch;
				}		
			}
			cout<<setw(15)<<setiosflags(ios_base::left)<<str;
		}
};

class symbolstack
{
	private:
		string *base;
		string *top;
		int size;
		int stacksize;
	public:
		symbolstack()
		{
			size=0;
			stacksize=20;
			base=new string[stacksize];;
			top=base;
		}	
		string getTop()//获取栈顶的元素。
		{
			if(base==top)
			{
				return " ";  
			}
			else
			{
				return *(top-1);
			}
		}  
		//元素入栈
		bool symbolPush(string elem)
		{
			++size;
			*top=elem;
			++top;
			return true;
		}
		//元素出栈
		void symbolPop(int time)
		{
			for(int i=0;i<time;i++)
			{
				--top;
				--size;
			}
		}
		//输出栈内的所有元素
		void printSymbol()
		{
			string str=" ";
			string *pre;
			for(pre=base;pre<top;pre++)
			{
		        str+=*pre;
			}
			cout<<setw(15)<<setiosflags(ios_base::left)<<str;
		}
};

class analyseLR
{
private:
	int step;
	string inputstr;//布尔表达式
	statestack state;//状态栈
	symbolstack symbol;//符号栈
	vector<string> fors;//四元式
public:
	//构造函数
	analyseLR()
	{	
		step=0;
		inputstr=" ";
		state=statestack();
		symbol=symbolstack();
	}
	//初始化两个栈
	void initstack()
	{
		state.statePush(0);
		symbol.symbolPush("#");
	}
	//这是一个输出提示函数
    void printInfo(string str)
	{
		cout<<str<<endl;
	}
	//这是两个输出提示函数的增强版
	void printInfoEX(string str1,string str2,string str3,string str4,string str5)
	{
		cout<<setw(6)<<setiosflags(ios_base::left)<<str1;
		cout<<setw(15)<<setiosflags(ios_base::left)<<str2;
		cout<<setw(15)<<setiosflags(ios_base::left)<<str3;
		cout<<setw(24)<<setiosflags(ios_base::left)<<str4;
		cout<<setw(10)<<setiosflags(ios_base::left)<<str5<<endl;
	}
	void printfInfoEX(int str1,statestack state,symbolstack symbol,string str4,string str5)
	{
		cout<<setw(5)<<setiosflags(ios_base::left)<<str1;
		state.printState();
		symbol.printSymbol();
		cout<<setw(25)<<setiosflags(ios_base::left)<<str4;
		cout<<setw(10)<<setiosflags(ios_base::left)<<str5<<endl;
	}
	//初始化界面函数
	void initstageInfo()
	{
		printInfo("布尔表达式的文法如下:");
		cout<<"(0)  B’-> B"<<endl;
		cout<<"(1)  B -> B and T"<<endl;
		cout<<"(2)  B -> T"<<endl;
		cout<<"(3)  T -> T or F"<<endl;
		cout<<"(4)  T -> F"<<endl;
		cout<<"(5)  F -> not F"<<endl;
		cout<<"(6)  F -> ( B )"<<endl;
		cout<<"(7)  F -> true"<<endl;
		cout<<"(8)  F -> false "<<endl;
		cout<<"(9)  F -> i rop i"<<endl;
	}
	//这是初始化布尔表达式的函数
	void initInputstr()
	{
		printInfo("请输入布尔表达式:");
		getline(cin,inputstr);
	}
	//将终结符和非终结符转换为action和gotol表中对应的列号
	int strtoInt(string str)
	{
		if(str=="and")
			return 0;
		if(str=="or")
			return 1;
		if(str=="not")
			return 2;
		if(str=="true")
			return 3;
		if(str=="false")
			return 4;
		if(str=="(")
			return 5;
		if(str==")")
			return 6;
		if(str=="i")
			return 7;
		if(str=="rop")
			return 8;
		if(str=="#")
			return 9;
		if(str=="B")
			return 0;
		if(str=="T")
			return 1;
		if(str=="F")
			return 2;
	}
	//判断字符是终结符还是非终结符
	bool judgeSymbol(string str)
	{
		for (int i = 0;i<10; i++)
		{
			if(endls[i]==str)
				return true;	
		}
				return false;
	}
	//根据产生式选择非终结符
	int chooseNoEnds(int num)
	{
		if(num==1||num==2)
			return 0;//选择“B”
		if(num==3||num==4)
			return 1;//选择“T”
            return 2;//选择“F”
	}
	//计算字符串中元素的个数
	int calculatenum(string str)
	{
		int num=0;
		for(int i=0;i<str.size();++i)
		{
			if(isgraph(str[i]))
				continue;
			else
			{
				++num;
			}
		}
		++num;
        return num;
	}	
	//将字符串按空格分开,并存入vector中。
	vector<string> separatestrEX(string str)
	{
		vector<string> vec;
		int pos=0;
		for(int i=0;i<str.size();++i)
   		{   
			if(isspace(str[i]))//如果当前字符是空格
			{
				vec.push_back(str.substr(pos,i-pos));//复制起始位置为pos且长度为i-pos的字符串。
				pos=i+1;
			}
		}
		vec.push_back(str.substr(pos,str.size()-pos));
		return vec;
	}
	//将vector容器中的字符串连起来
	string linkVectorstr(vector<string> &vecs,vector<string>::iterator iter)
	{
		string str=" ";
		vector<string>::iterator it;
			it=iter;
		for(it;it<vecs.end();it++)
		{
			//cout<<*it; 
			str+=*it;
		}
		return str;
	}
	//生成四元式
	void createforchief(int num,string lenstr,string ch)
	{
		vector<string> strs=separatestrEX(lenstr);
		vector<string>::iterator iter=strs.begin();
		string str=" ";
        string l1="(";
		string l2=")";
		string l3=",";
		if(num==1)
		{
			string l0="=";
			string arg1=*iter;
			str=l1+l0+l3+arg1+l3+"_"+l3+ch+l2;
		}
		if(num==2)
		{
			string op=*iter;
			string arg1=*(iter+1);
			str=l1+op+l3+arg1+l3+"_"+l3+ch+l2;
		}
		if(num==3)
		{
			string arg1=*iter;
			string op=*(iter+1);
			string arg2=*(iter+2);
			if(arg1=="(")
			{
			    string l0="=";
				str=l1+l0+l3+op+l3+"_"+l3+ch+l2;
			}
			else
			{
				
				str=l1+op+l3+arg1+l3+arg2+l3+ch+l2;
			}
		}
		fors.push_back(str);
	}
	//输出四元式
	void printForsInfo()
	{
		printInfo("中间代码四元式为");
		vector<string>::iterator it=fors.begin();
		for(it;it<fors.end();it++)
		{
			cout<<*it<<endl;
		}
	}
	void Start()//开始函数.
	{
		initstageInfo();
		initstack();//初始化两个栈
		initInputstr();
		vector<string> vec=separatestrEX(inputstr);//分开布尔表达式
		vector<string>::iterator iter=vec.begin();
		printInfo("LR分析法的过程如下");
		printInfoEX("步骤","状态栈","符号栈","输入串","操作");
		//printfInfoEX(step,state,symbol,linkVectorstr(vec,iter),"开始");
		for(iter;iter!=vec.end();++iter)//依次遍历字符
		{                                                            
			string str1=linkVectorstr(vec,iter);
			actionGoto(*iter,str1);
		}
		printForsInfo();
	}
	//LR分析函数
	void actionGoto(string str,string str1)
	{      		
		    int x=state.getTop();//当前栈顶状态
			int y=strtoInt(str);//当前将要输入的字符
			if(action[x][y]>0&&judgeSymbol(str)&&(str!="#"))//移进
			{
				printfInfoEX(step,state,symbol,str1,"移入"+str);
				state.statePush(action[x][y]);
				symbol.symbolPush(str);	
				++step;
			}
			if(action[x][y]<0&&judgeSymbol(str))//规约
			{
				int z=-action[x][y];//用-action[x][y]对应的产生式规约
				string lenstr=products[z];//生成需要规约的产生式
				int n=calculatenum(lenstr);//计算产生式的长度,进行规约
				int c=chooseNoEnds(z);
				string ch=noends[c];//生成规约后的非终结符
				createforchief(n,lenstr,ch);//生成四元式
				printfInfoEX(step,state,symbol,str1,"规约"+noends[c]+"->"+products[z]);
				state.statePop(n);
				symbol.symbolPop(n);
				int m=state.getTop();//获取规约后的栈顶状态
				if(gotol[m][c]>0)
				{
					int g=gotol[m][c];
					state.statePush(g);
					symbol.symbolPush(ch);
				}
                ++step; 
				actionGoto(str,str1);
			}
			if((action[x][y]==100)&&(str=="#"))
			{
				printfInfoEX(step,state,symbol,str1,"分析完成");
			}
	}
};                    
int main()
{ 
	analyseLR ana=analyseLR();
	ana.Start();									
	system("pause");
	return 0;                                                  
}

 

44、软件模型检查工具与混合自动机场景验证技术解析 本文深入解析了KRATOS软件模型检查工具及其在SystemC设计验证中的应用,同时介绍了高效的混合自动机场景验证算法。KRATOS基于ESST算法和并发分析机制,结合多种高级抽象技术和SMT求解能力,提供高效准确的验证功能。混合自动机场景验证则通过基于SMT的有界模型检查和本地时间语义,实现复杂嵌入式系统的高效验证。两种技术共同为软件开发与系统建模提供了强有力的工具支持。 阅读详情

相关推荐

SLR(1)语法分析器原理与语法制导翻译实战

SLR(1)是一种经典的自底向上语法分析方法,其核心在于利用FOLLOW集解决LR(0)的移进-归约冲突,实现对上下文无关文法的高效识别。它通过项目集规范族构建分析表,在保证分析能力的同时控制计算复杂度,是理解编译器前端设计的关键技术路径。语法制导翻译则将语义动作嵌入语法规则,借助属性在分析栈中传递,驱动中间代码(如三地址码)的生成,形成从源码到可执行表示的结构化映射。该技术广泛应用于教学编译器、DSL解析器及静态分析工具开发。本文以可运行的SLR(1)实现为载体,深入剖析文法拓广、FOLLOW集计算、分析

weixin_34074740的博客 451

编译原理学习笔记(二十四)~习题

题目 构造语法树的语法制导定义翻译为LR翻译器的栈操作代码。 解

海到无边天作岸 山登绝顶我为峰 2077

STM32F103嵌入式病房监测系统实战:OLED+Gizwits+Keil全栈落地

嵌入式医疗监测系统是物联网与临床工程交叉的关键场景,其核心在于资源受限MCU(如STM32F10x)如何实现高可靠性数据采集、低功耗本地交互与稳定云协同。原理上需统筹ADC多通道DMA时序控制、I²C OLED驱动抗干扰、MQTT心跳容错等底层机制;技术价值体现在以极低成本(<200元/台)替代商用设备,在真实病房达成7×24小时无故障运行;典型应用场景覆盖术后离床预警、环境参数闭环调控及生命体征异常实时告警;本文聚焦STM32F103C8T6平台,结合Keil MDK深度调优与Gizwits云精简对接,详

weixin_34389926的博客 451

编译原理——用C++模拟一个词法分析器

一、需求分析 当今时代是飞速发展的信息时代,随着计算机技术的普及与网络的广泛应用,计算机语言更显得至关重要。计算机语言是人与计算机之间传递信息的媒介。计算机系统最大特征是指令通过一种语言传达给机器。为了使电子计算机进行各种工作,就需要有一套用以编写计算机程序的数字、字符和语法规划,由这些字符和语法规则组成计算机各种指令(或各种语句)。这些就是计算机能接受的语言。一个高级语言程序的实现,必...

Jayphone17的博客 2441

编译原理中词法分析(C++)

文档内容包括题目要求,源代码和运行结果截图以及文件截图 复制即可运行 适合学习编译原理的初学者 从源程序文件中读取有效字符流并将其分析识别单词符号,转换成二元组内部表示形式输出。 主程序的说明部分为各种表格和变量安排空间(关键字和特殊符号表)。 id 和ci 数组分别存放标识符和常数;还有一些为造表填表设置的变量。 主程序的工作部分建议设计成便于调试的循环结构。每个循环处理一个单词;调用词法分析过程;输出每个单词的内部码(种别编码,属性值)。建议从文件中读取要分析的符号串。

编译原理实验1词法分析器

编译原理实验1词法分析器

C++实现的利用LR(1)分析表对赋值表达式进行语法制导翻译生成四元式及汇编代码

赋值语句的语法制导翻译 一、需要的语义过程如下: newtemp() \quad每次调用送回一个代表新临时变量的序号,可认为是送回T1、T2这样的一些临时变量 ENTRY(i) \quad用于查变量i的符号表入口地址 GEN(OP,ARG1,ARG2,RESULT) \quad产生一个四元式,并填入四元式序列表 E.PLACE \quad含义:与非终结符E相关联的语义变量(值),值为某变量的符号表入口地址或临时变量序号 二、 赋值表达式文法如下 (1)S→A(2)A→i=E(3)E→−E

qq_45424267的博客 5730

编译原理赋值语句翻译源代码

编译原理赋值语句翻译源代码,绝对没有错误!

编译原理MOOC笔记

编译原理笔记词法分析前端词法分析器的任务词法分析器的实现方法正则表达式有限状态自动机正则表达式到非确定有限状态自动机 词法分析 源程序 -> 前端 -> 中间表示 -> 后端 -> 目标程序 前端 源程序 -> 词法分析器 -> 记号 -> 语法分析器 -> 抽象语法树 -> 语义分析器 -> 中间表示 词法分析器的任务 任务:字符流到...

crabstew的博客 976

编译原理课程设计-布尔表达式的翻译器

该文件包含编译原理课程布尔表达式翻译器的源程序以及撰写的报告。非常完整。

IF-ELSE条件语句的翻译程序设计(递归下降法、简单优先法、LR方法、LL(1)法、输出四元式)

IF-ELSE条件语句的翻译程序设计(递归下降法、简单优先法、LR方法、LL(1)法、输出四元式、输出三地址表示)

编译原理之计算题汇总

文章目录第二章 高级语言及其语法描述上下文无关文法例2.1 教材P30例2.2 教材P30例2.3 教材P30最左推导、最右推导最左推导最右推导第三章 词法分析器从正规式构造有限自动机例3.5 教材P56NFA确定化例3.3 教材P50DFA的化简例3.6 教材P57第四章 语法分析-自自上而下分析消除文法的左递归例4.2 教材P69例4.3 教材P70构造FIRST集和FOLLOW集例4.7 教材P79构造预测分析表例4.8 教材P79利用预测分析表进行预测分析例4.6 教材P78第五章 语法分析-自下而

qq_45347768的博客 3008

开源代码分享(29)-基于拉丁超立方抽样的风光场景生成和削减

作为分层抽样方法的一 种,拉丁超立方抽样具有良好的抽样精度和效率[14]。本文使用多场景方法来描述可再生能源(风电、光伏)的不确定性。以风电功率为例,首先假定风电功率服从正态分布 N(μ, δ 2 ),μ 为预测值的期望值,δ 为其波动的百分比。接着,采用拉丁超立方抽样[21]生成大量服从概率分布约束的风电出力场景,并采用考虑 Kantorovich 距离[22]的场景削减技术处理该场景,进行场景削减。最后,导出具有相应概率的削减之后的场景。

配电网和matlab的博客 923

编译原理---第六章、第七章

第六章—属性文法和语法制导翻译一、属性文法1、属性文法: 是在上下文无关文法的基础上为每个文法符号(终结符或非终结符)配备若干个相关的“值”(称为属性)。2、属性:代表与文法符号相关的信息,和变量一样,可以进行计算和传递。3、属性的分类:综合属性、继承属性4、语义规则:在一个属性文法中,对应于每个产生式A都有一套与之相关联的语义规则,每条语义规则的形式为:b:=f(c1,c2,…,ck)   ...

xinqi_789的博客 3086

C++中const和指针*的组合问题

今天在复习> 章节7.3的时候想到以前做的一个题,const和指针运算符*的若干种组合的合法性和意义问题,有点混淆,所以写了一个测试代码来验证一下,简单明了,一目了然。如果有什么遗漏的话欢迎指出。 首先是在Ubuntu14.04.1下用gcc 4.8.4编译运行的结果,编译器报错信息都附加在对应语句后面的注释里 /* * Note : Test for the combinations of

theColdOne的专栏 1080

UDS诊断ISO14229新手入门篇

这个命令的格式稍微复杂一点。sub-function = 0x06 用于读取某个 DTC 及其相关的环境数据,此时 parameter 为 4 个 byte,前三个 byte 用于标识我们要读取的 DTC,第四个 byte 用于标识要读取的环境数据的范围,UDS 规定使用 FF 来表示读取所有的环境数据,各厂家可以要根据自己的需求定义其他的值来代表要读取的环境数据的范围。环境数据包括 DTC 状态,优先级,发生次数,老化计数器,时间戳,里程等,厂家还可以根据自己的需求定义一些此 DTC 产生时的测量数据。

weixin_45387165的博客 1973

《计算机系统设计原理》,本科计算机类《编译器设计原理》

原标题:本科计算机类《编译器设计原理》 美国哥伦比亚大学的Alfred V. Aho教授在其经典名著《编译器:原理、技术与工具》的前言部分写道“编写编译器的原理和技术具有十分普遍的意义,以至于在每个计算机科学家的研究生涯中,本书中的原理和技术都会反复被用到”。对于学习“编译原理”这门课的学生来说,除了可以通过课程学习掌握一些具体的基本理论、技术和算法之外,更重要的是能培养学生具备计算机学科通用的问...

weixin_29405101的博客 220

一文搞懂【Linux 搭建 Dread Hunger 服务器】附本体及Docker部署集群方案

看直播发现了五花八门的开服器和版本,一时兴起按官方文档进行了搭建尝试,所以我的版本基于官方Stream2024.01.10更新的版本,也就是停服时的玩法,应该可以根据mod和补丁魔改成更那些开服器一样的版本,本文不做谈论,注重服务器搭建,毕竟8个人不可能在一个局域网里乱象:首先,我看了大量教程视频,一类是开服器的推广,另一类自建的基本采用Windows搭建,我觉得最离谱的是大部分教程都会教你买一台远程Windows虚拟机???

LHmine的博客 3983

第六章第七章总结

第六章:属性文法和语法制导翻译1.属性文法:是在上下文无关文法的基础上,为每个文法符号(终结符或非终结符)配备若干个相关的“值”(称为属性)。属性代表与文法符号相关的信息,和变量一样,可以进行计算和传递。又可以分类为综合属性和继承属性。2,语义规则:对于文法的每一个产生式配备一组属性的计算规则。3.语义规则所描述的工作:属性计算,静态语义查询,符号表操作,代码生成。4.基于属性文法的处理方法:(1...

qq_37278309的博客 1201

数据架构师必看:大数据时代的架构演进与实践

数据架构是企业数据资产的“骨架”——它决定了数据能多快被处理、多准被分析、多安全被存储。本文将聚焦从传统架构到大数据架构的关键转折点,覆盖技术选型、典型场景、落地挑战三大核心命题,帮助读者建立“演进思维”而非“固定思维”。本文将按“历史演进→核心概念→技术原理→实战案例→趋势展望”的逻辑展开,用“超市仓库升级”贯穿始终,让抽象的技术概念具象化。传统数据仓库:精但小,适合结构化、批量分析。大数据架构:大但乱,适合全类型、海量数据存储。流批一体:解决实时+批量的效率问题。湖仓一体。

AI Agent Harness Engineering 913

信息传输仿真:卫星通信系统仿真_(12).卫星通信系统仿真软件介绍

卫星通信系统仿真软件是进行卫星通信系统设计和性能优化的重要工具。通过这些软件,用户可以模拟和分析各种通信场景,验证不同的通信协议和算法,优化系统参数和配置。本节介绍了 MATLAB Simulink、NS-3、OPNET 和 SystemVue 的基本功能、特点和配置方法,希望对读者在选择和使用仿真软件时提供参考。在实际应用中,建议根据项目需求和团队能力,综合考虑选择合适的仿真软件。

2401_87715305的博客 1278

第六、七章

语义分析及翻译属性文法与语法制导翻译      这两章主要介绍语义分析及翻译问题,都是编译过程的阶段。      语义分析是对经语法分析器处理过后的在结构上正确的源程序进行上下文有关性质的审查,是编译程序最实质的过程。语义描述和语义处理最常用的方法是属性文法与语法制导翻译方法,也是本章主要介绍内容。       属性文法是在上下文无关文法的基础上为每个文法符号(终结符或非终结符)配备若干个相关的“...

qq_35482060的博客 322

OCR文字识别领域经典论文总结

本篇将介绍文字识别经典论文,内容包括文字检测、文字识别、端到端识别等方法,具体将分别对论文算法简介、思路、代码等几个部分展开介绍。目前各部分只举例经典论文,算法没有全部写完,后续会将在此部分基础上更新更多论文综述及代码实战部分。.................................

专注大数据与人工智能技术分享,欢迎私信加群互相学习! 1万+

实验一.词法分析实验

实验一、词法分析实验 商业软件工程专业 张煌 201506110130 一、 实验目的 从左至右地对源程序进行扫描,按照语言的词法规则识别各类单词,并产生以{种别码,属性}为格式的结果。 二、 实验内容和要求 输入:源程序字符串 输出:二元组(种别,单词符号本身) 三、 实验方法、步骤及结果测试 1.源程序名:...

weixin_30588675的博客 131

NSIS教程(6): 使用第三方插件

NSIS内置了很多指令,这些指令可以满足我们基本需求,但难免会遇到NSIS没有内置的功能,如进程操作,后台运行(即多线程),7z压缩等等,这个时候我们就需要借助第三方插件来满足我们所需要的功能了。 一、插件获取 NSIS官方收录插件的网址是:http://nsis.sourceforge.net/Category:Plugins,我们可以在这个网站上查找和下载我们需要的插件,该网站上针对每

while(1) { smile(); } 9万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

实验一、词法分析程序实验

实验一、词法分析实验 专业:商业软件工程3班 姓名:张德标 学号:201506110200 一、 实验目的 编制一个词法分析程序 二、 实验内容和要求 内容:对字符串表示的源程序,从左到右进行扫描和分解,根据词法规则,识别出一个一个具有独立意义的单词符号以供语法分析只用,发现语法错误,则返回出错信息 要求:输入源程序字符串,输出二元组(种别,单词...

weixin_33700350的博客 502

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

「已注销」
博客等级 码龄15年 7粉丝 1原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值