├── Interpreter4FPL ├── .idea │ ├── .name │ ├── encodings.xml │ ├── vcs.xml │ ├── modules.xml │ ├── misc.xml │ ├── Interpreter4FPL.iml │ └── workspace.xml ├── __pycache__ │ ├── expnode.cpython-35.pyc │ ├── mylexer.cpython-35.pyc │ ├── mypainter.cpython-35.pyc │ └── myparser.cpython-35.pyc ├── main.py ├── expnode.py ├── mypainter.py ├── mylexer.py └── myparser.py ├── test&pic ├── 五环.png ├── GUI.png ├── test0.jpg ├── 几何标志.png ├── 0testOK.png ├── NewGUI.png ├── test1.txt ├── 摆线&螺线 │ ├── 等角螺线.txt │ ├── 外摆线.txt │ ├── 内摆线.txt │ ├── 长幅圆外旋轮线.txt │ └── 心形螺线.txt ├── 奥运五环.txt ├── 0testOK.txt ├── test2.txt ├── 几何标志.txt └── test0.txt ├── docs ├── 函数绘图语言解释器.ppt ├── 编译原理 随课实验报告封面.docx └── 编译原理实验(绘图语言解释器)讲义.ppt ├── version2 ├── GUI.png ├── 0testOK.png ├── 0testOK.txt ├── README.md ├── main.py ├── mypainter.py ├── expnode.py ├── mylexer.py └── myparser.py ├── .idea ├── encodings.xml ├── vcs.xml ├── modules.xml ├── misc.xml ├── Interpreter.iml └── workspace.xml ├── version1 ├── README.md ├── t.py ├── test.py ├── grammer.py ├── Lexical.py ├── parser.py └── expression.py ├── version4 ├── README.md ├── main.py ├── expnode.py ├── mypainter.py ├── mylexer.py └── myparser.py ├── version3 ├── README.md ├── main.py ├── mypainter.py ├── expnode.py ├── mylexer.py └── myparser.py └── README.md /Interpreter4FPL/.idea/.name: -------------------------------------------------------------------------------- 1 | Interpreter4FPL -------------------------------------------------------------------------------- /test&pic/五环.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/五环.png -------------------------------------------------------------------------------- /docs/函数绘图语言解释器.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/docs/函数绘图语言解释器.ppt -------------------------------------------------------------------------------- /test&pic/GUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/GUI.png -------------------------------------------------------------------------------- /test&pic/test0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/test0.jpg -------------------------------------------------------------------------------- /test&pic/几何标志.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/几何标志.png -------------------------------------------------------------------------------- /version2/GUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/version2/GUI.png -------------------------------------------------------------------------------- /test&pic/0testOK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/0testOK.png -------------------------------------------------------------------------------- /test&pic/NewGUI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/test&pic/NewGUI.png -------------------------------------------------------------------------------- /version2/0testOK.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/version2/0testOK.png -------------------------------------------------------------------------------- /docs/编译原理 随课实验报告封面.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/docs/编译原理 随课实验报告封面.docx -------------------------------------------------------------------------------- /docs/编译原理实验(绘图语言解释器)讲义.ppt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/docs/编译原理实验(绘图语言解释器)讲义.ppt -------------------------------------------------------------------------------- /test&pic/test1.txt: -------------------------------------------------------------------------------- 1 | for t from 1 to 100 step 0.1 draw(1+sin(sqrt(2*3**2*2)-5*t)-sin(t), cos(t*24-e**sqrt(pi))); -------------------------------------------------------------------------------- /Interpreter4FPL/__pycache__/expnode.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/Interpreter4FPL/__pycache__/expnode.cpython-35.pyc -------------------------------------------------------------------------------- /Interpreter4FPL/__pycache__/mylexer.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/Interpreter4FPL/__pycache__/mylexer.cpython-35.pyc -------------------------------------------------------------------------------- /Interpreter4FPL/__pycache__/mypainter.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/Interpreter4FPL/__pycache__/mypainter.cpython-35.pyc -------------------------------------------------------------------------------- /Interpreter4FPL/__pycache__/myparser.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/izcat/Interpreter4FPL/HEAD/Interpreter4FPL/__pycache__/myparser.cpython-35.pyc -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Interpreter4FPL/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test&pic/摆线&螺线/等角螺线.txt: -------------------------------------------------------------------------------- 1 | //origin is (0, 35); 2 | --SCALE is ( 40,40); 3 | // 等角螺线 / 对数螺线 4 | // r = a*e**(b*t) 5 | for t from 0 to 6*pi step 0.01 draw (e**(0.2*t)*cos(t), e**(0.2*t)*sin(t)); -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /test&pic/摆线&螺线/外摆线.txt: -------------------------------------------------------------------------------- 1 | // 外摆线 2 | // x=(a+b)cosθ-bcos[(a+b)θ/b] 3 | // y=(a+b)sinθ-bsin[(a+b)θ/b] 4 | // 当a/b是有理数时,它是闭曲线 5 | for t from 0 to 10*pi step 0.01 draw (11*cos(t)-5*cos(11/5*t), 11*sin(t)-5*sin(11/5*t)); 6 | -------------------------------------------------------------------------------- /test&pic/摆线&螺线/内摆线.txt: -------------------------------------------------------------------------------- 1 | // 旋轮线(内摆线) 2 | // X=(a-b)cosθ+bcos[(a-b)θ/b] 3 | // Y=(a-b)sinθ-bsin[(a-b)θ/b] 4 | // 当a/b是有理数时,它是闭曲线 5 | for t from 0 to 4*pi step 0.01 draw (11*cos(t)-5*cos(11/5*t), 11*sin(t)-5*sin(11/5*t)); 6 | -------------------------------------------------------------------------------- /test&pic/摆线&螺线/长幅圆外旋轮线.txt: -------------------------------------------------------------------------------- 1 | for t from 0 to 10*pi step 0.01 draw (8*cos(t)-5*cos(8/3*t), 8*sin(t)-5*sin(8/3*t)) of red; 2 | 3 | for t from 0 to 10*pi step 0.01 draw (11*cos(t)-6*cos(11/5*t), 11*sin(t)-6*sin(11/5*t)) of red; -------------------------------------------------------------------------------- /Interpreter4FPL/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /version1/README.md: -------------------------------------------------------------------------------- 1 | # Version 1 2 | 完成词法分析 3 | 4 | ## 词法分析器功能 5 | - 输入:函数绘图语言源程序,以字符串形式传递给 `Lexer` 参数 6 | - 输出:返回源程序进行词法分析得到的全部 Token,类型为列表 7 | 8 | ## Update: 9 | 此版本 `Lexer` 会无法正确识别带小数点的浮点数!在version2中的 `Lexer` 才是正确写法! 10 | -------------------------------------------------------------------------------- /version1/t.py: -------------------------------------------------------------------------------- 1 | Points = dict(X=[], Y=[]) 2 | print(Points) 3 | print(Points['X']) 4 | 5 | a = 100 6 | 7 | def test1(): 8 | # print(a) 9 | a = 1 10 | 11 | def test2(): 12 | a = 2 13 | 14 | test2() 15 | print(a) 16 | test1() 17 | print(a) -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /Interpreter4FPL/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Interpreter4FPL/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | -------------------------------------------------------------------------------- /version4/README.md: -------------------------------------------------------------------------------- 1 | # Version 4 2 | 3 | 改进内容: 4 | - 在version3的基础上,分离语法分析器 `myparser` 模块与语义分析器 `mypainter` 模块 5 | - 重新设计了语法分析过程中的运行提示,增加了层级level参数,使递归调用的输出信息更友好 6 | - 重写了 `mypainter` 模块,改用面向对象方式 7 | - `Painter` 类 接收绘图源程序代码,调用语法分析器 `myparser.Parser` 8 | - 将获取到的语法树交给 `analyse` 方法进行语义分析 9 | - 语义分析完成后,`showPic` 执行绘图 10 | - 改进 `main` 程序入口模块,增加了打开文件选项,可以直接选择写好绘图源程序打开 11 | -------------------------------------------------------------------------------- /test&pic/奥运五环.txt: -------------------------------------------------------------------------------- 1 | origin is (0, 35); 2 | SCALE is ( 40,40); 3 | for t from 0 to 2*pi step 0.01 draw (sin(t), cos(t)); 4 | for t from 0 to 2*pi step 0.01 draw (-2.2+sin(t), cos(t)) of blue; 5 | for t from 0 to 2*pi step 0.01 draw (2.2+sin(t), cos(t)) of Red; 6 | for t from 0 to 2*pi step 0.01 draw (-1.1+sin(t), -1.1+cos(t)) of YELLOW; 7 | for t from 0 to 2*pi step 0.01 draw (1.1+sin(t), -1.1+cos(t)) of GREEN; -------------------------------------------------------------------------------- /test&pic/0testOK.txt: -------------------------------------------------------------------------------- 1 | ORigin is (-30, 0); 2 | SCALE is ( 20, 25); 3 | for t from 0 to 2*pi step 0.01 draw (sin(t), cos(t)); 4 | 5 | SCALE is ( 30, 20); 6 | for t from -1 to 1 step 0.01 draw (2, t); 7 | FOR t from 0 to 1 step 0.01 draw (2+t, t); 8 | for t from -1 to 1 step 0.01 draw (2, t); 9 | FOR t from 0 to 1 step 0.01 draw (2+t, -t); 10 | 11 | for t from 0 to 2*pi step 0.01 draw (1+3*sin(t), 3*cos(t)); 12 | -------------------------------------------------------------------------------- /version2/0testOK.txt: -------------------------------------------------------------------------------- 1 | ORigin is (-30, 0); 2 | SCALE is ( 20, 25); 3 | for t from 0 to 2*pi step 0.01 draw (sin(t), cos(t)); 4 | 5 | SCALE is ( 30, 20); 6 | for t from -1 to 1 step 0.01 draw (2, t); 7 | FOR t from 0 to 1 step 0.01 draw (2+t, t); 8 | for t from -1 to 1 step 0.01 draw (2, t); 9 | FOR t from 0 to 1 step 0.01 draw (2+t, -t); 10 | 11 | for t from 0 to 2*pi step 0.01 draw (1+3*sin(t), 3*cos(t)); 12 | -------------------------------------------------------------------------------- /version2/README.md: -------------------------------------------------------------------------------- 1 | # Version 2 2 | 已实现实验要求的函数绘图语言的全部功能 3 | 4 | 解释器执行的第一个程序结果(显示 'OK' 字样): 5 | 6 | ![图片](https://github.com/izcat/Interpreter4FPL/blob/master/version2/0testOK.png "结果") 7 | 8 | 9 | 10 | ## 修复Bug 11 | 由于新加入主界面的模块 `main.py` 无法正常 import 写好的 `parser`模块,因为会与 Python 的同名库冲突。 12 | 将全部模块改名,加上'my'前缀 13 | ## 不足 14 | 词法分析器与语义分析器没有完全分离,本解释器在语法分析阶段,未生成源代码的整体语法树,直接将绘制的点信息交给painter处理 15 | 缺少异常处理机制 16 | 没有完全面向对象开发 17 | 18 | -------------------------------------------------------------------------------- /Interpreter4FPL/.idea/Interpreter4FPL.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | -------------------------------------------------------------------------------- /test&pic/test2.txt: -------------------------------------------------------------------------------- 1 | 2 | ROT IS -pi/2; 3 | for t from 0 to pi step 0.001 draw (t*cos(t), t*sin(t)) of red; 4 | for t from 0 to pi step 0.001 draw (t*cos(t), -t*sin(t)); 5 | 6 | ROT IS -pi/2+pi/12; 7 | for t from 0 to pi step 0.001 draw (t*cos(t), t*sin(t)) of yellow; 8 | for t from 0 to pi step 0.001 draw (t*cos(t), -t*sin(t)); 9 | 10 | ROT IS -pi/2-pi/12; 11 | for t from 0 to pi step 0.001 draw (t*cos(t), t*sin(t)) of yellow; 12 | for t from 0 to pi step 0.001 draw (t*cos(t), -t*sin(t)); 13 | -------------------------------------------------------------------------------- /.idea/Interpreter.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /test&pic/摆线&螺线/心形螺线.txt: -------------------------------------------------------------------------------- 1 | // 阿基米德螺线 2 | // r = a + b*t 3 | ROT IS 0; 4 | for t from pi/2 to 3/2*pi step 0.001 draw (t*cos(t), t*sin(t)) of blue; 5 | for t from pi/2 to 3/2*pi step 0.001 draw (-t*cos(t), t*sin(t)); 6 | 7 | ROT IS -pi/2; 8 | for t from 0 to pi step 0.001 draw (t*cos(t), t*sin(t)) of yellow; 9 | for t from 0 to pi step 0.001 draw (t*cos(t), -t*sin(t)); 10 | 11 | // 费马螺线 12 | // r = a*sqrt(t) 13 | ROT IS -pi/2; 14 | for t from 0 to pi step 0.001 draw (2*sqrt(t)*cos(t), 2*sqrt(t)*sin(t)) of red; 15 | for t from 0 to pi step 0.001 draw (2*sqrt(t)*cos(t), -2*sqrt(t)*sin(t)); 16 | 17 | -------------------------------------------------------------------------------- /version1/test.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | class TokenType(Enum): 4 | ORIGIN = "ORIGIN" 5 | SCALE = "SCALE" 6 | ROT = "ROT" 7 | IS = "IS" 8 | TO = "TO" 9 | STEP = "STEP" 10 | DRAW = "DRAW" 11 | FOR = "FOR" 12 | FROM = "FROM" 13 | T = "T" 14 | SEMICO = ';' 15 | L_BRACKET = '(' 16 | R_BRACKET = ')' 17 | COMMA = ',' 18 | PLUS = '+' 19 | MINUS = '-' 20 | MUL = '*' 21 | DIV = '/' 22 | POWER = '**' 23 | FUNC = "FUNCTION" 24 | CONST_ID = "CONST_ID" 25 | NONTOKEN = 22 26 | ERRTOKEN = 23 27 | 28 | print(TokenType) -------------------------------------------------------------------------------- /version3/README.md: -------------------------------------------------------------------------------- 1 | # Version 3 2 | 3 | 本次版本不涉及代码修复和功能修改,version2可以正常运行标准绘图源程序 4 | 5 | 在完成作业要求的基础上,本次更新增加了**自定义颜色**的语法 6 | 即 7 | **FOR T FROM T_start TO T_end STEP T_step DRAW (Point_x, Point_Y)** 8 | **[OF (RED|GREEN|BLUE|YELLOW|BLACK)]** 9 | 10 | 更改内容如下 11 | - `mylexer` 模块新增记号类别 `TokenType` : **OF**,**RED**,**GREEN**,**BLUE**,**YELLOW**, **BLACK** 12 | - `mylexer` 模块新增字符与记号的字典映射 `TokenTypeDict` : 13 | - OF = Token(TokenType.OF, "OF") 14 | - RED = Token(TokenType.COLOR, "RED") 15 | - GREEN = Token(TokenType.COLOR, "GREEN") 16 | - BLUE = Token(TokenType.COLOR, "BLUE") 17 | - YELLOW = Token(TokenType.COLOR, "YELLOW") 18 | - BLACK = Token(TokenType.COLOR, "BLACK") 19 | - `myparser` 模块作少量改动,`ForStatement` 方法新增颜色识别语句,将获取颜色结果传给 `Painter` 20 | - `mypainter` 模块内的 `paint` 方法 21 | - plt.plot(Painter.Points['X'], Painter.Points['Y'], '.'+Draw_color) 22 | - 参考自 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 23 | - 第三个参数 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 24 | - '.' 点标记 ',' 像素点 25 | 26 | -------------------------------------------------------------------------------- /version2/main.py: -------------------------------------------------------------------------------- 1 | from tkinter import Tk 2 | from tkinter import Text 3 | from tkinter import Menu 4 | 5 | # parse.py与python包名冲突 6 | from mylexer import Lexer 7 | from myparser import Parser 8 | 9 | 10 | textBox = None 11 | 12 | def callLexer(): 13 | # '1.0' 第一行第一列开始 14 | str = textBox.get('1.0', "end") 15 | # Lexer(string, show=False) 16 | # show=True显示分析过程 17 | tokens = Lexer(str, show=True) 18 | 19 | def callParser(): 20 | str = textBox.get('1.0', "end") 21 | # Parser(string, show=False) 22 | # show=True显示分析过程 23 | Parser(str, show=True) 24 | 25 | def callPainter(): 26 | str = textBox.get('1.0', "end") 27 | # Parser(string, show=False) 28 | # paint=True函数绘图 29 | Parser(str, paint=True) 30 | 31 | def main(): 32 | tk = Tk() 33 | tk.title("izcat's Interpreter for Functional Painting Language") 34 | tk.geometry("800x600") 35 | 36 | menuBar = Menu(tk) 37 | menuBar.add_command(label="词法分析", command=callLexer) 38 | menuBar.add_command(label="语法分析", command=callParser) 39 | menuBar.add_command(label="函数绘图", command=callPainter) 40 | tk.config(menu=menuBar) 41 | 42 | global textBox 43 | textBox = Text(tk, width=800, height=300) 44 | textBox.pack() 45 | 46 | tk.mainloop() 47 | 48 | if __name__=='__main__': 49 | main() 50 | 51 | -------------------------------------------------------------------------------- /test&pic/几何标志.txt: -------------------------------------------------------------------------------- 1 | 2 | ROT IS pi/12; 3 | for t from 0 to 1 step 0.01 draw (0, t) of blue; 4 | for t from 0 to 1 step 0.01 draw (1, t); 5 | for t from 0 to 1 step 0.01 draw (t, 0); 6 | for t from 0 to 1 step 0.01 draw (t, 1); 7 | 8 | 9 | ROT IS pi/12+pi/3; 10 | for t from 0 to 1 step 0.01 draw (0, t); 11 | for t from 0 to 1 step 0.01 draw (1, t); 12 | for t from 0 to 1 step 0.01 draw (t, 0); 13 | for t from 0 to 1 step 0.01 draw (t, 1); 14 | 15 | 16 | ROT IS pi/12+pi/3*2; 17 | for t from 0 to 1 step 0.01 draw (0, t); 18 | for t from 0 to 1 step 0.01 draw (1, t); 19 | for t from 0 to 1 step 0.01 draw (t, 0); 20 | for t from 0 to 1 step 0.01 draw (t, 1); 21 | 22 | 23 | ROT IS pi/12+pi/3*3; 24 | for t from 0 to 1 step 0.01 draw (0, t); 25 | for t from 0 to 1 step 0.01 draw (1, t); 26 | for t from 0 to 1 step 0.01 draw (t, 0); 27 | for t from 0 to 1 step 0.01 draw (t, 1); 28 | 29 | 30 | ROT IS pi/12+pi/3*4; 31 | for t from 0 to 1 step 0.01 draw (0, t); 32 | for t from 0 to 1 step 0.01 draw (1, t); 33 | for t from 0 to 1 step 0.01 draw (t, 0); 34 | for t from 0 to 1 step 0.01 draw (t, 1); 35 | 36 | 37 | ROT IS pi/12+pi/3*5; 38 | for t from 0 to 1 step 0.01 draw (0, t); 39 | for t from 0 to 1 step 0.01 draw (1, t); 40 | for t from 0 to 1 step 0.01 draw (t, 0); 41 | for t from 0 to 1 step 0.01 draw (t, 1); 42 | -------------------------------------------------------------------------------- /version3/main.py: -------------------------------------------------------------------------------- 1 | from tkinter import Tk 2 | from tkinter import Text 3 | from tkinter import Menu 4 | 5 | # parse.py与python包名冲突 6 | from mylexer import Lexer 7 | from myparser import Parser 8 | 9 | 10 | textBox = None 11 | 12 | def callLexer(): 13 | # '1.0' 第一行第一列开始 14 | str = textBox.get('1.0', "end") 15 | # Lexer(string, show=False) 16 | # show=True显示分析过程 17 | tokens = Lexer(str, show=True) 18 | 19 | def callParser(): 20 | str = textBox.get('1.0', "end") 21 | # Parser(string, show=False) 22 | # show=True显示分析过程 23 | Parser(str, show=True) 24 | 25 | def callPainter(): 26 | str = textBox.get('1.0', "end") 27 | # Parser(string, show=False) 28 | # paint=True函数绘图 29 | Parser(str, paint=True) 30 | 31 | def main(): 32 | tk = Tk() 33 | tk.title("izcat's Interpreter for Functional Painting Language") 34 | tk.geometry("800x600") 35 | 36 | menuBar = Menu(tk) 37 | menuOpt = Menu(menuBar, tearoff=0) 38 | menuOpt.add_command(label="词法分析", command=callLexer) 39 | menuOpt.add_command(label="语法分析", command=callParser) 40 | menuOpt.add_command(label="函数绘图", command=callPainter) 41 | menuOpt.add_separator() 42 | menuBar.add_cascade(label="选择操作", menu=menuOpt) 43 | tk.config(menu=menuBar) 44 | 45 | global textBox 46 | textBox = Text(tk, width=800, height=300) 47 | textBox.pack() 48 | 49 | tk.mainloop() 50 | 51 | if __name__=='__main__': 52 | main() 53 | 54 | -------------------------------------------------------------------------------- /test&pic/test0.txt: -------------------------------------------------------------------------------- 1 | -- 十字线 2 | ORIGIN IS (400, 400); 3 | FOR T FROM -350 TO 350 STEP 1 DRAW (T, 0); 4 | FOR T FROM -350 TO 350 STEP 1 DRAW (0, T); 5 | 6 | 7 | ------------------------------------------------------------ 8 | 9 | -- 左上角 10 | ORIGIN IS (200,550); 11 | SCALE IS (80,80); 12 | ROT IS 0; 13 | FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (COS(T), SIN(T)) of YELLOW; 14 | FOR T FROM 0 TO 20*PI STEP PI/50 DRAW ((1-1/(10/7))*COS(T)+1/(10/7)*COS(-T*((10/7)-1)), (1-1/(10/7))*SIN(T)+1/(10/7)*SIN(-T*((10/7)-1))); 15 | 16 | ------------------------------------------------------------ 17 | 18 | -- 右上角 19 | ORIGIN IS (600,550); 20 | SCALE IS (80,80/3); 21 | 22 | ROT IS PI/2+0*PI/3; 23 | FOR T FROM -PI TO PI STEP PI/50 DRAW (COS(T),SIN(T)) of RED; 24 | 25 | ROT IS PI/2+2*PI/3; 26 | FOR T FROM -PI TO PI STEP PI/50 DRAW (COS(T),SIN(T)); 27 | 28 | ROT IS PI/2-2*PI/3; 29 | FOR T FROM -PI TO PI STEP PI/50 DRAW (COS(T),SIN(T)); 30 | 31 | 32 | ------------------------------------------------------------ 33 | 34 | -- 左下角 35 | SCALE IS (20, 30); 36 | ROT IS 0; 37 | ORIGIN IS (200-20*PI, 200); 38 | FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (T, SIN(T)) of GREEN; 39 | ORIGIN IS (200-20*PI, 250); 40 | FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (T, SIN(T)); 41 | ORIGIN IS (200-20*PI, 300); 42 | FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (T, SIN(T)); 43 | 44 | ------------------------------------------------------------ 45 | 46 | --右下角 47 | ORIGIN IS (600,250); 48 | ROT IS 0; 49 | 50 | SCALE IS (50, 50); 51 | FOR T FROM 0 TO 2*PI STEP PI/100 DRAW(COS(T), SIN(T)) of BLUE; 52 | 53 | SCALE IS (100, 100); 54 | FOR T FROM 0 TO 2*PI STEP PI/200 DRAW(COS(T), SIN(T)); 55 | -------------------------------------------------------------------------------- /version4/main.py: -------------------------------------------------------------------------------- 1 | from tkinter import Tk 2 | from tkinter import Text 3 | from tkinter import Menu 4 | from tkinter import filedialog 5 | import os 6 | 7 | # parse.py与python包名冲突 8 | from mylexer import Lexer 9 | from myparser import Parser 10 | from mypainter import Painter 11 | 12 | 13 | textBox = None 14 | 15 | def callLexer(): 16 | # '1.0' 第一行第一列开始 17 | str = textBox.get('1.0', "end") 18 | # Lexer(string, show=False) 19 | # show=True显示分析过程 20 | Lexer(str, show=True) 21 | 22 | def callParser(): 23 | str = textBox.get('1.0', "end") 24 | # Parser(string, show=False) 25 | # show=True显示分析过程 26 | Parser(str, show=True) 27 | 28 | def callPainter(): 29 | str = textBox.get('1.0', "end") 30 | # 函数绘图 31 | Painter(str) 32 | 33 | # 打开文件 显示到textBox上 34 | def openFile(): 35 | global textBox 36 | filePath = filedialog.askopenfilename(title=u'选择文件', 37 | initialdir=(os.path.expanduser(r"文件路径"))) 38 | txtFile = open(filePath) 39 | content = txtFile.read() 40 | textBox.delete(0.0, "end") 41 | textBox.insert("insert", content) 42 | 43 | 44 | def main(): 45 | tk = Tk() 46 | tk.title("izcat's Interpreter for Functional Painting Language") 47 | tk.geometry("800x600") 48 | 49 | menuBar = Menu(tk) 50 | menuBar.add_command(label="文件", command=openFile) 51 | 52 | menuOpt = Menu(menuBar, tearoff=0) 53 | menuOpt.add_command(label="词法分析", command=callLexer) 54 | menuOpt.add_command(label="语法分析", command=callParser) 55 | menuOpt.add_command(label="函数绘图", command=callPainter) 56 | menuOpt.add_separator() 57 | menuBar.add_cascade(label="选择", menu=menuOpt) 58 | tk.config(menu=menuBar) 59 | 60 | global textBox 61 | textBox = Text(tk, width=800, height=300) 62 | textBox.pack() 63 | 64 | tk.mainloop() 65 | 66 | if __name__=='__main__': 67 | main() 68 | 69 | -------------------------------------------------------------------------------- /version2/mypainter.py: -------------------------------------------------------------------------------- 1 | from expnode import * 2 | import matplotlib.pyplot as plt 3 | import math 4 | 5 | class Painter(): 6 | orx = 0.0 7 | ory = 0.0 8 | scx = 1.0 9 | scy = 1.0 10 | ang = 0.0 11 | # 绘制的点横坐标 12 | Points = dict(X=[], Y=[]) 13 | # xlist = [] # 绘制的点横坐标 14 | # ylist = [] # 绘制的点纵坐标 15 | # 16 | def set(Origin_x=0.0, Origin_y=0.0, Scale_x=1.0, Scale_y=1.0, Rot_angle=0.0): 17 | Painter.orx = Origin_x 18 | Painter.ory = Origin_y 19 | Painter.scx = Scale_x 20 | Painter.scy = Scale_y 21 | Painter.ang = Rot_angle 22 | 23 | def paint(T_start, T_end, T_step, Point_x, Point_y): 24 | # for T_value in range(T_start, T_end, T_step): 25 | T_value = T_start 26 | 27 | while T_value<=T_end: 28 | ExpNode.T_value = T_value 29 | x = Point_x.getValue() 30 | y = Point_y.getValue() 31 | 32 | # print("(%f, %f)" % (x, y)) 33 | 34 | # 坐标变换 35 | # 比例变换 36 | x, y = x*Painter.scx, y*Painter.scy 37 | # 旋转变换 38 | x, y = x*math.cos(Painter.ang) + y*math.sin(Painter.ang), y*math.cos(Painter.ang) - x*math.sin(Painter.ang) 39 | # 平移变换 40 | x, y = x+Painter.orx, y+Painter.ory 41 | 42 | # points.append((x, y)) 43 | Painter.Points['X'].append(x) 44 | Painter.Points['Y'].append(y) 45 | 46 | # print("(%f, %f)" % (x, y)) 47 | T_value += T_step 48 | 49 | def showPic(): 50 | plt.xlim(xmax=100, xmin=-100) 51 | plt.ylim(ymax=100, ymin=-100) 52 | # plt.plot(x,y,format_string,**kwargs) 53 | # 第三个参数 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 54 | # 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 55 | # '.' 点标记 ',' 像素点 56 | plt.plot(Painter.Points['X'], Painter.Points['Y'], 'k.') 57 | plt.show() 58 | 59 | # 清空点 下次重新绘图 60 | Painter.Points['X'].clear() 61 | Painter.Points['Y'].clear() 62 | 63 | -------------------------------------------------------------------------------- /version3/mypainter.py: -------------------------------------------------------------------------------- 1 | from expnode import * 2 | import matplotlib.pyplot as plt 3 | import math 4 | 5 | class Painter(): 6 | orx = 0.0 7 | ory = 0.0 8 | scx = 1.0 9 | scy = 1.0 10 | ang = 0.0 11 | # 绘制的点横坐标 12 | Points = dict(X=[], Y=[]) 13 | # xlist = [] # 绘制的点横坐标 14 | # ylist = [] # 绘制的点纵坐标 15 | # 16 | def set(Origin_x=0.0, Origin_y=0.0, Scale_x=1.0, Scale_y=1.0, Rot_angle=0.0): 17 | Painter.orx = Origin_x 18 | Painter.ory = Origin_y 19 | Painter.scx = Scale_x 20 | Painter.scy = Scale_y 21 | Painter.ang = Rot_angle 22 | Painter.Points['X'].clear() 23 | Painter.Points['Y'].clear() 24 | 25 | def paint(T_start, T_end, T_step, Point_x, Point_y, Draw_color): 26 | # for T_value in range(T_start, T_end, T_step): 27 | T_value = T_start 28 | 29 | while T_value<=T_end: 30 | ExpNode.T_value = T_value 31 | x = Point_x.getValue() 32 | y = Point_y.getValue() 33 | 34 | # print("(%f, %f)" % (x, y)) 35 | 36 | # 坐标变换 37 | # 比例变换 38 | x, y = x*Painter.scx, y*Painter.scy 39 | # 旋转变换 40 | x, y = x*math.cos(Painter.ang) + y*math.sin(Painter.ang), y*math.cos(Painter.ang) - x*math.sin(Painter.ang) 41 | # 平移变换 42 | x, y = x+Painter.orx, y+Painter.ory 43 | 44 | # points.append((x, y)) 45 | Painter.Points['X'].append(x) 46 | Painter.Points['Y'].append(y) 47 | 48 | # print("(%f, %f)" % (x, y)) 49 | T_value += T_step 50 | 51 | # plt.plot(x,y,format_string,**kwargs) 52 | # 第三个参数 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 53 | # 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 54 | # '.' 点标记 ',' 像素点 55 | plt.plot(Painter.Points['X'], Painter.Points['Y'], '.'+Draw_color) 56 | 57 | def showPic(): 58 | # plt.xlim(xmax=100, xmin=-100) 59 | # plt.ylim(ymax=100, ymin=-100) 60 | # 保持纵横比例 61 | plt.axis('equal') 62 | 63 | plt.show() 64 | 65 | # 清空点 下次重新绘图 66 | Painter.Points['X'].clear() 67 | Painter.Points['Y'].clear() 68 | 69 | -------------------------------------------------------------------------------- /Interpreter4FPL/main.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | # @Time : 2019/12/6 12:31 3 | # @Author : izcat 4 | # @Site : cnblogs.com/izcat 5 | # @File : main.py 6 | # @Software : PyCharm 7 | # @Desc : 项目GUI与程序入口 8 | 9 | from tkinter import Tk 10 | from tkinter import Text 11 | from tkinter import Menu 12 | from tkinter import filedialog 13 | import os 14 | 15 | # parse.py与python包名冲突 16 | from mylexer import Lexer 17 | from myparser import Parser 18 | from mypainter import Painter 19 | 20 | 21 | textBox = None 22 | 23 | def callLexer(): 24 | # '1.0' 第一行第一列开始 25 | str = textBox.get('1.0', "end") 26 | # Lexer(string, show=False) 27 | # show=True显示分析过程 28 | Lexer(str, show=True) 29 | 30 | def callParser(): 31 | str = textBox.get('1.0', "end") 32 | # Parser(string, show=False) 33 | # show=True显示分析过程 34 | Parser(str, show=True) 35 | 36 | def callPainter(): 37 | str = textBox.get('1.0', "end") 38 | # 函数绘图 39 | Painter(str) 40 | 41 | # 打开文件 显示到textBox上 42 | def openFile(): 43 | global textBox 44 | filePath = filedialog.askopenfilename(title=u'选择文件', 45 | initialdir=(os.path.expanduser(r"文件路径"))) 46 | txtFile = open(filePath) 47 | content = txtFile.read() 48 | textBox.delete(0.0, "end") 49 | textBox.insert("insert", content) 50 | 51 | 52 | def main(): 53 | tk = Tk() 54 | tk.title("izcat's Interpreter for Functional Painting Language") 55 | tk.geometry("800x600") 56 | 57 | menuBar = Menu(tk) 58 | menuBar.add_command(label="文件", command=openFile) 59 | 60 | menuOpt = Menu(menuBar, tearoff=0) 61 | menuOpt.add_command(label="词法分析", command=callLexer) 62 | menuOpt.add_command(label="语法分析", command=callParser) 63 | menuOpt.add_command(label="函数绘图", command=callPainter) 64 | menuOpt.add_separator() 65 | menuBar.add_cascade(label="选择", menu=menuOpt) 66 | tk.config(menu=menuBar) 67 | 68 | global textBox 69 | textBox = Text(tk, width=800, height=300) 70 | textBox.pack() 71 | 72 | tk.mainloop() 73 | 74 | if __name__=='__main__': 75 | main() 76 | 77 | -------------------------------------------------------------------------------- /version2/expnode.py: -------------------------------------------------------------------------------- 1 | from mylexer import Token 2 | from mylexer import TokenType 3 | 4 | class ExpNode: 5 | T_value = 0.0 6 | 7 | def __init__(self, token, left=None, right=None): 8 | self.token = token 9 | self.lson = left 10 | self.rson = right 11 | def addson(self, son): 12 | if self.lson==None: 13 | self.lson = son 14 | return self 15 | elif self.rson==None: 16 | self.rson = son 17 | return self 18 | else: 19 | print("Cannot add son!") 20 | exit(-1) 21 | 22 | def getValue(self): 23 | # 叶子节点 24 | if self.lson==None and self.rson==None: 25 | if self.token.tokenType==TokenType.CONST_ID: 26 | return self.token.value 27 | elif self.token.tokenType==TokenType.T: 28 | return ExpNode.T_value 29 | else: 30 | print("Expression Error") 31 | exit(-1) 32 | 33 | # 只有左子树 函数节点 or +5 or -5 34 | elif self.rson==None: 35 | if self.token.tokenType==TokenType.PLUS: 36 | return self.lson.getValue() 37 | elif self.token.tokenType==TokenType.MINUS: 38 | return -self.lson.getValue() 39 | elif self.token.tokenType==TokenType.FUNC: 40 | return self.token.funcPtr(self.lson.getValue()) 41 | else: 42 | print("Expression Error") 43 | exit(-1) 44 | # 只有右子树 45 | # elif self.lson==None: 46 | # if self.token.tokenType==TokenType.PLUS: 47 | # return self.rson.getValue() 48 | # elif self.token.tokenType==TokenType.MINUS: 49 | # return -self.rson.getValue() 50 | # elif self.token.tokenType==TokenType.FUNC: 51 | # return self.token.funcptr(self.rson.getValue()) 52 | # else: 53 | # print("Expression Error") 54 | else: 55 | if self.token.tokenType==TokenType.PLUS: 56 | return self.lson.getValue() + self.rson.getValue() 57 | elif self.token.tokenType==TokenType.MINUS: 58 | return self.lson.getValue() - self.rson.getValue() 59 | elif self.token.tokenType==TokenType.MUL: 60 | return self.lson.getValue() * self.rson.getValue() 61 | elif self.token.tokenType==TokenType.DIV: 62 | return self.lson.getValue() / self.rson.getValue() 63 | elif self.token.tokenType==TokenType.POWER: 64 | return self.lson.getValue() ** self.rson.getValue() 65 | else: 66 | print("Expression Error") 67 | exit(-1) 68 | 69 | def dfs(self, depth=0): 70 | if self.lson!=None: 71 | self.lson.dfs(depth+1) 72 | if self.rson!=None: 73 | self.rson.dfs(depth+1) 74 | 75 | print("Depth %d" % depth) 76 | self.token.show() -------------------------------------------------------------------------------- /version3/expnode.py: -------------------------------------------------------------------------------- 1 | from mylexer import Token 2 | from mylexer import TokenType 3 | 4 | class ExpNode: 5 | T_value = 0.0 6 | 7 | def __init__(self, token, left=None, right=None): 8 | self.token = token 9 | self.lson = left 10 | self.rson = right 11 | def addson(self, son): 12 | if self.lson==None: 13 | self.lson = son 14 | return self 15 | elif self.rson==None: 16 | self.rson = son 17 | return self 18 | else: 19 | print("Cannot add son!") 20 | exit(-1) 21 | 22 | def getValue(self): 23 | # 叶子节点 24 | if self.lson==None and self.rson==None: 25 | if self.token.tokenType==TokenType.CONST_ID: 26 | return self.token.value 27 | elif self.token.tokenType==TokenType.T: 28 | return ExpNode.T_value 29 | else: 30 | print("Expression Error") 31 | exit(-1) 32 | 33 | # 只有左子树 函数节点 or +5 or -5 34 | elif self.rson==None: 35 | if self.token.tokenType==TokenType.PLUS: 36 | return self.lson.getValue() 37 | elif self.token.tokenType==TokenType.MINUS: 38 | return -self.lson.getValue() 39 | elif self.token.tokenType==TokenType.FUNC: 40 | return self.token.funcPtr(self.lson.getValue()) 41 | else: 42 | print("Expression Error") 43 | exit(-1) 44 | # 只有右子树 45 | # elif self.lson==None: 46 | # if self.token.tokenType==TokenType.PLUS: 47 | # return self.rson.getValue() 48 | # elif self.token.tokenType==TokenType.MINUS: 49 | # return -self.rson.getValue() 50 | # elif self.token.tokenType==TokenType.FUNC: 51 | # return self.token.funcptr(self.rson.getValue()) 52 | # else: 53 | # print("Expression Error") 54 | else: 55 | if self.token.tokenType==TokenType.PLUS: 56 | return self.lson.getValue() + self.rson.getValue() 57 | elif self.token.tokenType==TokenType.MINUS: 58 | return self.lson.getValue() - self.rson.getValue() 59 | elif self.token.tokenType==TokenType.MUL: 60 | return self.lson.getValue() * self.rson.getValue() 61 | elif self.token.tokenType==TokenType.DIV: 62 | return self.lson.getValue() / self.rson.getValue() 63 | elif self.token.tokenType==TokenType.POWER: 64 | return self.lson.getValue() ** self.rson.getValue() 65 | else: 66 | print("Expression Error") 67 | exit(-1) 68 | 69 | def dfs(self, depth=0): 70 | ret = ' '*depth + self.token.lexeme + '\n' 71 | if self.lson!=None: 72 | ret += self.lson.dfs(depth+1) 73 | if self.rson!=None: 74 | ret += self.rson.dfs(depth+1) 75 | 76 | return ret 77 | # print("Depth %d" % depth) 78 | # self.token.show() -------------------------------------------------------------------------------- /version4/expnode.py: -------------------------------------------------------------------------------- 1 | from mylexer import Token 2 | from mylexer import TokenType 3 | 4 | class ExpNode: 5 | T_value = 0.0 6 | 7 | def __init__(self, token, left=None, right=None): 8 | self.token = token 9 | self.lson = left 10 | self.rson = right 11 | def addson(self, son): 12 | if self.lson==None: 13 | self.lson = son 14 | return self 15 | elif self.rson==None: 16 | self.rson = son 17 | return self 18 | else: 19 | print("Cannot add son!") 20 | exit(-1) 21 | 22 | def getValue(self): 23 | # 叶子节点 24 | if self.lson==None and self.rson==None: 25 | if self.token.tokenType==TokenType.CONST_ID: 26 | return self.token.value 27 | elif self.token.tokenType==TokenType.T: 28 | return ExpNode.T_value 29 | else: 30 | print("Expression Error") 31 | exit(-1) 32 | 33 | # 只有左子树 函数节点 or +5 or -5 34 | elif self.rson==None: 35 | if self.token.tokenType==TokenType.PLUS: 36 | return self.lson.getValue() 37 | elif self.token.tokenType==TokenType.MINUS: 38 | return -self.lson.getValue() 39 | elif self.token.tokenType==TokenType.FUNC: 40 | return self.token.funcPtr(self.lson.getValue()) 41 | else: 42 | print("Expression Error") 43 | exit(-1) 44 | # 只有右子树 45 | # elif self.lson==None: 46 | # if self.token.tokenType==TokenType.PLUS: 47 | # return self.rson.getValue() 48 | # elif self.token.tokenType==TokenType.MINUS: 49 | # return -self.rson.getValue() 50 | # elif self.token.tokenType==TokenType.FUNC: 51 | # return self.token.funcptr(self.rson.getValue()) 52 | # else: 53 | # print("Expression Error") 54 | else: 55 | if self.token.tokenType==TokenType.PLUS: 56 | return self.lson.getValue() + self.rson.getValue() 57 | elif self.token.tokenType==TokenType.MINUS: 58 | return self.lson.getValue() - self.rson.getValue() 59 | elif self.token.tokenType==TokenType.MUL: 60 | return self.lson.getValue() * self.rson.getValue() 61 | elif self.token.tokenType==TokenType.DIV: 62 | return self.lson.getValue() / self.rson.getValue() 63 | elif self.token.tokenType==TokenType.POWER: 64 | return self.lson.getValue() ** self.rson.getValue() 65 | else: 66 | print("Expression Error") 67 | exit(-1) 68 | 69 | def dfs(self, depth=0): 70 | ret = ' '*depth + self.token.lexeme + '\n' 71 | if self.lson!=None: 72 | ret += self.lson.dfs(depth+1) 73 | if self.rson!=None: 74 | ret += self.rson.dfs(depth+1) 75 | 76 | return ret 77 | # print("Depth %d" % depth) 78 | # self.token.show() -------------------------------------------------------------------------------- /version4/mypainter.py: -------------------------------------------------------------------------------- 1 | from expnode import * 2 | from myparser import Parser 3 | import matplotlib.pyplot as plt 4 | import math 5 | 6 | class Painter: 7 | def __init__(self, string): 8 | self.orx = 0.0 9 | self.ory = 0.0 10 | self.scx = 1.0 11 | self.scy = 1.0 12 | self.ang = 0.0 13 | self.Draw_color = 'k' 14 | statements = Parser(string) 15 | # print(len(statements)) 16 | 17 | self.analyse(statements) 18 | self.showPic() 19 | 20 | # 语义分析 21 | def analyse(self, statements): 22 | for statement in statements: 23 | if statement[0]=="RotStatement": 24 | self.ang = statement[1].getValue() 25 | elif statement[0]=="ScaleStatement": 26 | self.scx, self.scy = statement[1].getValue(), statement[2].getValue() 27 | elif statement[0]=="OriginStatement": 28 | self.orx, self.ory = statement[1].getValue(), statement[2].getValue() 29 | elif statement[0]=="ForStatement": 30 | T_start, T_end = statement[1].getValue(), statement[2].getValue() 31 | T_step = statement[3].getValue() 32 | 33 | Point_x, Point_y = statement[4], statement[5] 34 | if statement[6]: 35 | # print(statement[6]) 36 | self.Draw_color = statement[6] 37 | self.paint(T_start, T_end, T_step, Point_x, Point_y) 38 | else: 39 | print("analyse Error") 40 | 41 | def paint(self, T_start, T_end, T_step, Point_x, Point_y): 42 | # for T_value in range(T_start, T_end, T_step): 43 | T_value = T_start 44 | # 绘制的点坐标 45 | Points = dict(X=[], Y=[]) 46 | while T_value<=T_end: 47 | ExpNode.T_value = T_value 48 | x = Point_x.getValue() 49 | y = Point_y.getValue() 50 | 51 | # print("(%f, %f)" % (x, y)) 52 | 53 | # 坐标变换 54 | # 比例变换 55 | x, y = x*self.scx, y*self.scy 56 | # 旋转变换 57 | x, y = x*math.cos(self.ang) + y*math.sin(self.ang), y*math.cos(self.ang) - x*math.sin(self.ang) 58 | # 平移变换 59 | x, y = x+self.orx, y+self.ory 60 | 61 | # points.append((x, y)) 62 | Points['X'].append(x) 63 | Points['Y'].append(y) 64 | 65 | # print("(%f, %f)" % (x, y)) 66 | T_value += T_step 67 | 68 | # plt.plot(x,y,format_string,**kwargs) 69 | # 第三个参数 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 70 | # 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 71 | # '.' 点标记 ',' 像素点 72 | plt.plot(Points['X'], Points['Y'], '.'+self.Draw_color) 73 | 74 | # 颜色全相同bug已修复 Points应为局部变量 75 | # print("=="+self.Draw_color) 76 | 77 | 78 | def showPic(self): 79 | # plt.xlim(xmax=100, xmin=-100) 80 | # plt.ylim(ymax=100, ymin=-100) 81 | # 保持纵横比例 82 | 83 | plt.axis('equal') 84 | 85 | plt.show() 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /Interpreter4FPL/expnode.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | # @Time : 2019/12/6 12:50 3 | # @Author : izcat 4 | # @Site : $ cnblogs.com/izcat 5 | # @File : expnode.py 6 | # @Software : PyCharm 7 | # @Desc : 表达式节点定义 8 | 9 | from mylexer import Token 10 | from mylexer import TokenType 11 | 12 | class ExpNode: 13 | T_value = 0.0 14 | 15 | def __init__(self, token, left=None, right=None): 16 | self.token = token 17 | self.lson = left 18 | self.rson = right 19 | def addson(self, son): 20 | if self.lson==None: 21 | self.lson = son 22 | return self 23 | elif self.rson==None: 24 | self.rson = son 25 | return self 26 | else: 27 | print("Cannot add son!") 28 | exit(-1) 29 | 30 | def getValue(self): 31 | # 叶子节点 32 | if self.lson==None and self.rson==None: 33 | if self.token.tokenType==TokenType.CONST_ID: 34 | return self.token.value 35 | elif self.token.tokenType==TokenType.T: 36 | return ExpNode.T_value 37 | else: 38 | print("Expression Error") 39 | exit(-1) 40 | 41 | # 只有左子树 函数节点 or +5 or -5 42 | elif self.rson==None: 43 | if self.token.tokenType==TokenType.PLUS: 44 | return self.lson.getValue() 45 | elif self.token.tokenType==TokenType.MINUS: 46 | return -self.lson.getValue() 47 | elif self.token.tokenType==TokenType.FUNC: 48 | return self.token.funcPtr(self.lson.getValue()) 49 | else: 50 | print("Expression Error") 51 | exit(-1) 52 | # 只有右子树 53 | # elif self.lson==None: 54 | # if self.token.tokenType==TokenType.PLUS: 55 | # return self.rson.getValue() 56 | # elif self.token.tokenType==TokenType.MINUS: 57 | # return -self.rson.getValue() 58 | # elif self.token.tokenType==TokenType.FUNC: 59 | # return self.token.funcptr(self.rson.getValue()) 60 | # else: 61 | # print("Expression Error") 62 | else: 63 | if self.token.tokenType==TokenType.PLUS: 64 | return self.lson.getValue() + self.rson.getValue() 65 | elif self.token.tokenType==TokenType.MINUS: 66 | return self.lson.getValue() - self.rson.getValue() 67 | elif self.token.tokenType==TokenType.MUL: 68 | return self.lson.getValue() * self.rson.getValue() 69 | elif self.token.tokenType==TokenType.DIV: 70 | return self.lson.getValue() / self.rson.getValue() 71 | elif self.token.tokenType==TokenType.POWER: 72 | return self.lson.getValue() ** self.rson.getValue() 73 | else: 74 | print("Expression Error") 75 | exit(-1) 76 | 77 | def dfs(self, depth=0): 78 | ret = ' '*depth + self.token.lexeme + '\n' 79 | if self.lson!=None: 80 | ret += self.lson.dfs(depth+1) 81 | if self.rson!=None: 82 | ret += self.rson.dfs(depth+1) 83 | 84 | return ret 85 | # print("Depth %d" % depth) 86 | # self.token.show() -------------------------------------------------------------------------------- /version1/grammer.py: -------------------------------------------------------------------------------- 1 | # Program -> {Statement SEMICO} 2 | # Statement -> OriginStatement | ScaleStatement | RotStatement | ForStatement 3 | # OriginStatement -> ORIGIN IS L_BRACKET Expression COMMA Expression R_BRACKET 4 | # ScaleStatement -> SCALE IS L_BRACKET Expression COMMA Expression R_BRACKET 5 | # RotStatement -> ROT IS Expression 6 | # ForStatement -> FOR T FROM Expression TO Expression STEP Expression 7 | # DRAW L_BRACKET Expression COMMA Expression R_BRACKET 8 | 9 | from lexer import * 10 | import sys 11 | 12 | tokenIter = None 13 | tokenNow = Token(TokenType.NONTOKEN, ''); 14 | 15 | # 从词法分析器的tokens获得token 16 | def FetchToken(): 17 | global tokenNow 18 | try: 19 | tokenNow = next(tokenIter) 20 | return tokenNow 21 | except StopIteration: 22 | sys.exit() 23 | 24 | def MatchToken(tokenType, show=False): 25 | if show: 26 | tokenNow.show() 27 | if tokenNow.tokenType==tokenType: 28 | FetchToken() 29 | else: 30 | print("Excepted ", tokenType, "received ", tokenNow.tokenType) 31 | print("error!") 32 | exit(-1) 33 | 34 | def Parser(string): 35 | global tokenIter # 必须要 global 36 | tokenList = Lexer(string) 37 | tokenIter = iter(tokenList) 38 | FetchToken() 39 | Program() 40 | 41 | def OriginStatement(): 42 | MatchToken(TokenType.ORIGIN) 43 | MatchToken(TokenType.IS) 44 | MatchToken(TokenType.L_BRACKET) 45 | Origin_x = Expression().getValue() 46 | MatchToken(TokenType.COMMA) 47 | Origin_y = Expression().getValue() 48 | MatchToken(TokenType.R_BRACKET) 49 | 50 | def ScaleStatement(): 51 | MatchToken(TokenType.SCALE) 52 | MatchToken(TokenType.IS) 53 | MatchToken(TokenType.L_BRACKET) 54 | Scale_x = Expression().getValue() 55 | MatchToken(TokenType.COMMA) 56 | Scale_y = Expression().getValue() 57 | MatchToken(TokenType.R_BRACKET) 58 | 59 | def RotStatement(): 60 | MatchToken(TokenType.ROT) 61 | MatchToken(TokenType.IS) 62 | Rot_angle = Expression().getValue() 63 | 64 | def ForStatement(): 65 | MatchToken(TokenType.FOR) 66 | MatchToken(TokenType.T) 67 | MatchToken(TokenType.FROM) 68 | T_start = Expression() 69 | MatchToken(TokenType.TO) 70 | T_end = Expression() 71 | MatchToken(TokenType.STEP) 72 | T_step = Expression() 73 | 74 | MatchToken(TokenType.DRAW) 75 | MatchToken(TokenType.L_BRACKET) 76 | Point_x = Expression() 77 | MatchToken(TokenType.COMMA) 78 | Point_y = Expression() 79 | MatchToken(TokenType.R_BRACKET) 80 | 81 | 82 | # Statement -> OriginStatement | ScaleStatement | RotStatement | ForStatement 83 | def Statement(): 84 | if tokenNow.tokenType==TokenType.ORIGIN: 85 | OriginStatement() 86 | elif tokenNow.tokenType==TokenType.SCALE: 87 | ScaleStatement() 88 | elif tokenNow.tokenType==TokenType.ROT: 89 | RotStatement() 90 | elif tokenNow.tokenType==TokenType.FOR: 91 | ForStatement() 92 | else: 93 | print("error!") 94 | 95 | 96 | def Program(): 97 | while tokenNow.tokenType!=TokenType.NONTOKEN: 98 | Statement() 99 | matched = MatchToken(TokenType.SEMICO) 100 | if not matched: 101 | break 102 | 103 | 104 | def test(): 105 | Parser("--hello fad\n //fadfjl\n ROT is ( 1, 0*2) \n ROT is (sin(t), cos(tt));") 106 | 107 | test() 108 | -------------------------------------------------------------------------------- /Interpreter4FPL/mypainter.py: -------------------------------------------------------------------------------- 1 | #-*- coding:utf-8 -*- 2 | # @Time : 2019/12/6 12:55 3 | # @Author : izcat 4 | # @Site : $ cnblogs.com/izcat 5 | # @File : mypainter.py 6 | # @Software : PyCharm 7 | # @Desc : 语义分析器,绘图程序 8 | 9 | from expnode import * 10 | from myparser import Parser 11 | import matplotlib.pyplot as plt 12 | import math 13 | 14 | 15 | class Painter: 16 | def __init__(self, string): 17 | self.orx = 0.0 18 | self.ory = 0.0 19 | self.scx = 1.0 20 | self.scy = 1.0 21 | self.ang = 0.0 22 | self.Draw_color = 'k' 23 | statements = Parser(string) 24 | # print(len(statements)) 25 | 26 | self.analyse(statements) 27 | self.showPic() 28 | 29 | # 语义分析 30 | def analyse(self, statements): 31 | for statement in statements: 32 | if statement[0] == "RotStatement": 33 | self.ang = statement[1].getValue() 34 | elif statement[0] == "ScaleStatement": 35 | self.scx, self.scy = statement[1].getValue(), statement[2].getValue() 36 | elif statement[0] == "OriginStatement": 37 | self.orx, self.ory = statement[1].getValue(), statement[2].getValue() 38 | elif statement[0] == "ForStatement": 39 | T_start, T_end = statement[1].getValue(), statement[2].getValue() 40 | T_step = statement[3].getValue() 41 | 42 | Point_x, Point_y = statement[4], statement[5] 43 | if statement[6]: 44 | # print(statement[6]) 45 | self.Draw_color = statement[6] 46 | self.paint(T_start, T_end, T_step, Point_x, Point_y) 47 | else: 48 | print("analyse Error") 49 | 50 | def paint(self, T_start, T_end, T_step, Point_x, Point_y): 51 | # for T_value in range(T_start, T_end, T_step): 52 | T_value = T_start 53 | # 绘制的点坐标 54 | Points = dict(X=[], Y=[]) 55 | while T_value <= T_end: 56 | ExpNode.T_value = T_value 57 | x = Point_x.getValue() 58 | y = Point_y.getValue() 59 | 60 | # print("(%f, %f)" % (x, y)) 61 | 62 | # 坐标变换 63 | # 比例变换 64 | x, y = x * self.scx, y * self.scy 65 | # 旋转变换 66 | x, y = x * math.cos(self.ang) + y * math.sin(self.ang), y * math.cos(self.ang) - x * math.sin(self.ang) 67 | # 平移变换 68 | x, y = x + self.orx, y + self.ory 69 | 70 | # points.append((x, y)) 71 | Points['X'].append(x) 72 | Points['Y'].append(y) 73 | 74 | # print("(%f, %f)" % (x, y)) 75 | T_value += T_step 76 | 77 | # plt.plot(x,y,format_string,**kwargs) 78 | # 第三个参数 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 79 | # 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 80 | # '.' 点标记 ',' 像素点 81 | plt.plot(Points['X'], Points['Y'], '.' + self.Draw_color) 82 | 83 | # 颜色全相同bug已修复 Points应为局部变量 84 | # print("=="+self.Draw_color) 85 | 86 | def showPic(self): 87 | # plt.xlim(xmax=100, xmin=-100) 88 | # plt.ylim(ymax=100, ymin=-100) 89 | # 保持纵横比例 90 | 91 | plt.axis('equal') 92 | 93 | plt.show() 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Interpreter For Functional Painting Language 2 | > 西电 编译原理大作业 3 | 4 | ## 实验目的 5 | 实现函数绘图语言的解释器,通过实验加深对编译器构造原理和方法的理解,巩固所学知识。 6 | - 会用正规式设计简单语言的词法 7 | - 会用产生式设计简单语言的语法 8 | - 会用递归下降子程序编写语言的解释器 9 | 10 | 11 | 12 | ## 实验要求 13 | 14 | ### 语句原则: 15 | 16 | 1. 各类语句可以按任意次序书写,且语句以分号结尾。源程序中的语句以它们出现的先后顺序处理。 17 | 18 | 2. ORIGIN、ROT和SCALE 语句只影响其后的绘图语句,且遵循最后出现的语句有效的原则。 19 | 例如,若有下述ROT语句序列: 20 | ROT IS 0.7 ; 21 | ROT IS 1.57 ; 22 | 则随后的绘图语句将按1.57而不是0.7弧度旋转。 23 | 24 | 3. 无论ORIGIN、ROT和SCALE语句的出现顺序如何,图形的变换顺序总是:比例变换→旋转变换→平移变换 25 | 26 | 4. 语言对大小写不敏感,例如for、For、FOR等,均被认为是同一个保留字。 27 | 28 | 5. 语句中表达式的值均为双精度类型,旋转角度单位为弧度且为逆时针旋转,平移单位为点。 29 | 30 | ### 循环绘图(FOR-DRAW )语句 31 | 语法:FOR T FROM 起点 TO 终点 STEP 步长 DRAW(横坐标, 纵坐标); 32 | 33 | 语义:令T从起点到终点、每次改变一个步长,绘制出由(横坐标,纵坐标)所规定的点的轨迹。 34 | 35 | 举例:FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (cos(T), sin(T)); 36 | 37 | 说明:该语句的作用是令T从0到2*PI、步长 PI/50,绘制出各个点的坐标(cos(T),sin(T)),即一个单位圆。 38 | 39 | ### 比例设置(SCALE)语句 40 | 语法:SCALE IS (横坐标比例因子,纵坐标比例因子); 41 | 42 | 语义:设置横坐标和纵坐标的比例,并分别按照比例因子进行缩放。 43 | 44 | 举例:SCALE IS (100, 100); 45 | 46 | 说明:将横坐标和纵坐标的比例设置为1:1,且放大100倍。 47 | 48 | ### 坐标平移(ORIGIN)语句 49 | 语法:ORIGIN IS (横坐标,纵坐标); 50 | 51 | 语义:将坐标系的原点平移到横坐标和纵坐标规定的点处。 52 | 53 | 举例:ORIGIN IS (360, 240); 54 | 55 | 说明:将原点从(0, 0)平移到(360, 240) 处 56 | 57 | ### 角度旋转(ROT)语句 58 | 语法:ROT IS 角度; 59 | 60 | 语义:逆时针旋转角度所规定的弧度值。 61 | 具体计算公式: 62 | 旋转后X=旋转前X*COS(角度)+旋转前Y*SIN(角度) 63 | 旋转后Y=旋转前Y*COS(角度)-旋转前X*SIN(角度) 64 | 65 | 举例:ROT IS PI/2; 66 | 67 | 说明:逆时针旋转PI/2,即逆时针旋转90度。 68 | 69 | ### 注释语句 70 | 作用:便于理解; 71 | 屏蔽暂时不需要的语句。 72 | 语法:// This is a comment line 73 | 或 -- 此行是注释 74 | 语义:// 或 -- 之后,直到行尾,均是注释 75 | 76 | 77 | 78 | ------- 79 | 80 | 81 | 82 | ## 实验过程 83 | 84 | ### Version 1 85 | 代码详见 https://github.com/izcat/Interpreter4FPL/tree/master/version1 86 | 87 | 完成词法分析 88 | 89 | #### 词法分析器功能 90 | 91 | - 输入:函数绘图语言源程序,以字符串形式传递给 `Lexer` 参数 92 | - 输出:返回源程序进行词法分析得到的全部 Token,类型为列表 93 | 94 | #### Update: 95 | 96 | 此版本 `Lexer` 会无法正确识别带小数点的浮点数!在version2中的 `Lexer` 才是正确写法! 97 | 98 | 99 | ### Version 2 100 | 代码详见 https://github.com/izcat/Interpreter4FPL/tree/master/version2 101 | 102 | 已实现实验要求的函数绘图语言的全部功能 103 | 解释器执行的第一个程序结果(显示 'OK' 字样): 104 | ![图片](https://github.com/izcat/Interpreter4FPL/blob/master/version2/0testOK.png "结果") 105 | 106 | 107 | #### 修复Bug 108 | 109 | 由于新加入主界面的模块 `main.py` 无法正常 import 写好的 `parser`模块,因为会与 Python 的同名库冲突。 110 | 将全部模块改名,加上'my'前缀 111 | 112 | #### 不足 113 | 114 | 词法分析器与语义分析器没有完全分离,本解释器在语法分析阶段,未生成源代码的整体语法树,直接将绘制的点信息交给painter处理 115 | 缺少异常处理机制 116 | 没有完全面向对象开发 117 | 118 | 119 | ### Version 3 120 | 代码详见 https://github.com/izcat/Interpreter4FPL/tree/master/version3 121 | 122 | 本次版本不涉及代码修复和功能修改,version2可以正常运行标准绘图源程序 123 | 124 | 在完成作业要求的基础上,本次更新增加了**自定义颜色**的语法 125 | 即 126 | **FOR T FROM T_start TO T_end STEP T_step DRAW (Point_x, Point_Y)** 127 | **[OF (RED|GREEN|BLUE|YELLOW|BLACK)]** 128 | 129 | 更改内容如下 130 | 131 | - `mylexer` 模块新增记号类别 `TokenType` : **OF**,**RED**,**GREEN**,**BLUE**,**YELLOW**, **BLACK** 132 | - `mylexer` 模块新增字符与记号的字典映射 `TokenTypeDict` : 133 | - OF = Token(TokenType.OF, "OF") 134 | - RED = Token(TokenType.COLOR, "RED") 135 | - GREEN = Token(TokenType.COLOR, "GREEN") 136 | - BLUE = Token(TokenType.COLOR, "BLUE") 137 | - YELLOW = Token(TokenType.COLOR, "YELLOW") 138 | - BLACK = Token(TokenType.COLOR, "BLACK") 139 | - `myparser` 模块作少量改动,`ForStatement` 方法新增颜色识别语句,将获取颜色结果传给 `Painter` 140 | - `mypainter` 模块内的 `paint` 方法 141 | - plt.plot(Painter.Points['X'], Painter.Points['Y'], '.'+Draw_color) 142 | - 参考自 https://blog.csdn.net/qiurisiyu2016/article/details/80187177 143 | - 第三个参数 'r', 'g', 'b', 'k'(Black),'y'(Yellow) 144 | - '.' 点标记 ',' 像素点 145 | 146 | 147 | ### Version 4 148 | 代码详见 https://github.com/izcat/Interpreter4FPL/tree/master/version4 149 | 150 | 改进内容: 151 | 152 | - 在version3的基础上,分离语法分析器 `myparser` 模块与语义分析器 `mypainter` 模块 153 | - 重新设计了语法分析过程中的运行提示,增加了层级level参数,使递归调用的输出信息更友好 154 | - 重写了 `mypainter` 模块,改用面向对象方式 155 | - `Painter` 类 接收绘图源程序代码,调用语法分析器 `myparser.Parser` 156 | - 将获取到的语法树交给 `analyse` 方法进行语义分析 157 | - 语义分析完成后,`showPic` 执行绘图 158 | - 改进 `main` 程序入口模块,增加了打开文件选项,可以直接选择写好绘图源程序打开 159 | 160 | 161 | ## 结果展示 162 | 163 | ![pic3](https://github.com/izcat/Interpreter4FPL/blob/master/test%26pic/几何标志.png) 164 | ![pic2](https://github.com/izcat/Interpreter4FPL/blob/master/test%26pic/五环.png) 165 | ![pic1](https://github.com/izcat/Interpreter4FPL/blob/master/test%26pic/test0.jpg) 166 | 167 | 168 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 14 | 15 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 144 | 145 | 146 | 147 | 148 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 1575604286922 181 | 188 | 189 | 190 | 191 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | --------------------------------------------------------------------------------