编译原理(七) 算符优先分析法(构造算符优先关系表算法及C++实现)
最后更新于:2022-04-01 14:15:25
## 概念简述
移动归约分析法:自底向上的语法分析方法,也称为***移动归约分析法***。
- 最易于实现的一种移动归约分析方法,叫做***算符优先分析法***,
- 而更一般的移动归约分析方法叫做***LR分析法***,LR分析法可以用作许多自动的语法分析器的生成器。
短语:文法G[S],αβδ是文法G的一个句型,S=>*αAδ且A=>+β则称β是句型αβδ相对于非终结符A的短语。
直接短语:若有A ⇒+β则称β是句型αβδ相对于该规则A→β的直接短语。
句柄:一个句型的最左直接短语称为该句型的句柄。
**其实作为一个常年和树打交道的acmer来说,我觉得下面这种定义方法更容易理解….**
短语:一棵子树的所有叶子自左至右排列起来形成一个相对于子树根的短语。
直接短语:仅有父子两代的一棵子树,它的所有叶子自左至右排列起来所形成的符号串。
句柄:一个句型的分析树中最左那棵只有父子两代的子树的所有叶子的自左至右排列。
算符文法的定义:
- 所有产生式的右部都不是ε或两个相邻的非终结符
- 设有一个文法G,如果G中没有形如A→…BC…的产生式,其中B和C为非终结符,则称G为算符文法(Operator Grammar)也称OG文法.
算符优先文法的特点:
- 一旦我们构造了算符优先语法分析器,就可以忽略原来的文法,栈中的非终结符仅仅作为与这些非终结符相关的属性的占位符
- 难以处理像减号这样有不同优先级的符号
- 由于分析的语言的文法和算符优先语法分析器本身的关系不是很紧密,所以不能肯定语法分析器接受的就是所期望的语言
## 算法优先关系构造算法
### 一、首先对于优先关系进行如下定义:
- a的优先级低于b
a < b: 文法中有形如A→…aB…的产生式而B+b…或B+Cb…
- a的优先级等于b
a = b: 文法中有形如A→…ab…或者A→…aBb…的产生式
- a的优先级高于b
a > b: 文法中有形如A…Bb…的产生式,而B+…a或B+…aC
- 算符的优先关系是有序的
- 如果a > b,不能推出b < a
- 如果a > b,有可能b > a
- 如果a > b, b > c,不一定a > c
根据这个大小关系的定义,我们知道为了确定两个终止符的优先关系,我们需要知道它的在所有的产生式中和前后非终止符的关系,那么我们做一个如(二)预处理:
### 二、定义并构造FIRSTVT和LASTVT两个集合
FIRSTVT(P)={a|P⇒+a⋯或P⇒+Qa⋯}
LASTVT(P)={a|P⇒+⋯a或P⇒+⋯aQ}
FIRSTVT(P)直接根据定义递归的构造即可:
-
a) 若有产生式 P→a••• 或 p→Qa•••
则 a∈FIRSTVT(P)
-
b) 若有产生式 P→Q••• ,
若 a∈FIRSTVT(Q)
则 a∈FIRSTVT(P)
LASTVT(P)直接根据定义递归的构造即可:
-
a) 若有产生式 P→•••a 或 p→•••aQ
则 a∈LASTVT(P)
-
b) 若有产生式 P→•••Q ,
若 a∈LASTVT(Q)
则 a∈LASTVT(P)
代码实现见代码部分的make_first和make_last函数,是两个简单的递归实现。
### 三、利用FIRSTVT和LASTVT集合构造算法优先关系表
~~~
FOR 每个产生式 P->X1 X2 ……Xn
DO FOR i:=1 TO n-1 DO
IF X[i]和X[i+1]均为终结符
THEN 置 X[i]=X[i+1]
IF X[i]和X[i+2]均为终结符,X[i+1]为非终结符,i≤n-2,
THEN 置 X[i]=X[i+2]
IF X[i]为终结符, 但X[i+1]为非终结符
THEN FOR FIRSTVT(X[i+1])中的每个a
DO 置 X[i]<a
IF Xi为非终结符, 但X i+1 为终结符
THEN FOR LASTVT(X i )中的每个a
DO 置 a>X[i+1]
~~~
## C++代码实现
~~~
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <string>
#include <cstdlib>
#include <cctype>
#define MAX 507
using namespace std;
class WF
{
public:
string left;
vector<string> right;
WF ( const string& str )
{
left = str;
}
void insert ( char str[] )
{
right.push_back(str);
}
void print ( )
{
printf ( "%s->%s" , left.c_str() , right[0].c_str() );
for ( int i = 1 ; i < right.size() ; i++ )
printf ( "|%s" , right[i].c_str() );
puts("");
}
};
char relation[MAX][MAX];
vector<char> VT;
vector<WF> VN_set;
map<string,int> VN_dic;
set<char> first[MAX];
set<char> last[MAX];
int used[MAX];
int vis[MAX];
void dfs ( int x )
{
if ( vis[x] ) return;
vis[x] = 1;
string& left = VN_set[x].left;
for ( int i = 0 ; i < VN_set[x].right.size() ; i++ )
{
string& str = VN_set[x].right[i];
if ( isupper(str[0]) )
{
int y = VN_dic[str.substr(0,1)]-1;
if ( str.length() > 1 && !isupper(str[1] ) )
first[x].insert ( str[1] );
dfs ( y );
set<char>::iterator it = first[y].begin();
for ( ; it!= first[y].end() ; it++ )
first[x].insert ( *it );
}
else
first[x].insert ( str[0] );
}
}
void make_first ( )
{
memset ( vis , 0 , sizeof ( vis ) );
for ( int i = 0 ; i < VN_set.size() ; i++ )
if ( vis[i] ) continue;
else dfs ( i );
#define DEBUG
#ifdef DEBUG
puts("------------FIRSTVT集-------------------");
for ( int i = 0 ; i < VN_set.size() ; i++ )
{
printf ( "%s : " , VN_set[i].left.c_str() );
set<char>::iterator it = first[i].begin();
for ( ; it!= first[i].end() ; it++ )
printf ( "%c " , *it );
puts ("" );
}
#endif
}
void dfs1 ( int x )
{
if ( vis[x] ) return;
vis[x] = 1;
string& left = VN_set[x].left;
for ( int i = 0 ; i < VN_set[x].right.size() ; i++ )
{
string& str = VN_set[x].right[i];
int n = str.length() -1;
if ( isupper(str[n] ) )
{
int y = VN_dic[str.substr(n,1)]-1;
if ( str.length() > 1 && !isupper(str[n-1]) )
last[x].insert ( str[1] );
dfs1 ( y );
set<char>::iterator it = last[y].begin();
for ( ; it != last[y].end() ; it++ )
last[x].insert ( *it );
}
else
last[x].insert ( str[n] );
}
}
void make_last ( )
{
memset ( vis , 0 , sizeof ( vis ) );
for ( int i = 0 ; i < VN_set.size() ; i++ )
if ( vis[i] ) continue;
else dfs1 ( i );
#define DEBUG
#ifdef DEBUG
puts("--------------LASTVT集---------------------");
for ( int i = 0 ; i < VN_set.size() ; i++ )
{
printf ( "%s : " , VN_set[i].left.c_str() );
set<char>::iterator it = last[i].begin();
for ( ; it!= last[i].end() ; it++ )
printf ( "%c " , *it );
puts ("" );
}
#endif
}
void make_table ( )
{
for ( int i = 0 ; i < MAX ; i++ )
for ( int j = 0 ; j < MAX ; j++ )
relation[i][j] = ' ';
for ( int i = 0 ; i < VN_set.size() ; i++ )
for ( int j = 0 ; j < VN_set[i].right.size() ; j++ )
{
string& str = VN_set[i].right[j];
for ( int k = 0 ; k < str.length()-1 ; k++ )
{
if ( !isupper(str[k]) && !isupper(str[k+1]) )
relation[str[k]][str[k+1]] = '=';
if ( !isupper(str[k]) && isupper(str[k+1]) )
{
int x = VN_dic[str.substr(k+1,1)]-1;
set<char>::iterator it = first[x].begin();
for ( ; it != first[x].end() ; it++ )
relation[str[k]][*it] = '<';
}
if ( isupper(str[k]) && !isupper(str[k+1]) )
{
int x = VN_dic[str.substr(k,1)]-1;
set<char>::iterator it = last[x].begin();
for ( ; it != last[x].end() ; it++ )
relation[*it][str[k+1]] = '>';
}
if ( k > str.length()-2 ) continue;
if ( !isupper(str[k]) && !isupper(str[k+2]) && isupper(str[k+1]) )
relation[str[k]][str[k+2]] = '=';
}
}
#define DEBUG
#ifdef DEBUG
for ( int i = 0 ; i < VT.size()*5 ; i++ )
printf ("-");
printf ( "算符优先关系表" );
for ( int i = 0 ; i < VT.size()*5 ; i++ )
printf ( "-" );
puts("");
printf ( "|%8s|" , "" );
for ( int i = 0 ; i < VT.size() ; i++ )
printf ( "%5c%5s" , VT[i] , "|" );
puts ("");
for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
printf ("-");
puts("");
for ( int i = 0 ; i < VT.size() ; i++ )
{
printf ( "|%4c%5s" , VT[i] , "|");
for ( int j = 0 ; j < VT.size() ; j++ )
printf ( "%5c%5s" , relation[VT[i]][VT[j]] , "|" );
puts ("");
for ( int i = 0 ; i < (VT.size()+1)*10 ; i++ )
printf ("-");
puts("");
}
#endif
}
int main ( )
{
int n;
char s[MAX];
while ( ~scanf ( "%d" , &n ) )
{
memset ( used , 0 , sizeof ( used ) );
for ( int i = 0 ; i < n ; i++ )
{
scanf ( "%s" , s );
int len = strlen(s),j;
for ( j = 0 ; j < len ; j++ )
if ( s[j] == '-' )
break;
s[j] = 0;
if ( !VN_dic[s] )
{
VN_set.push_back ( WF(s) );
VN_dic[s] = VN_set.size();
}
int x = VN_dic[s]-1;
VN_set[x].insert ( s+j+2 );
for ( int k = 0 ; k < j; k++ )
if ( !isupper(s[k] ) )
{
if ( used[s[k]] ) continue;
used[s[k]] = 1;
VT.push_back ( s[k] );
}
for ( int k = j+2 ; k < len; k++ )
if ( !isupper(s[k] ) )
{
if ( used[s[k]] ) continue;
VT.push_back ( s[k] );
used[s[k]] = VT.size();
}
}
#define DEBUG
#ifdef DEBUG
puts ("************VT集*******************");
for ( int i = 0 ; i < VT.size() ; i++ )
printf ( "%c " , VT[i] );
puts ("");
puts("*************产生式*****************");
for ( int i = 0 ; i < VN_set.size() ; i++ )
VN_set[i].print();
puts("************************************");
#endif
make_first();
make_last();
make_table();
}
}
~~~
Input:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_57171fab7ce07.jpg "")
Output:
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-20_57171fab90ed2.jpg "")