【Python】代码实现LL(1),LR(1)上下文无关文法(Stack()类)

冷不防 2023-02-13 14:45 76阅读 0赞

任务要求

针对书上第三章中的表达式文法,采用LL(1)、LR(1)进行分析

相关文法(需要进行消除左递归等操作):
在这里插入图片描述

顺手分享一下课本资源好了(可能不是最新版,排版略有点别扭)
后文的书上内容就是指这本书:[编译原理].陈意云.文字版
提取码:e0ag

LL1介绍

LL(1):从左往右处理输入,最左推导,向前展望1个符号的,不带回溯的自上而下的算法,是上下文无关文法的子集。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

LL1代码实现

书上P59-60
在这里插入图片描述
在这里插入图片描述

  1. #LL1
  2. import pandas as pd
  3. class Stack:
  4. def __init__(self):
  5. self.values = "$E"
  6. def push(self, product):
  7. while product[-1:]!='→':
  8. if(product[-1:]=='\'' or product[-1:]=='d'):
  9. self.values+=product[-2:]
  10. product=product[0:-2]
  11. else:
  12. self.values+=product[-1:]
  13. product=product[0:-1]
  14. def pop(self):
  15. if(self.values[-1:]=='\''or self.values[-1:]=='d'):
  16. self.values=self.values[:-2];
  17. else:
  18. self.values=self.values[:-1]
  19. def top(self):
  20. if(self.values[-1:]=='\''or self.values[-1:]=='d'):
  21. return self.values[-2:]
  22. else:
  23. return self.values[-1:]
  24. def empty(self):
  25. return len(self.values) == 0
  26. def Next_Char():#获取下一个词法记号
  27. global pend_input
  28. if(pend_input[0:2]=="id"):
  29. pend_input=pend_input[2:]
  30. return "id"
  31. else:
  32. t=pend_input[0:1]
  33. pend_input=pend_input[1:]
  34. return t
  35. dic={
  36. #手工构造预测分析表
  37. 'id':['E→TE\'','error','T→FT\'','error','F→id'],
  38. '+':['error','E\'→+TE\'','error','T\'→ε','error'],
  39. '*':['error','error','error','T\'→*FT\'','error'],
  40. '(':['E→TE\'','error','T→FT\'','error','F→(E)'],
  41. ')':['error','E\'→ε','error','T\'→ε','error'],
  42. '$':['error','E\'→ε','error','T\'→ε','error']}
  43. Analysis_table=pd.DataFrame(dic,index=['E','E\'','T','T\'','F'])
  44. if __name__ == '__main__':
  45. stk = Stack() #构造自定义栈
  46. #pend_input=input()+'$' #记得在输入内容后加上表示终止的"$"符号
  47. pend_input='id*id+id$' #可手动输入亦可提前输入'待处理的输入内容'
  48. pend_head=Next_Char() #取出第一个待处理的符号
  49. print("预测分析器接受输入id*id+id的部分动作(与书上稍有不同)")
  50. print("%-15s"%"栈","%-15s"%"输入","%+10s"%"输出")
  51. while(stk.empty()==False):
  52. if stk.top()==pend_head:
  53. if pend_head!='$':
  54. print('----------------成功匹配符号:{}-------------------'.format(pend_head))
  55. pend_head=Next_Char()
  56. stk.pop()
  57. else:
  58. product=Analysis_table[pend_head][stk.top()]#获取产生式
  59. if product=='error':
  60. print('Error Skip!')
  61. stk.pop()
  62. else:
  63. print("%-15s"%stk.values,"%-15s"%str(pend_head+pend_input),"%+15s"%product)
  64. stk.pop()
  65. if(product[-1:]!='ε'):#对于产生空串的产生式,只需弹栈,不需入栈
  66. stk.push(product)

手动构造的预测分析表:
在这里插入图片描述

预测分析器接受输入id * id + id的相关动作:
在这里插入图片描述

LR1简略介绍

LR(1):从左往右处理输入,构造一个最右推导的逆过程(规范规约),向前看1个符号的,自下而上的算法,是上下文无关文法的子集。

LR文法:我们能为之构造出所有条目都唯一的LR分析表。

LR分析器特点:适用于一大类上下文无关文法,效率高。

句型的句柄是和某产生式右部匹配的子串,并且,把它归约成该产生式左部的非终结符代表了最右推导过程的逆过程的一步。

活前缀:右句型的前缀,该前缀不超过最右句柄的右端。

在这里插入图片描述

LR1代码

书上P73-74

在这里插入图片描述
r后面的数字代表按第几个产生式做归约;s代表移进,它后面的数字转移到哪个状态。产生式:
在这里插入图片描述
在这里插入图片描述

  1. #LR1
  2. import pandas as pd
  3. class Stack:
  4. def __init__(self):
  5. self.values = "0"
  6. def push(self, s):
  7. self.values=self.values+s
  8. def __init__(self):
  9. self.values = "0"
  10. def pop(self):
  11. if(self.values[-2:]=='id'or self.values[-2:]=='10'or self.values[-2:]=='11'):
  12. self.values=self.values[:-2]
  13. else:
  14. self.values=self.values[:-1]
  15. def top(self):
  16. if(self.values[-2:]=='10'or self.values[-2:]=='id' or self.values[-2:]=='11'):
  17. return self.values[-2:]
  18. else:
  19. return self.values[-1:]
  20. class Input_Token:
  21. def __init__(self):
  22. self.values = ""
  23. def Get_Token(self):#获取待处理字符串pend_input中下一个词法记号
  24. if(self.values[0:2]=="id"):
  25. self.values=self.values[2:]
  26. return "id"
  27. else:
  28. s=self.values[0:1]
  29. self.values=self.values[1:]
  30. return s
  31. def Show_Token(self):#查看待处理字符串pend_input的下一个词法记号(不取出)
  32. if (self.values[0:2] == "id"):
  33. return "id"
  34. else:
  35. s = self.values[0:1]
  36. return s
  37. def Len_Right(p):
  38. p_char=p[p.find('→')+1:]
  39. if p_char=='id':
  40. return 1
  41. else:
  42. return len(p_char)
  43. def LR1(head,top):#分析程序
  44. action=SLR[head][top]
  45. if action=='acc':#接受
  46. print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"接受")
  47. return False
  48. else:
  49. if action[0]=='s':#移进
  50. print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+6s"%"移进")
  51. stk.push(pend_input.Get_Token())
  52. stk.push(action[1:])
  53. elif action[0]=='r':#归约
  54. production=Production[int(action[1:])]
  55. print("%-9s"%stk.values,"%+9s"%pend_input.values,"%+5s"%"按",production,"归约")
  56. for i in range(Len_Right(production)*2): #按照产生式右边长度的2倍出栈(1字符跟1数字)
  57. stk.pop()
  58. top_num=stk.top()
  59. left=production[0] #获取产生式左边的字符
  60. stk.push(left)
  61. stk.push(SLR[left][top_num])
  62. else:
  63. print('Error!\n Exit!')
  64. return False
  65. return True
  66. dic={
  67. 'id':['s5',' ',' ',' ','s5',' ','s5','s5',' ',' ',' ',' '],
  68. '+':[' ','s6','r2','r4',' ','r6',' ',' ','s6','r1','r3','r5'],
  69. '*':[' ',' ','s7','r4',' ','r6',' ',' ',' ','s7','r3','r5'],
  70. '(':['s4',' ',' ',' ','s4',' ','s4','s4',' ',' ',' ',' ',],
  71. ')':[' ',' ','r2','r4',' ','r6',' ',' ','s11','r1','r3','r5'],
  72. '$':[' ','acc','r2','r4',' ','r6',' ',' ',' ','r1','r3','r5'],
  73. 'E':['1',' ',' ',' ','8',' ',' ',' ',' ',' ',' ',' '],
  74. 'T':['2',' ',' ',' ','2',' ','9',' ',' ',' ',' ',' ',],
  75. 'F':['3',' ',' ',' ','3',' ','3','10',' ',' ',' ',' ']}
  76. SLR=pd.DataFrame(dic,index=['0','1','2','3','4','5','6','7','8','9','10','11'])#分析表
  77. Production=['null','E→E+T','E→T','T→T*F','T→F','F→(E)','F→id']#产生式
  78. if __name__=='__main__':
  79. stk = Stack()
  80. pend_input=Input_Token()
  81. pend_input.values='id*id+id$'
  82. print("———————————————LR分析器———————————————")
  83. print("%-7s"%"栈","%+8s"%"输入","%+6s"%"动作")
  84. while(True):
  85. if LR1(pend_input.Show_Token(),stk.top())==False:
  86. break
  87. print("——————————————————————————————————————")

分析表(action表)
描述?
实验结果:
在这里插入图片描述

LR分析方法和LL分析方法的比较

部分参考资料" class="reference-link">在这里插入图片描述 部分参考资料

编译原理:语法分析2-非递归的预测分析

编译原理:语法分析3-LR分析器

编译原理:LL(1),LR(0),SLR(1),LALR(1),LR(1)对比

《编译原理》LR 分析法与构造 LR(1) 分析表的步骤 - 例题解析

Python栈实现

发表评论

表情:
评论列表 (有 0 条评论,76人围观)

还没有评论,来说两句吧...

相关阅读

    相关 LL1文法 JAVA

    E文法表达式类 G 定义文法类 LL 文法分析类 , 包含对First,Follow,Select集合的求解以及对表达式的分析函数  Main测试分析程序,并输出结果

    相关 LL(1)文法

    文章目录 预测分析法的工作过程 S\_文法(简单的确定性文法) 什么时候使用$\\epsilon$产生式? 非终结符的后继符号集 产生式的可