我们可以以下面的文法为例子进行算符优先分析:
E→E+T|T
T→T*F|F
F→(E)|i
FIRSTVT和LASTVT的构建
首先我们要通过文法规则来产生相应的FIRSTVT和LASTVT集,具体的构建规则如下:
FIRSTVT:
若出现 E→a... 或 E→Aa 的情况,则 a∈FIRSTVT【E】,即产生式右部的第一个终结符属于左部非终结符的FIRSTVT集
若出现 E→A... 的情况,则 FIRSTVT【A】∈FIRSTVT【E】,即产生式右部开头若是非终结符的情况下,该终结符的FIRSTVT属于左部非终结符的FIRSTVT集
LASTVT:
若出现 E→...a 或 E→...aA 的情况,则 a∈LASTVT【E】,即产生式右部倒数第一个终结符属于左部非终结符的FIRSTVT集
若出现 E→...A 的情况,则 LASTVT【A】∈LASTVT【E】,集产生式右部尾部若是非终结符的情况下,该终结符的LASTVT属于左部非终结符的LASTVT集
通过以上方法得到的FIRSTVT和LASTVT集如下:
FIRSTVT:
FIRSTVT【E】={ ( , i , + , * }
FIRSTVT【T】 = { ( , i , * }
FIRSTVT【F】 = { ( , i }
LASTVT:
LASTVT【E】 = { ) , i , + , * }
LASTVT【T】 = { ) , i , * }
LASTVT【F】 = { ) , i }
算符优先关系表的构造
得到了文法的FIRSTVT和LASTVT集以后,我们需要通过它来得到算符优先关系表,具体构造方法如下:
若出现 E→...ab... 或者 E→....aAb... 的情况:a = b
若出现 E→...aA.. 且 b∈FIRSTVT【A】的情况:a < b
若出现 E→...Ab...且 a∈LASTVT【A】的情况:a > b
用此方法构造的算符优先分析表如下所示:
i | + | * | ( | ) | # | |
i | > | > | > | > | ||
+ | < | > | < | < | > | > |
* | < | > | > | < | > | > |
( | < | < | < | < | = | |
) | > | > | > | > | ||
# | < | < | < | < | = |
注:在讨论#与其他终结符的优先级时,可以添加E→#E#来完成
算符优先分析
算符优先分析采用的是移进-归约法,取符号栈中最左素短语的终结符,并将其与输入串头的元素进行优先级比较,若优先关系为 ">" ,则进行归约,若为 "<" 或 "=" 则将输入串头元素压入符号栈。
我们以i+i*i为例来进行算符优先分析:
符号栈 | 输入串 | 动作# |
# | i+i*i# | 移进 |
#i | +i*i# | 归约 |
#E | +i*i# | 移进 |
#E+ | i*i# | 移进 |
#E+i | *i# | 归约 |
#E+E | *i# | 移进 |
#E+E* | i# | 移进 |
#E+E*i | # | 归约 |
#E+E*E | # | 归约 |
#E+E | # | 归约 |
#E | # | 结束 |
注:算符优先分析中不关心非终结符的优先关系,因此我们在归约的时候可以不用考虑字符串被归约到了哪个非终结符。
参考代码
用c#进行实现,代码冗余极多,效率很低,泛用性不足,各种考虑不全面的情况也很多,大家权当做个参考。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 算符优先分析 8 { 9 10 class Program 11 { 12 /*-------------------------------变量声明---------------------------------------------------------------------------------------*/ 13 static string effectValue = "i+*()#"; //有效的字符集合 14 static List<string> grammarList = new List<string>(); //文法列表 15 static Dictionary<string, List<string>> grammarDic = new Dictionary<string, List<string>>(); //文法字典 16 static Dictionary<string, List<string>>.KeyCollection vertex; //非终结符集合 17 static Dictionary<string, string> firstVT = new Dictionary<string, string>(); //firstVT集 18 static Dictionary<string, string> lastVT = new Dictionary<string, string>(); //lastVT集 19 static char[,] priorityTable = new char[7,7]; //算符优先关系表 20 static string message; //要分析的字符串 21 static MyStack stack = new MyStack(); 22 23 24 /*----------------------------主函数--------------------------------------------------------------------------------------------*/ 25 static void Main(string[] args) 26 { 27 inputGrammar(); //获得文法字符串 28 getVT(); //获得firstVT和lastVT 29 printVT(); //输出firstVT和lastVT 30 getPriorityTable();//得到优先关系表 31 printPriorityTable();//打印优先关系表 32 inputMessage(); //获得要分析的字符串 33 34 //判断字符串是否符合要求 35 if (judgeMessage()) 36 //进行算符优先分析 37 if (analyze()) 38 Console.WriteLine("分析成功!该句子符合算符优先。"); 39 else Console.WriteLine("分析失败!该句子不符合算符优先。"); 40 } 41 42 /*---------------------------------------输入数据---------------------------------------------------------------------*/ 43 static void inputGrammar() 44 { 45 Console.WriteLine("该系统支持的终结符有:i,+,*,(,),请勿输入其他终结符!"); 46 Console.WriteLine("请输入要分析的文法:(在单独一行输入#结束输入)"); 47 Console.WriteLine("如:E→E+T|T\nT→T*F|F\nF→(E)|i\n#\n"); 48 while (true) 49 { 50 string str = Console.ReadLine(); 51 if (str.Equals("#")) 52 break;