本学期编译原理的一个大作业,我的选题是算术表达式的词法语法语义分析,当时由于学得比较渣,只用了递归下降的方法进行了分析。

首先,用户输入算术表达式,其中算术表达式可以包含基本运算符,括号,数字,以及用户自定义变量。

词法分析,检查单词变量是否正确;语法分析,检查算术表达式语法是否正确并输出生成语法树;语义分析,输出四元表达式。

最终效果图:

例如输入:

词法分析结果:

语法分析结果:

语义分析结果:

算术表达式的组成语法如下:

无符号整数 = 〈数字〉{〈数字〉}

〈标识符〉= 〈字母〉{〈字母〉|〈数字〉}

表达式〉= [+|-]〈项〉{〈加减运算符〉〈项〉}

〈项〉= 〈因子〉{〈乘除运算符〉〈因子〉}

〈因子〉= 〈标识符〉|〈无符号整数〉|‘(’〈表达式〉‘)’

〈加减运算符〉= +|-

〈乘除运算符〉= *|/

注意:

#标识符以字母开头,仅包含字母和数字

#字母包含大写和小写字母

符号文法表示:

Indentifer: 标识符  digit:数字 M:表达式

项:T    因子:F

M -> +E|-E|E

E -> E+T|E-T|T

T -> T*F|T/F|F

F -> (E)|indentifer|digit

消除左递归,改进文法:

1. M -> +E|-E|E

2. E -> TE~

3. E~ -> +TE~|-TE~|&

4. T -> FT~

5. T~ -> *FT~|/FT~|&

6. F -> (E)|indentifer|digit

1.词法分析

单词类别定义

运算符:( , ) , + , - , * , /      类别码:3

标识符:〈字母〉{〈字母〉|〈数字〉}     类别码:1

无符号整数:〈数字〉{〈数字〉}     类别码:2

设计思路

依次接受所输入的字符串,根据DFA进行判断单词类型,将单词及符号内码存入符号表字典,将单词存入单词栈

1.如若接收到字母说明为标识符,接着一直接受字母和数字,直到出现非数字和非字母符号

2.如若在运算符后接收到数字,则说明为无符号整数,一直接受直到出现非数字符号

3.如若接受到运算符,则继续处理

简单绘制的DFA:

数据结构

符号表:dic={}

单词栈:table=[]输入数据

2.语法分析

为文法中的每一个非终结符号设计对应的处理程序,处理程序按照具体的文法接受顺序设计,每当程序选择其中一个文法时,将其保存并打印出来,若单词栈中的所有单词都被接受,则说明语法正确,其他情况,则说明语法错误

数据结构

dic={}   #符号表

table=[]   #单词栈

wenfa=[]   #字符串文法

3.语义分析与中间代码生成

设计思路

这里我运用的依旧是递归下降的思想,我并没有利用语法分析的结果,而是利用词法分析的结果为每一个非终结符号设计相应的程序, 当结果足够生成四元式时,将其输出。将结果赋给给临时变量,传递给父项。

数据结构

table=[]   #单词栈

siyuan=[]  #四元式

源码:

#-*- coding=utf-8 -*-

letter='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
number='0123456789'
operater='+-*/()' dic={} #符号表
table=[] #单词栈
wenfa=[] #字符串文法
siyuan=[] #四元式 ##################################### 词法分析 ######################################
def cifa(string): #词法分析
print ''
m=0
state=0 #1:为标识符 2:为数字串 3:为运算符
for i in range(len(string)):
if string[i] in operater : #如果是运算符
if state==1: #state=1表明其前面的为标识符
print string[m:i],'是标识符,类型码:1'
dic[string[m:i]]=1
table.append(string[m:i])
elif state==2: #state=2表明其前面的为数字
print string[m:i],'是数字,类型码:2'
dic[string[m:i]]=2
table.append(string[m:i])
m=i+1
state=3
print string[i],'是运算符,类型码:3'
dic[string[i]]=3
table.append(string[i])
elif string[i] in number: #如果是数字
if i==m: #判断此时的数字是否为整数的第一个数字,若是则改变状态为无符号整数
state=2
elif string[i] in letter: #如果是字母
if state==2: #判断此时的状态,若state=2表明状态为无符号整数,而整数内不能包含字母,故报错
print '词法分析检测到错误,数字串中不能包含字母'
exit(0)
if i==m: #判断此时的字母是否为标识符的第一个字母,若是则改变状态为标识符
state=1
else: #当输入的字符均不符合以上判断,则说明为非法字符,故报错
print '词法分析检测到非法字符'
exit(0)
if state==1: #当字符串检查完后,若字符串最后部分为标识符,应将其print出来
print string[m:],'是标识符,类型码:3'
dic[string[m:]]=1
table.append(string[m:])
elif state==2: #若字符串最后部分为无符号整数,应将其print出来
print string[m:],'是无符号整数,类型码:2'
dic[string[m:]]=2
table.append(string[m:])
table.append('#')
print '字符栈:',table,'\n词法正确' ################################### 语法分析 #####################################
'''
基本文法:
M -> +E|-E|E
E -> TE~
E~ -> +TE~|-TE~|&
T -> FT~
T~ -> *FT~|/FT~|&
F -> (E)|indentifer|digit
'''
class yufa(): #语法分析程序
def __init__(self):
self.i=0 #栈指针
try: #用异常处理程序捕获程序的错误,出现异常则报错
self.m()
except:
print '\n语法分析程序检查到错误'
exit(0)
def m(self): #PM程序
if(table[self.i]=='+'):
self.i+=1
wenfa.append('M -> +E')
self.e()
elif(table[self.i]=='-'):
self.i+=1
wenfa.append('M -> -E')
self.e()
else:
wenfa.append('M -> E')
self.e()
if(self.i is not len(table)-1): #语法分析结束时,若单词栈指针与单词表长度不相等,报错
print "\n语法分析程序检查到错误,'('前应该有运算符"
exit(0)
else:
print '\n字符串语法是:' #若一切正确,则输出语法树文法
for i in wenfa:
print i
print '语法正确'
def e(self): #PE程序
wenfa.append('E -> TE1')
self.t()
self.e1()
def e1(self): #PE1程序
if(table[self.i]=='+'):
self.i+=1
wenfa.append('E1 -> +TE1')
self.t()
self.e1()
elif(table[self.i]=='-'):
self.i+=1
wenfa.append('E1 -> -TE1')
self.t()
self.e1()
else:
wenfa.append('E1 -> &')
def t(self): #PT程序
wenfa.append('T -> FT1')
self.f()
self.t1()
def t1(self): #PT1程序
if(table[self.i]=='*'):
self.i+=1
wenfa.append('T1 -> *FT1')
self.f()
self.t1()
elif(table[self.i]=='/'):
self.i+=1
wenfa.append('T1 -> /FT1')
self.f()
self.t1()
else:
wenfa.append('T1 -> &')
def f(self): #PF程序
if(table[self.i]=='('):
wenfa.append('F -> (E)')
self.i+=1
self.e()
if(table[self.i]!=')'):
raise Exception
self.i+=1
elif(dic[table[self.i]]==1):
wenfa.append('F -> Indentifer '+str(table[self.i]))
self.i+=1
elif(dic[table[self.i]]==2):
wenfa.append('F -> Digit '+str(table[self.i]))
self.i+=1
else:
raise Exception #若均不符合,则引出异常 ####################################### 语义分析 ####################################### class yuyi:
def __init__(self):
print '\n语义分析结果(四元式):'
self.i=0 #栈指针
self.flag=0 #记录临时变量T数目
self.m()
for i in siyuan: #输出四元式结果
print i
def m(self): #PM程序
if(table[self.i]=='+'):
self.i+=1
ret1=self.e()
siyuan.append('(+,0,'+ret1+',out)')
self.flag+=1
elif(table[self.i]=='-'):
self.i+=1
ret2=self.e()
siyuan.append('(-,0,'+ret2+',out)')
self.flag+=1
else:
ret3=self.e()
siyuan.append('(=,'+ret3+',0,out)')
def e(self): #PE程序
ret1=self.t()
ret2,ret3=self.e1()
if(ret2!='&'): #若ret2不为&,则可以产生四元式,否则将变量传递给父项
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return 'T'+str(self.flag)
else:
return ret1
def e1(self): #PE1程序
if(table[self.i]=='+'):
self.i+=1
ret1=self.t()
ret2,ret3=self.e1()
if(ret2=='&'):
return '+',ret1
else:
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return '+','T'+str(self.flag)
elif(table[self.i]=='-'):
self.i+=1
ret1=self.t()
ret2,ret3=self.e1()
if(ret2=='&'):
return '-',ret1
else:
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return '-','T'+str(self.flag)
else:
return '&','&'
def t(self): #PT程序
ret1=self.f()
ret2,ret3=self.t1()
if(ret2!='&'):
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return 'T'+str(self.flag)
else:
return ret1
def t1(self): #PT1程序
if(table[self.i]=='*'):
self.i+=1
ret1=self.f()
ret2,ret3=self.t1()
if(ret2=='&'):
return '*',ret1
else:
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return '*','T'+str(self.flag)
elif(table[self.i]=='/'):
self.i+=1
ret1=self.f()
ret2,ret3=self.t1()
if(ret2=='&'): #若ret2不为&,则可以产生四元式,否则将变量传递给父项
return '/',ret1
else:
self.flag+=1
siyuan.append('('+ret2+','+ret1+','+ret3+',T'+str(self.flag)+')')
return '/','T'+str(self.flag)
else:
return '&','&'
def f(self): #PF程序
if(table[self.i]=='('):
self.i+=1
ret1=self.e()
self.i+=1
return str(ret1)
elif(dic[table[self.i]]==1): #当为标识符时,传递给父项
temp=self.i
self.i+=1
return table[temp]
elif(dic[table[self.i]]==2): #当为整数时,传递给父项
temp=self.i
self.i+=1
return table[temp] ####################################### 主程序 #######################################
if __name__=='__main__':
string=raw_input('请输入表达式:')
cifa(string)
yufa()
yuyi()

  

python实现算术表达式的词法语法语义分析(编译原理应用)的更多相关文章

  1. PYTHON实现算术表达式构造二叉树

    LEETCOCE 224. Basic Calculator Implement a basic calculator to evaluate a simple expression string. ...

  2. 用java实现编译器-算术表达式及其语法解析器的实现

    大家在参考本节时,请先阅读以下博文,进行预热: http://blog.csdn.net/tyler_download/article/details/50708807 本节代码下载地址: http: ...

  3. Python运算符与表达式

    Python运算符包括赋值运算符.算术运算符.关系运算符.逻辑运算符.位运算符.成员运算符和身份运算符. 表达式是将不同类型的数据(常亮.变量.函数)用运算符按照一定得规则连接起来的式子. 算术运算符 ...

  4. Compiler Theory(编译原理)、词法/语法/AST/中间代码优化在Webshell检测上的应用

    catalog . 引论 . 构建一个编译器的相关科学 . 程序设计语言基础 . 一个简单的语法制导翻译器 . 简单表达式的翻译器(源代码示例) . 词法分析 . 生成中间代码 . 词法分析器的实现 ...

  5. python基础知识-(1)语法基础知识总结(转载)

    1.Python标识符 在 Python 里,标识符有字母.数字.下划线组成. 在 Python 中,所有标识符可以包括英文.数字以及下划线(_),但不能以数字开头. Python 中的标识符是区分大 ...

  6. <编译原理 - 函数绘图语言解释器(2)语法分析器 - python>

    <编译原理 - 函数绘图语言解释器(2)语法分析器 - python> 背景 编译原理上机实现一个对函数绘图语言的解释器 - 用除C外的不同种语言实现 设计思路: 设计函数绘图语言的文法, ...

  7. [Java]算术表达式求值之一(中序表达式转后序表达式方案)

    第二版请见:https://www.cnblogs.com/xiandedanteng/p/11451359.html 入口类,这个类的主要用途是粗筛用户输入的算术表达式: package com.h ...

  8. Project Euler 93:Arithmetic expressions 算术表达式

    Arithmetic expressions By using each of the digits from the set, {1, 2, 3, 4}, exactly once, and mak ...

  9. C++算术运算符与算术表达式

    基本的算术运算符 在本章中主要介绍算术运算符与算术表达式,赋值运算符与赋值表达式,逗号运算符与逗号表达式,其他运算符将在以后各章中陆续介绍. 常见算数运算符 运算符 说明 举例 + 加法运算符,或正值 ...

随机推荐

  1. springmvc sessionfilter 登录过滤器

    1.在web.xml中配置 <!-- sessionfilter --> <filter> <filter-name>sessionFilter</filte ...

  2. 通过gmapping和伪造的odom,完成Kinect建图

    传感器信息: 环境深度信息:sensor_msgs/laserScan -----> RGBD三维点云数据:通过ros功能包depthimage to laserscan完成深度相机数据转换成激 ...

  3. MySQL驱动和数据库字符集设置不搭配

    刚才控制台又报这个错,这是代表MySQL驱动和数据库字符集设置不搭配: 错误: "...Initial client character set can be forced via the ...

  4. Solr和Lucene的区别?

    1.Lucene 是工具包 是jar包 2.Solr是索引引擎服务  War 3.Solr是基于Lucene(底层是由Lucene写的) 4.上面二个软件都是Apache公司由java写的 5.Luc ...

  5. P4248 [AHOI2013]差异

    思路 SAM 后缀自动机parent树的LCA就是两个子串的最长公共后缀 现在要求LCP 所以把字符串反转一下 然后每个点的贡献就是endpos的大小,dfs一遍求出贡献就可以了 代码 #includ ...

  6. 使用VS Code调试Node

    1.双击打开vscode 2.找到底层面板 把ctrl改成LF 2. 3.打开文件夹,建立项目test 4.新建hellow.js 输入: var name='world'; var s='hello ...

  7. variable 'o' used without having been completely initialized Compiling Vertex program

    variable 'o' used without having been completely initialized Compiling Vertex program   v2f vert (ap ...

  8. windows图形图像桌面消失(误删.net组件)

    核心模式core 变回完整模式 Full,用dism命令,具体命令如下 dism /online /enable-feature /all /featurename:servercore-fullse ...

  9. 来自师兄的Django2.0笔记摘录

    翻看一本书,觉得对于Django的日志处理.权限处理包括Django-guardian还没学清楚,然后书上关于mysql深入学习.elasticsearch.redis.celery分布式都没学过. ...

  10. SpringBoot之依赖注入DI

    相关注解: @Component @Service @Controller @Repository --------------------------------------------- @Inj ...