一个算符文法分析的实现

原创 2007年10月13日 15:05:00

算符优先分析法程序模拟

作者:李朝中

摘要:大家在学编译原理文法分析时都会先学习弱文法和算符文法,然后是LR系列的文法,算符文法做为一种简单易于理解的文法,可以帮助大家学习深刻复杂的文法。本文介绍算符分析程序实现方法,希望能帮助大家理解算符分析的实际分析流程。

关键词:算符分析、VC++编译原理

一、简介

算符优先分析法的关键是比较两个相继出现的终结符号的优先级而决定应采取的动作。要完成算符间的优先级比较,就要先定义各种可能出相继出现的运算符的优先级,并将其表示成矩阵形式,在分析过程中通过查询矩阵元素而得算符间的优先关系。对于任何两个相继出现的终结符号ab具有形式:“…ab…” “…aQb…”Q为非终结符,定义ab间的如下三种关系为:
      1
ab  a的优先级低于b
        2
a=b   a的优先级等于
b
        3
a>b   a的优先级高于
b
      
如果ab在任何情况下不可能相继出现,则a,b之间无关系。i½E½E*E½E-E½E+E 已知文法G[E]其终结符号的关系可用一个矩阵表示如下,称其为优先表。有了优先表我们就可根据算符的优先关系对符号串进行归约,从而求出其运算结果。

二、程序实现

下面来一起来计论一下算符文法分析的程序实现。所分析的文法是E->E*E|E/E|E-E|E+E|(E)|i分析表的建立过程大家可以自己做。大部教材上都有详细的说明。我们所要达到目的是写一个指定的表达式列出分析的过程并最终分析出它是否合法。

     第一步:在VC++6.0中新建一个对话框工程命名为SyntaxAnalyse

     第二步:将取消按钮改成退出,确定的ID改为ID_ANALYSE,名字改为分析

     第三步:添加一个文本框,一个LIST控件分别对应变量m_edit,m_list。注意LIST控件设置为REPORT模式,无排序。

     第四步:要为产生式建立一个结构体把它放在stdafx.h,这个结构体存储产生式的左部和右部,我们在具体分析时会用到它,具体如下:

typedef struct _tagProductFormula
{
      char m_left;
      char m_right[256];
}Formula,*PFormula;

第五步:在SyntaxAnalyseDlg.h中添加变量及声名函数其都为私有成员。下面列出几较为重要的变量和函数

 void Analyse(CString param);//分析主函数
 int CmpPRI(char param1,char param2);//
分析时确定符号的优先级

 bool TestISVT(CString string);
 int PRITable[8][8];
 Formula FormulaTable[6];

     第六步:在OnInitDialog()函数中加入一个对m_list变量的初始化,下面的代码是用来设置控件的样式和初始化我们分析时所要用的到的数据。

 m_list.SetExtendedStyle(LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_TRACKSELECT);
 ///
初始化数据表为分析方法做准备

 InitList();//
初始化list控件
 InitTable();//
初始化数据表

第七步:我们来实现在实际分析过程中需要的其他操作。其作用与上面第五步已经说明,下面是具体的实现码。
//测试串是否在规定的字符集中
bool CSyntaxAnalyseDlg::TestISVT(CString string)
{
 int iLen=string.GetLength()-1;
 char temp;
 while(iLen>-1)
 {
  temp=string.GetAt(iLen);
  if(GetItem(temp)==8)
   return false;
 }
 return true;
 
}
//
比较优先级
int CSyntaxAnalyseDlg::CmpPRI(char param1, char param2)
{
 int pri_1=GetItem(param1);
 int pri_2=GetItem(param2);
 if(pri_1==8||pri_2==8)
 {
  return 3;
 }
 return PRITable[pri_1][pri_2];
}
   
第八步:我们前已经做很多的初化和准备工作下面的代码,就是我们的具体分析过程实现。
//语法分析
void CSyntaxAnalyseDlg::Analyse(CString param)
{
 int k=0,p=0,j=0,iLen=param.GetLength(),PRI,l=0;
 char temp_1,temp_2;
 InserteList(-1,m_stack,3," ",param,"
初始");
 while(iLen>p)
 {
  temp_2=param.GetAt(p);
goto1: temp_1=m_stack.GetAt(k);
     if(GetItem(temp_1)!=8)
   j=k;
  else
   j=k-1;
        temp_1=m_stack.GetAt(j);
  PRI=CmpPRI(temp_1,temp_2);

  if(PRI==1)
  {
   while(1)
   {
    //MessageBox("temp_2=param.GetAt(p);");
    temp_1=m_stack.GetAt(j);
    if(GetItem(m_stack.GetAt(j-1))!=8)
    {
     j=j-1;
    }
    else
    {
     j=j-2;
    }//end if(GetItem(m_stack.GetAt(j-1))!=8)
    PRI=CmpPRI(m_stack.GetAt(j),temp_1);
    if(PRI==2)
     break;
   }
   ///
完成一次归约/////////////////////////////////////////////
   j++;
   CString str1,str2;
   l=0;
   while(l<6)
   {
    str1.Format("%s",m_stack.Mid(j,k-j+1));
    str2.Format("%s",FormulaTable[l].m_right);
    if(str1==str2)
    {
     m_stack.Delete(j,k-j+1);
     m_stack.Insert(j,FormulaTable[l].m_left);
     k=j;
     InserteList(p,m_stack,1,temp_2,param.Right(iLen-p-1),"
归约
");
     goto goto1;
    }//end if(!strcmp(m_stack.Mid(j,k-j),FormulaTable[l].m_right))
    l++;
   }
      ////////////////////////////////////////////////////////////
  }
  else
  {
   if(PRI==2)
   {
    //
如果优先低就移进栈

    k++;
    m_stack.Insert( k, temp_2 );
    //temp_2=(char)p+48;
    InserteList(p,m_stack,2,temp_2,param.Right(iLen-p-1),"
移进");
    p++;
   }
   else
   {
    if(PRI==0)
    {
     PRI=CmpPRI(m_stack.GetAt(j),'#');
     if(PRI==0)
     {
      InserteList(p,m_stack,0,temp_2,param.Right(iLen-p-1),"
接受
");
      break;
     }
     else
     {
      k++;
      m_stack.Insert( k, temp_2 );
      InserteList(p,m_stack,2,temp_2,param.Right(iLen-p-1),"
移进
");
      p++;
     }
    }
    else
    {
     InserteList(p,m_stack,3,temp_2,param.Right(iLen-p-1),"
出错
");
     MessageBox("
语法出错误
!!!!");
     break;
    }//end if(PRI==0)
   }//end if(PRI==2)
  }//end if(PRI==1)
  
 }

}

最后我们在分析按钮单击事件中实现下面代码:

CString token;
UpdateDate(true);
m_stack=”#”;
token.Format(“%s#”,m_edit);
m_list.DeleteAllItems();
nIndex=0;
Aanalyse(token);

编译运行出如下图:

三、结束语

上面我们一起讨论算符文法分析程序的实现的过程,希望能给大家学编译原理这门课带来一些帮助。

[编译原理]算符优先文法分析与实现

在算术表达式中,运算的优先顺序主要采用四则运算的口诀:先乘除后加减,从左算到右,这个口诀确定了乘除运算优先于加减运算,同级运算一律从左到右,即代数中的“左结合”法则。如果计算的每一步做一个运算,那么四...
  • u012848631
  • u012848631
  • 2015年06月16日 14:33
  • 5410

简单算符优先文法分析程序(编译原理)

题目                       实现算符优先文法分析程序;完成对以下表达式文法的分析程序。        G[E]:             E->E+T             E...
  • khwkhwkhw
  • khwkhwkhw
  • 2015年11月28日 23:50
  • 3778

编译原理(八) 算符优先分析法(分析过程的算法和C++实现)

前情提要算符优先分析法(构造算法优先关系表)算法描述算符优先关系主要用于界定右句型的句柄: 标记句柄的右端。 发现句柄的过程: 从左端开始扫描串,直到遇到第一个>为止。 向左扫描,跳过所有的=,直...
  • qq_24451605
  • qq_24451605
  • 2015年11月30日 10:49
  • 3057

LL(1)文法预测分析法 实现及演示

  • 2009年11月06日 15:11
  • 520KB
  • 下载

[编译原理]算符优先文法分析与实现

在算术表达式中,运算的优先顺序主要采用四则运算的口诀:先乘除后加减,从左算到右,这个口诀确定了乘除运算优先于加减运算,同级运算一律从左到右,即代数中的“左结合”法则。如果计算的每一步做一个运算,那么四...
  • u012848631
  • u012848631
  • 2015年06月16日 14:33
  • 5410

编译原理(九) LR(0)文法分析法(算法描述和C++代码实现)

概念梳理最左推导:每一步替换最左边的非终结符 最右推导:每一步替换最右边的非终结符,最右推导称为规范推导 短语:令G是一个文法,S是文法的开始符号,假定αβδ是文法G的一个句型,如果有 S⇒∗αA...
  • qq_24451605
  • qq_24451605
  • 2015年12月02日 19:58
  • 5563

编译原理之算术表达式文法的预测分析算法c实现

已知表达式文法:        E
  • u014771617
  • u014771617
  • 2014年10月11日 12:36
  • 1319

编译原理(十) SLR文法分析法(算法原理和C++实现)

前情提要因为SLR文法分析法就是对LR(0)的一种优化,它提供了一种解决冲突的方法,所以很多之前在LR(0)提及的东西,在此只提供一个引用。 LR(0)文法分析法算法描述SLR文法构造分析表的主要思...
  • qq_24451605
  • qq_24451605
  • 2015年12月04日 09:37
  • 3234

编译原理(九) LR(0)文法分析法(算法描述和C++代码实现)

概念梳理 最左推导:每一步替换最左边的非终结符  最右推导:每一步替换最右边的非终结符,最右推导称为规范推导  短语:令G是一个文法,S是文法的开始符号,假定αβδ是文法G的一个句型,如果有...
  • github_36601823
  • github_36601823
  • 2017年07月02日 09:25
  • 339

基于文法分析的简单计算器实现

《Programming: Principles and Practice Using C++》读书笔记(二) 程序设计的过程: 分析 设计-实现-测试 得到程序原型 再设计-再实现-再测试 几个轮...
  • leowww
  • leowww
  • 2014年03月12日 19:07
  • 908
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:一个算符文法分析的实现
举报原因:
原因补充:

(最多只允许输入30个字)