算符优先分析及其简单代码实现

我们可以以下面的文法为例子进行算符优先分析:

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;
 53                 else grammarList.Add(str);
 54             }
 55             //将文法转存为文法字典保存
 56             foreach (string str in grammarList)
 57             {
 58                 List<string> l1 = new List<string>();
 59                 string[] s1 = str.Split('');
 60                 string[] s2 = s1[1].Split('|');
 61                 foreach (string s in s2)
 62                     l1.Add(s);
 63                 grammarDic.Add(s1[0], l1);
 64             }
 65             vertex = grammarDic.Keys;   //将文法字典的key值给vector
 66         }
 67 
 68         /*---------------------------------------得到firstVT和lastVT----------------------------------------------------------*/
 69         static void getVT()
 70         {
 71             //第一遍遍历,将第一个非终结符和在串头的终结符加入firstVT
 72             foreach (string v in vertex)
 73             {
 74                 List<string> l = grammarDic[v];
 75                 foreach (string s in l)
 76                 {
 77                     getFirstVT(s, v);
 78                     getLastVT(s, v);
 79                 }
 80             }
 81             trimFirstVT();
 82             trimLastVT();
 83 
 84         }
 85 
 86         //得到firstVT
 87         static void getFirstVT(string s, string v)
 88         {
 89             //从前往后,找合适字符加入firstVT
 90             for (int i = 0; i < s.Length; i++)
 91             {
 92                 string t = Convert.ToString(s[i]);
 93                 //如果是非终结符,且在字符串最前,将其加入firstVT
 94                 if (grammarDic.ContainsKey(t) && i == 0)
 95                     if (firstVT.ContainsKey(v))
 96                         if (!firstVT[v].Contains(t))
 97                             firstVT[v] += t;
 98                         else firstVT.Add(v, t);
 99                 //将第一个终结符加入firstVT
100                 if (!grammarDic.ContainsKey(t))
101                 {
102                     if (firstVT.ContainsKey(v))
103                         firstVT[v] += t;
104                     else firstVT.Add(v, t);
105                     break;
106                 }
107             }
108         }
109         
110         //得到lastVT
111         static void getLastVT(string s, string v)
112         {
113             //从后往前,找合适字符加入lastVT
114             for (int i = s.Length - 1; i >= 0; i--)
115             {
116                 string t = Convert.ToString(s[i]);
117                 //如果是非终结符,且在字符串最后,将其加入lastVT
118                 if (grammarDic.ContainsKey(t) && i == s.Length - 1)
119                     if (lastVT.ContainsKey(v))
120                         if (!lastVT[v].Contains(t))
121                             lastVT[v] += t;
122                         else lastVT.Add(v, t);
123                 //将最后一个终结符加入firstVT
124                 if (!grammarDic.ContainsKey(t))
125                 {
126                     if (lastVT.ContainsKey(v))
127                         lastVT[v] += t;
128                     else lastVT.Add(v, t);
129                     break;
130                 }
131             }
132         }
133 
134         //将firstVT中的终结符去掉
135         static void trimFirstVT()
136         {
137             //逆序遍历终结符集(必须逆序)
138             foreach (string v in vertex.Reverse())
139             {
140                 string s1 = firstVT[v];
141                 for (int i = 0; i < s1.Length; i++)
142                 {
143                     string t = Convert.ToString(s1[i]);
144                     //若firstVT集中含有终结符,进行整理
145                     if (grammarDic.ContainsKey(t))
146                     {
147                         firstVT[v] = firstVT[v].Replace(t, ""); //删除此终结符
148                         string s2 = firstVT[t];
149                         //将此终结符的firstVT集添加进来
150                         for (int j = 0; j < s2.Length; j++)
151                         {
152                             if (!s1.Contains(s2[j]) && !grammarDic.ContainsKey(Convert.ToString(s2[j])))
153                                 firstVT[v] += s2[j];
154                         }
155                     }
156                 }
157             }
158         }
159 
160         //将firstVT中的终结符去掉,过程同trimFirstVT()
161         static void trimLastVT()
162         {
163             foreach (string v in vertex.Reverse())
164             {
165                 string s1 = lastVT[v];
166                 for (int i = 0; i < s1.Length; i++)
167                 {
168                     string t = Convert.ToString(s1[i]);
169                     if (grammarDic.ContainsKey(t))
170                     {
171                         lastVT[v] = lastVT[v].Replace(t, "");
172                         string s2 = lastVT[t];
173                         for (int j = 0; j < s2.Length; j++)
174                         {
175                             if (!s1.Contains(s2[j]) && !grammarDic.ContainsKey(Convert.ToString(s2[j])))
176                                 lastVT[v] += s2[j];
177                         }
178                     }
179                 }
180             }
181         }
182 
183         /*------------------------------------------------------打印firstVT和lastVT------------------------------------------------------*/
184         static void printVT()
185         {
186             //输出firstVT
187             Console.WriteLine("\nfirstVT:");
188             foreach (string s in firstVT.Keys)
189             {
190                 Console.Write("firstVT " + s + " : ");
191                 for (int i = 0; i < firstVT[s].Length; i++)
192                     Console.Write(firstVT[s][i] + "  ");
193                 Console.WriteLine("");
194             }
195             //输出lastVT
196             Console.WriteLine("lastVT:");
197             foreach (string s in lastVT.Keys)
198             {
199                 Console.Write("lastVT " + s + " : ");
200                 for (int i = 0; i < lastVT[s].Length; i++)
201                     Console.Write(lastVT[s][i] + "  ");
202                 Console.WriteLine();
203             }
204         }
205 
206         /*--------------------------------------------------------算符优先关系表----------------------------------------------------*/
207         //得到算符优先关系表
208         static void getPriorityTable()
209         {
210             //添加文法:E→#E#
211             string str = vertex.FirstOrDefault();
212             grammarDic[str].Add("#" + str + "#");
213             int i1, j1;
214             //对优先关系表进行初始化
215             for (int i = 1; i <= effectValue.Length; i++)
216             {
217                 priorityTable[0,i] = effectValue[i - 1];
218                 priorityTable[i,0] = effectValue[i - 1];
219             }
220             //对产生式右部进行遍历
221             foreach (string v in vertex)
222             {
223                 List<string> g = grammarDic[v];
224                 foreach (string s in g)
225                 {
226                     for (int i = 0; i < s.Length; i++)
227                     {
228                         string t = Convert.ToString(s[i]);
229                         //若只有一个非终结符,则#=#
230                         if (s.Length == 1)
231                         {
232                             if (grammarDic.ContainsKey(t))
233                                 priorityTable[6, 6] = '=';
234                         }
235                         else
236                         {
237                             if (i > 0)
238                             {
239                                 string tp = Convert.ToString(s[i - 1]);
240                                 //出现ab型的产生式,则a=b
241                                 if ((!grammarDic.ContainsKey(tp)) && (!grammarDic.ContainsKey(t)))
242                                 {
243                                     i1 = effectValue.IndexOf(tp);
244                                     j1 = effectValue.IndexOf(t);
245                                     priorityTable[i1, j1] = '=';
246                                 }
247                                 //出现aA型的产生式,则a<firstVT[A]
248                                 if ((!grammarDic.ContainsKey(tp)) && grammarDic.ContainsKey(t))
249                                 {
250                                     i1 = effectValue.IndexOf(tp)+1;
251                                     string fir = firstVT[t];
252                                     for (int j = 0; j < fir.Length; j++)
253                                     {
254                                         j1 = effectValue.IndexOf(fir[j])+1;
255                                         priorityTable[i1, j1] = '<';
256                                     }
257                                 }
258                                 //出现Aa型的产生式,则lastVT[A]>a
259                                 if(grammarDic.ContainsKey(tp) && (!grammarDic.ContainsKey(t)))
260                                 {
261                                     j1 = effectValue.IndexOf(t) + 1;
262                                     string lat = lastVT[tp];
263                                     for(int j=0;j<lat.Length;j++)
264                                     {
265                                         i1 = effectValue.IndexOf(lat[j]) + 1;
266                                         priorityTable[i1, j1] = '>';
267                                     }
268                                 }
269                                 if(i<s.Length-1)
270                                 {
271                                     string tn = Convert.ToString(s[i + 1]);
272                                     //出现aAb型的产生式,则a=b
273                                     if((!grammarDic.ContainsKey(tp)) && grammarDic.ContainsKey(t) && (!grammarDic.ContainsKey(tn)))
274                                     {
275                                         i1 = effectValue.IndexOf(tp)+1;
276                                         j1 = effectValue.IndexOf(tn)+1;
277                                         priorityTable[i1, j1] = '=';
278                                     }
279                                 }
280                             }
281                         }
282                     }
283                 }
284             }
285         }
286 
287         //输出算符优先关系表
288         static void printPriorityTable()
289         {
290             Console.WriteLine("\n算符优先关系表如下:");
291             for (int i = 0; i < 7; i++)
292             {
293                 for (int j = 0; j < 7; j++)
294                     Console.Write(priorityTable[i,j] + "\t");
295                 Console.WriteLine("\n");
296             }
297         }
298 
299         /*-------------------------------------------算符优先分析-----------------------------------------------------------------*/
300         //得到要分析的字符串
301         static void inputMessage()
302         {
303             Console.WriteLine("\n该分析器只能识别i,+,*,(,),#,请勿输入其他字符!");
304             Console.WriteLine("请输入要分析的字符串,用#结尾(如i+i*i#)");
305             message = Console.ReadLine();
306         }
307         
308         //检测输入的字符串是否符合要求
309         static Boolean judgeMessage()
310         {
311             //检测输入的字符串是否合法
312             bool isLegal = true;
313             bool flag = true;
314             if (message[message.Length - 1] != '#')
315             {
316                 Console.WriteLine("字符串必须以#结尾!");
317                 flag = false;
318             }
319             for (int i = 0; i < message.Length; i++)
320                 if (!effectValue.Contains(message[i]))
321                     isLegal = false;
322             if (!isLegal)
323             {
324                 Console.WriteLine("该字符串中含有非法字符!");
325                 flag = false;
326             }
327 
328             return flag;
329         }
330 
331         //进行算符优先分析
332         static Boolean analyze()
333         {
334             bool flag = true;
335             stack.push("#");    //对栈进行初始化
336 
337             //对待处理串中的每个字符进行遍历
338             for (int i = 0; i < message.Length; )
339             {
340                 string s = stack.getString();   //获得栈中数据
341                 int j = s.Length - 1;
342 
343                 //寻找栈中第一个终结符
344                 while (grammarDic.ContainsKey(s[j].ToString()) || s[j] == 'E')
345                 {
346                     j--;
347                 }
348 
349                 //获取栈中第一个终结符,与字符串头元素在优先表中的位置
350                 int i1 = effectValue.IndexOf(s[j]) + 1;
351                 int j1 = effectValue.IndexOf(message[i]) + 1;
352 
353                 //优先表值进行相应的操作
354                 switch (priorityTable[i1, j1])
355                 {
356                     case '<': moveIn(i); i++; break;
357                     case '=': moveIn(i); i++; break;
358                     case '>': flag = reduction(i,j); break;
359                     default: break;
360                 }
361 
362                 //分析完成输出结果
363                 if (stack.getString().Equals("#E") && i >= message.Length-1)
364                 {
365                     Console.WriteLine(stack.getString() + "\t\t" + message.Substring(i) +  "\t\t" + "分析完成");
366                     break;
367                 }
368                 //分析失败退出循环
369                 if (!flag)
370                     break;
371             }
372             return flag;
373         }
374 
375         //移进操作
376         static void moveIn(int i)
377         {
378             Console.WriteLine(stack.getString() + "\t\t" + message.Substring(i) + "\t\t移进");
379             stack.push(message[i].ToString());
380         }
381 
382         //归约操作
383         static Boolean reduction(int n,int i)
384         {
385             string s = stack.getString();
386             bool flag = true;
387             int k = i-1;
388 
389             //遍历每一个文法
390             foreach (string v in vertex)
391             {
392                 string c = s[i].ToString();
393                 List<string> list = grammarDic[v];
394                 foreach (string g in list)
395                 {
396                     if (g.Contains(c))
397                     {
398                         Console.WriteLine(s + "\t\t" + message.Substring(n) + "\t\t规约");
399                         if (c == "i")
400                         {
401                             //防止多个i连一起的情况发生
402                             if (s[i - 1] == 'i')
403                                 flag = false;
404                             else
405                             {
406                                 stack.pop();
407                                 stack.push("E");
408                             }
409                         }
410                         else if (s.Length > g.Length)
411                         {
412                             for (int j = 0; j < g.Length; j++)
413                                 stack.pop();
414                             stack.push("E");
415                         }
416                         //开头不能为运算符
417                         else if (s[i - 1] != 'i')
418                             flag = false;
419                     }
420                 }
421             }
422             return flag;
423         }
424 
425         /*----------------------------------------------------堆栈操作--------------------------------------------------------------*/
426         //系统自带的堆栈不是很好用,于是我自己写了一个
427         class MyStack
428         {
429             string data;
430             int top;
431             public MyStack()
432             {
433                 data = "";
434                 top = -1;
435             }
436             public void push(string s)
437             {
438                 data += s;
439                 top++;
440             }
441             public string pop()
442             {
443                 data = data.Substring(0, data.Length - 1);
444                 top--;
445                 return data;
446             }
447             public string getString()
448             {
449                 return data;
450             }
451         }
452     }
453 }

运行结果

 

posted @ 2019-05-29 22:00  Sunrise_1018  阅读(4349)  评论(0编辑  收藏  举报