目录
相关篇目
编译原理上机——函数绘图语言(一)
编译原理上机——函数绘图语言(二):词法分析器
编译原理上机——函数绘图语言(三):语法分析器
编译原理上机——函数绘图语言(四):语义分析器
完整代码
Gitee开源代码
说明
这是编译原理上机的最后一部分代码了,激动不?兴奋不?
最后一篇代码是基于编译原理上机——函数绘图语言(四):语义分析器的改写,将其改为方便于编译器与解释器读取的代码.(大同小异,大同小异)
文件罗列
test.py
测试文件(这个可以自己改)
createtable.py
创建符号表
scanner.py
扫描器
lexer.py
词法分析器
以上文件与编译原理上机——函数绘图语言(四):语义分析器中同名文件相同
myparser.py
语法分析器+语义分析器+中间代码生成器+中间代码优化器
mycompile.py
编译器
interpreter.py
解释器
main.py
主函数
output.py
目标代码(解释器没有该文件)
语法分析器
文件名为myparser.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 2 19:36:32 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 语法分析器
import ast
import math
import os
import astunparse
import scanner
class Parser:
def __init__(self, path):
# 中间代码生成
self.state_of_origin = [0, 0] # 原点默认值
self.state_of_scale = [1, 1] # 图像放大默认值
self.state_of_rot = 0 # 图像旋转默认值
self.state_of_for = [0, 0, 0] # 绘图的状态参数
self.draw = ['', ''] # 画图
self.MidCode = []
# 中间代码生成结束
self.scanner = scanner.Scanner(path)
self.dataflow = self.scanner.analyze()
self.pos = 0 # 数据读取位置
self.length = len(self.dataflow) # 数据流长度
def analyze(self):
while(self.pos < self.length):
# 匹配保留字
# S->'ORIGIN'T|'SCALE'T|'ROT'T|'FOR'P
# T->'IS('E','E')'|'IS'E
# E为一个算数表达式
# P为FOR后特殊结构
if self.dataflow[self.pos][1]['TYPE'] == 'KEYWORD':
self.output(self.dataflow[self.pos][0])
# 转换为列表
return [eval(x) for x in self.MidCode]
def output(self, string):
# 输出
# 因为输出语句结构相同
# 所以放在同一个函数中
# 实际上,语法分析到得到语法树便结束了
self.pos += 1
if string == 'ORIGIN':
self.ORIGIN()
elif string == 'SCALE':
self.SCALE()
elif string == 'ROT':
self.ROT()
elif string == 'FOR':
self.FOR()
# 因为Python深复制与浅复制的问题
# 我直接使用了字符串
# 输出的时候转换为列表
# 可以将中间代码输出至文件
# 增加6+2图的上下层隔离性
self.MidCode.append(str((self.state_of_origin, self.state_of_scale,
self.state_of_rot, self.state_of_for, self.draw)))
else:
raise SyntaxError()
def ORIGIN(self):
self.matchstring('IS')
templist = self.matchparameter()
# 更改平移状态
self.state_of_origin[0] = eval(templist[0])
self.state_of_origin[1] = eval(templist[1])
def SCALE(self):
self.matchstring('IS')
templist = self.matchparameter()
# 更改缩放状态
self.state_of_scale[0] = eval(templist[0])
self.state_of_scale[1] = eval(templist[1])
def ROT(self):
self.matchstring('IS')
# 更改旋转状态
self.state_of_rot = eval(self.matchexpression())
def FOR(self):
self.matchstring('T')
self.matchstring('FROM')
# 更改FOR状态
self.state_of_for[0] = eval(self.matchexpression())
self.matchstring('TO')
self.state_of_for[1] = eval(self.matchexpression())
self.matchstring('STEP')
self.state_of_for[2] = eval(self.matchexpression())
self.matchstring('DRAW')
templist = self.matchparameter()
# 更改画图状态
self.draw[0] = templist[0]
self.draw[1] = templist[1]
def matchstring(self, string):
# 匹配一个特定的字符串
if self.dataflow[self.pos][0] == string:
self.pos += 1
else:
raise SyntaxError()
# matchparameter与matchexpression的区别
# 前者匹配双表达式
# 或者既可以匹配双表达式又可以匹配单表达式
# 分开原因:
# 考虑到ROT后面是单表达式而ORIGIN与SCALE后面都是算表达式
# 并且FOR后面既有单表达式又有双表达式
# 所以特此区分
def matchparameter(self):
# 匹配(E,E)
# 即匹配参数列表
# 如:
# ORIGIN IS (5,5);
# 后面的括号中包括括号的部分都是参数列表
temp = self.matchexpression() # 缓冲区
# 转换为列表[E,E]
if temp[0] == '(' and temp[-1] == ')':
temp = temp[1:-1].split(',')
else:
raise SyntaxError()
return temp
def matchexpression(self):
# 匹配E或者(E,E)
# 即匹配一个算数表达式
# 如
# 5*2-LN(3)
# (5*2-3,tan(0.1))
temp = '' # 缓冲区
while(self.dataflow[self.pos][0] != ';' and self.pos < self.length and self.dataflow[self.pos][1]['TYPE'] != 'KEYWORD'):
if self.dataflow[self.pos][1]['TYPE'] == 'FUNC':
temp += self.dataflow[self.pos][1]['FUNCTION']
elif self.dataflow[self.pos][1]['TYPE'] == 'CONST_ID':
temp += self.dataflow[self.pos][1]['VALUE']
else:
temp += self.dataflow[self.pos][0]
self.pos += 1
if self.dataflow[self.pos][0] == ';':
self.pos += 1 # 跳过结尾的分号
return temp
编译器
编译器主体
文件名为mycompile.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 4 11:12:17 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 编译器
import myparser
class Compile():
def __init__(self, input_path, output_path):
self.path = output_path
self.MidCode = myparser.Parser(input_path).analyze()
with open(self.path, 'w', encoding='utf-8') as f:
# 增加头文件,即turtle库
f.write(
'''# @author: FishPotatoChen
# Copyright (c) 2020 FishPotatoChen All rights reserved.
import math
import turtle
import numpy as np
turtle.setup(width=1.0,height=1.0)
turtle.penup()
'''
)
def create(self):
with open(self.path, 'a') as f:
#操作每一次画图
for i in self.MidCode:
f.write(
'''
for T in np.arange('''+str(i[3][0])+''', '''+str(i[3][1])+''', '''+str(i[3][2])+'''):
x = '''+str(i[4][0])+'''*'''+str(i[1][0])+'''
y = '''+str(i[4][1])+'''*'''+str(i[1][1])+'''
x_rot = x*math.cos('''+str(i[2])+''')+y*math.sin('''+str(i[2])+''')+'''+str(i[0][0])+'''
y_rot = y*math.cos('''+str(i[2])+''')-x*math.sin('''+str(i[2])+''')+'''+str(i[0][1])+'''
turtle.goto(x_rot,y_rot)
turtle.dot()
'''
)
f.write('\nturtle.done()')
主函数
文件名为main.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 4 11:12:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
import os
import mycompile
if __name__ == '__main__':
path = os.getcwd()
mycompile.Compile(path+r'\test.txt', path+r'\output.py').create()
解释器
解释器主体
文件名为interpreter.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 5 8:37:29 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 解释器
import myparser
import math
import turtle
import numpy as np
class Interpreter():
def __init__(self, path):
self.MidCode = myparser.Parser(path).analyze()
# 初始化画布
turtle.setup(width=1.0, height=1.0)
turtle.penup()
def create(self):
# 解析中间代码
for i in self.MidCode:
# 操作每一次画图
for T in np.arange(i[3][0], i[3][1], i[3][2]):
x = eval(i[4][0])*i[1][0]
y = eval(i[4][1])*i[1][1]
x_rot = x * math.cos(i[2])+y*math.sin(i[2])+i[0][0]
y_rot = y * math.cos(i[2])-x*math.sin(i[2])+i[0][1]
turtle.goto(x_rot, y_rot)
turtle.dot()
turtle.done()
主函数
文件名为main.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 4 11:12:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
import os
import interpreter
if __name__ == '__main__':
path = os.getcwd()
interpreter.Interpreter(path+r'\test.txt').create()
测试
测试文件
文件名为test.txt
scale is (100,100);
for t from 0 to 2*pi step pi/50 draw (cos(t),sin(t));
scale is (100/2,100);
origin is (100,0);
rot is pi/2;
for t from 0 to 2*pi step pi/50 draw (cos(t),sin(t));
目标代码
文件名为output.py
,注意这是运行编译器的main.py
后得到的文件,对于编译器,还需运行目标代码才能得到绘图结果。这就像C/C++
编译完成后生成的.exe
文件,想要得到C/C++
的结果还需运行.exe
文件。
# @author: FishPotatoChen
# Copyright (c) 2020 FishPotatoChen All rights reserved.
import math
import turtle
import numpy as np
turtle.setup(width=1.0,height=1.0)
turtle.penup()
for T in np.arange(0, 6.283185307179586, 0.06283185307179587):
x = math.cos(T)*100
y = math.sin(T)*100
x_rot = x*math.cos(0)+y*math.sin(0)+0
y_rot = y*math.cos(0)-x*math.sin(0)+0
turtle.goto(x_rot,y_rot)
turtle.dot()
for T in np.arange(0, 6.283185307179586, 0.06283185307179587):
x = math.cos(T)*50.0
y = math.sin(T)*100
x_rot = x*math.cos(1.5707963267948966)+y*math.sin(1.5707963267948966)+100
y_rot = y*math.cos(1.5707963267948966)-x*math.sin(1.5707963267948966)+0
turtle.goto(x_rot,y_rot)
turtle.dot()
turtle.done()
绘图结果
说明
绘制的初始原点为全图最中心,因为我觉得在左上角对用户不是很友好。
绘图流程:
- 修改比例;
- 旋转图形;
- 平移图形。
附录
为了方便起见,我在这里将所有的代码总结在这
支持库
math
Python数学函数支持库
re
匹配正则表达式,也就是匹配正规式
os
系统调用,在此主要用来获得当前路径
turtle
Python海龟库,用于画图
numpy
Python科学计算库,在此主要用于解决range
不支持小数问题
使用前请务必安装支持库
符号表
文件名为createtable.py
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
import math
TOKEN = {
# 常量
'PI': {'TYPE': 'CONST_ID', 'VALUE': 'math.pi', 'FUNCTION': None},
'E': {'TYPE': 'CONST_ID', 'VALUE': 'math.e', 'FUNCTION': None},
# 变量
'T': {'TYPE': 'SYMBOL', 'VALUE': None, 'FUNCTION': None},
# 函数
'SIN': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.sin'},
'COS': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.cos'},
'TAN': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.tan'},
'LN': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.log'},
'EXP': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.exp'},
'SQRT': {'TYPE': 'FUNC', 'VALUE': None, 'FUNCTION': 'math.sqrt'},
# 保留字
'ORIGIN': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'SCALE': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'ROT': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'IS': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'FOR': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'FROM': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'TO': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'STEP': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
'DRAW': {'TYPE': 'KEYWORD', 'VALUE': None, 'FUNCTION': None},
# 运算符
'+': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
'-': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
'*': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
'/': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
'**': {'TYPE': 'OP', 'VALUE': None, 'FUNCTION': None},
# 记号
'(': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
')': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
',': {'TYPE': 'MARK', 'VALUE': None, 'FUNCTION': None},
# 结束符
';': {'TYPE': 'END', 'VALUE': None, 'FUNCTION': None},
# 空
'': {'TYPE': 'EMPTY', 'VALUE': None, 'FUNCTION': None},
# 数字
'0': {'TYPE': 'NUMBER', 'VALUE': 0.0, 'FUNCTION': None},
'1': {'TYPE': 'NUMBER', 'VALUE': 1.0, 'FUNCTION': None},
'2': {'TYPE': 'NUMBER', 'VALUE': 2.0, 'FUNCTION': None},
'3': {'TYPE': 'NUMBER', 'VALUE': 3.0, 'FUNCTION': None},
'4': {'TYPE': 'NUMBER', 'VALUE': 4.0, 'FUNCTION': None},
'5': {'TYPE': 'NUMBER', 'VALUE': 5.0, 'FUNCTION': None},
'6': {'TYPE': 'NUMBER', 'VALUE': 6.0, 'FUNCTION': None},
'7': {'TYPE': 'NUMBER', 'VALUE': 7.0, 'FUNCTION': None},
'8': {'TYPE': 'NUMBER', 'VALUE': 8.0, 'FUNCTION': None},
'9': {'TYPE': 'NUMBER', 'VALUE': 9.0, 'FUNCTION': None},
'.': {'TYPE': 'NUMBER', 'VALUE': None, 'FUNCTION': None},
}
扫描器
文件名为scanner.py
,输入为未处理的文件,输出为去掉注释之后经过简单处理的文件
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 输入处理器
import re
import lexer
class Scanner():
def __init__(self, path):
# 读入文件位置
self.path = path
# 设置缓冲区
self.text = ""
with open(self.path, "r") as f:
lines = f.readlines()
for line in lines:
# 将文件中注释去掉
self.text = self.text + \
line.split("//")[0].split("--")[0].split("\n")[0]
self.text = self.text.upper().strip()
self.lexer = lexer.Lexer()
self.output_lists = []
def analyze(self):
sentences = re.split("(;)", self.text)
# No.0
# 识别
# E->E;|ε
# 用于记录状态机状态,当state == True时,意味着可以读入一个E,当state == False时,意味着可以读入一个;
state = True
for sentence in sentences:
if state and sentence != ";":
state = False
self.lexer.getToken(sentence)
self.output_lists.extend(self.lexer.output_list)
elif sentence == ";":
state = True
else:
raise SyntaxError()
if state:
raise SyntaxError()
# No.0 识别结束
return self.output_lists
词法分析器
文件名为lexer.py
,输入为经过简单处理的文件,输出为记号流
# -*- coding: utf-8 -*-
"""
Created on Mon Nov 23 20:05:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 词法分析器
import math
import re
import createtable
class Lexer:
def __init__(self):
# 从文件中读取记号表
self.TOKEN = createtable.TOKEN
def getToken(self, sentence):
self.output_list = []
if sentence:
tokens = sentence.split()
for token in tokens:
try:
# No.0
# 首先识别直接可以识别的记号
# 正规式为ORIGIN|SCALE|ROT|IS|FOR|FROM|TO|STEP|DRAW|ε
self.output_token(token)
# No.0 识别结束
except:
# 找不到就进入更高级的DFA中识别
self.argument_lexer(token)
self.output_token(';')
# 构造更为复杂、高级的、多种类的识别表达式
def argument_lexer(self, argument):
# 扫描位置
i = 0
# 字符串长度
length = len(argument)
while(i < length):
# 临时字符串,即缓冲区
temp = ''
if argument[i] in ['P', 'S', 'C', 'L', 'E', 'T', '*']:
# No.1
# 识别"*"还是"**"的过程是一个上下文有关文法
if argument[i] == '*':
i += 1
if i >= length:
self.output_token(argument[i])
break
elif argument[i] == '*':
self.output_token('**')
else:
i -= 1
self.output_token(argument[i])
# No.1 识别结束
else:
# No.2
# DFA判断全为字母的字符串
# 正规式为PI|E|T|SIN|COS|TAN|LOG|EXP|SQRT
temp = re.findall(r"[A-Z]+", argument[i:])[0]
# 看该串是否接受
self.output_token(temp)
i += len(temp)-1
if i >= length:
break
# No.2 识别结束
elif argument[i] in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.']:
# No.3
# 识别数字
if argument[i] == '.':
# 识别开头为"."的数字
# 正规式为.[0-9]+
# 如:.52=>0.52
i += 1
temp = re.findall(r"\d+", argument[i:])[0]
i += len(temp)-1
temp = '0.' + temp
self.output_token(temp, False)
else:
# 识别一般数字
# 正规式为[0-9]+.?[0-9]*
# 如:5.52=>5.52;12=>12
temp = re.findall(r"\d+\.?\d*", argument[i:])[0]
i += len(temp)-1
self.output_token(temp, False)
if i >= length:
break
# No.3 识别结束
else:
# No.4
# 识别其他字符
# 正规式为+|-|/|(|)|,|ε
self.output_token(argument[i])
i += 1
# 输出函数
# 因为解释器可以不用输出至屏幕,但是题目要求输出至屏幕
# 所以特别写了一个函数用于输出,便于接下来的语法分析器调用文法分析器
# 当输出不为屏幕时,将输出嵌入代码会变得不好更改
# 如果写成独立函数,直接更改输出函数即可
def output_token(self, token, NotNumber=True):
if NotNumber:
self.output_list.append([token, self.TOKEN[token]])
else:
tempdic = {token: {'TYPE': 'NUMBER',
'VALUE': float(token), 'FUNCTION': None}}
self.output_list.append([token, tempdic[token]])
语法分析器+语义分析器+中间代码优化+中间代码生成
文件名为myparser.py
,输入为记号流,输出为中间代码
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 2 19:36:32 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 语法分析器
import math
import os
import scanner
class Parser:
def __init__(self, path):
# 中间代码生成
self.state_of_origin = [0, 0] # 原点默认值
self.state_of_scale = [1, 1] # 图像放大默认值
self.state_of_rot = 0 # 图像旋转默认值
self.state_of_for = [0, 0, 0] # 绘图的状态参数
self.draw = ['', ''] # 画图
self.MidCode = []
# 中间代码生成结束
self.scanner = scanner.Scanner(path)
self.dataflow = self.scanner.analyze()
self.pos = 0 # 数据读取位置
self.length = len(self.dataflow) # 数据流长度
def analyze(self):
while(self.pos < self.length):
# 匹配保留字
# S->'ORIGIN'T|'SCALE'T|'ROT'T|'FOR'P
# T->'IS('E','E')'|'IS'E
# E为一个算数表达式
# P为FOR后特殊结构
if self.dataflow[self.pos][1]['TYPE'] == 'KEYWORD':
self.output(self.dataflow[self.pos][0])
# 转换为列表
return [eval(x) for x in self.MidCode]
def output(self, string):
# 输出
# 因为输出语句结构相同
# 所以放在同一个函数中
# 实际上,语法分析到得到语法树便结束了
self.pos += 1
if string == 'ORIGIN':
self.ORIGIN()
elif string == 'SCALE':
self.SCALE()
elif string == 'ROT':
self.ROT()
elif string == 'FOR':
self.FOR()
# 因为Python深复制与浅复制的问题
# 我直接使用了字符串
# 输出的时候转换为列表
# 可以将中间代码输出至文件
# 增加6+2图的上下层隔离性
self.MidCode.append(str((self.state_of_origin, self.state_of_scale,
self.state_of_rot, self.state_of_for, self.draw)))
else:
raise SyntaxError()
def ORIGIN(self):
self.matchstring('IS')
templist = self.matchparameter()
# 更改平移状态
self.state_of_origin[0] = eval(templist[0])
self.state_of_origin[1] = eval(templist[1])
def SCALE(self):
self.matchstring('IS')
templist = self.matchparameter()
# 更改缩放状态
self.state_of_scale[0] = eval(templist[0])
self.state_of_scale[1] = eval(templist[1])
def ROT(self):
self.matchstring('IS')
# 更改旋转状态
self.state_of_rot = eval(self.matchexpression())
def FOR(self):
self.matchstring('T')
self.matchstring('FROM')
# 更改FOR状态
self.state_of_for[0] = eval(self.matchexpression())
self.matchstring('TO')
self.state_of_for[1] = eval(self.matchexpression())
self.matchstring('STEP')
self.state_of_for[2] = eval(self.matchexpression())
self.matchstring('DRAW')
templist = self.matchparameter()
# 更改画图状态
self.draw[0] = templist[0]
self.draw[1] = templist[1]
def matchstring(self, string):
# 匹配一个特定的字符串
if self.dataflow[self.pos][0] == string:
self.pos += 1
else:
raise SyntaxError()
# matchparameter与matchexpression的区别
# 前者匹配双表达式
# 或者既可以匹配双表达式又可以匹配单表达式
# 分开原因:
# 考虑到ROT后面是单表达式而ORIGIN与SCALE后面都是算表达式
# 并且FOR后面既有单表达式又有双表达式
# 所以特此区分
def matchparameter(self):
# 匹配(E,E)
# 即匹配参数列表
# 如:
# ORIGIN IS (5,5);
# 后面的括号中包括括号的部分都是参数列表
temp = self.matchexpression() # 缓冲区
# 转换为列表[E,E]
if temp[0] == '(' and temp[-1] == ')':
temp = temp[1:-1].split(',')
else:
raise SyntaxError()
return temp
def matchexpression(self):
# 匹配E或者(E,E)
# 即匹配一个算数表达式
# 如
# 5*2-LN(3)
# (5*2-3,tan(0.1))
temp = '' # 缓冲区
while(self.dataflow[self.pos][0] != ';' and self.pos < self.length and self.dataflow[self.pos][1]['TYPE'] != 'KEYWORD'):
if self.dataflow[self.pos][1]['TYPE'] == 'FUNC':
temp += self.dataflow[self.pos][1]['FUNCTION']
elif self.dataflow[self.pos][1]['TYPE'] == 'CONST_ID':
temp += self.dataflow[self.pos][1]['VALUE']
else:
temp += self.dataflow[self.pos][0]
self.pos += 1
if self.dataflow[self.pos][0] == ';':
self.pos += 1 # 跳过结尾的分号
return temp
中间代码之后
解释器
所需的文件
test.py
测试文件(这个可以自己改)
createtable.py
创建符号表
scanner.py
扫描器
lexer.py
词法分析器
myparser.py
语法分析器+语义分析器+中间代码生成器+中间代码优化器
interpreter.py
解释器
main.py
主函数
主函数
文件名为main.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 4 11:12:45 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
import os
import interpreter
if __name__ == '__main__':
path = os.getcwd()
interpreter.Interpreter(path+r'\test.txt').create()
解释器主体
文件名为interpreter.py
,输入为中间代码,输出为绘制的图像
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 5 8:37:29 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 解释器
import myparser
import math
import turtle
import numpy as np
class Interpreter():
def __init__(self, path):
self.MidCode = myparser.Parser(path).analyze()
# 初始化画布
turtle.setup(width=1.0, height=1.0)
turtle.penup()
def create(self):
# 解析中间代码
for i in self.MidCode:
# 操作每一次画图
for T in np.arange(i[3][0], i[3][1], i[3][2]):
x = eval(i[4][0])*i[1][0]
y = eval(i[4][1])*i[1][1]
x_rot = x * math.cos(i[2])+y*math.sin(i[2])+i[0][0]
y_rot = y * math.cos(i[2])-x*math.sin(i[2])+i[0][1]
turtle.goto(x_rot, y_rot)
turtle.dot()
turtle.done()
编译器
所需的文件
test.py
测试文件(这个可以自己改)
createtable.py
创建符号表
scanner.py
扫描器
lexer.py
词法分析器
myparser.py
语法分析器+语义分析器+中间代码生成器+中间代码优化器
mycompile.py
编译器
main.py
主函数
output.py
目标代码(运行编译器的主函数后自动生成)
编译器
文件名为mycompile.py
,输入为中间代码,输出为目标代码output.py
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 4 11:12:17 2020
@author: FishPotatoChen
Copyright (c) 2020 FishPotatoChen All rights reserved.
"""
# 编译器
import myparser
class Compile():
def __init__(self, input_path, output_path):
self.path = output_path
self.MidCode = myparser.Parser(input_path).analyze()
with open(self.path, 'w', encoding='utf-8') as f:
# 增加头文件,即turtle库
f.write(
'''# @author: FishPotatoChen
# Copyright (c) 2020 FishPotatoChen All rights reserved.
import math
import turtle
import numpy as np
# 初始化画布
turtle.setup(width=1.0,height=1.0)
turtle.penup()
'''
)
def create(self):
with open(self.path, 'a', encoding='utf-8') as f:
# 操作每一次画图
for i in self.MidCode:
f.write(
'''
# 绘图
for T in np.arange('''+str(i[3][0])+''', '''+str(i[3][1])+''', '''+str(i[3][2])+'''):
x = '''+str(i[4][0])+'''*'''+str(i[1][0])+'''
y = '''+str(i[4][1])+'''*'''+str(i[1][1])+'''
x_rot = x*math.cos('''+str(i[2])+''')+y*math.sin('''+str(i[2])+''')+'''+str(i[0][0])+'''
y_rot = y*math.cos('''+str(i[2])+''')-x*math.sin('''+str(i[2])+''')+'''+str(i[0][1])+'''
turtle.goto(x_rot,y_rot)
turtle.dot()
'''
)
f.write('\nturtle.done()')
编译器使用方法
运行主函数后生成目标代码output.py
,运行目标代码得到绘制的图形