函数绘图语言
Github:carpediemtal/Drawlang-Interpreter (github.com)
概述
5 种语句
循环绘图(FOR-DRAW)
比例设置(SCALE)
角度旋转(ROT)
坐标平移(ORIGIN)
注释 (– 或 //)
坐标系
左上角为原点
x方向从左向右增长
y方向从上到下增长
栗子
1 | --------------- 函数f(t)=t的图形 |
1 | origin is (100, 300); |
为函数绘图语言构造‘解释器’
词法分析器
记号的种类
1 | public enum TokenType { |
常数
数值字面量和标识符形式的常量名均称为常数。
字面量的形式为普通的数值,如果没有小数部分,可以省略小数点。例如2、2.、2.0都是合法的常数。
标识符PI、E也是常数,它们分别代表圆周率和自然对数的底。常数不能有符号位,如-1和+2不是常数而是(一元运算的)表达式。
参数
本绘图语言中唯一的、已经被定义好的变量名T被称为参数,它也是一个表达式。由于绘图语言中只有这唯一的变量,因此绘图语言中无需变量或参数的声明和定义语句。
函数
为简单起见,当前函数调用仅支持Sin、Cos、Tan、Sqrt、Exp 和 Ln。
保留字
语句中具有固定含义的标识符,包括:
ORIGIN, SCALE, ROT, IS,
FOR, FROM, TO, STEP, DRAW
运算符
+ - * / **
结合性: ** 右结合, 其他 左结合
优先级:** > 一元+- > */ > 二元+-
分隔符
; ( ) ,
建立hash表将字符串和Token相对应
1 | private void initTable() { |
识别出的函数会在后面的语法分析器进一步细分:
1 | /** |
DFA
核心代码
1 | /** |
语法分析器
流程
语法分析器Parser内部持有一个词法分析器Lexer实例,通过该实例的getToken获得Token,再进一步分析。
1 | public void parse() { |
文法
经过各种处理之后的最终文法规则
表达式的语法树
函数绘图语言比较简单,只有表达式需要建立语法树进一步求值。
1 | package eternal.fire.syntax; |
构造语法树的片段节选
1 | /** |
To be continued…
绘图:JavaFX
核心思路
利用JavaFx的canvas可以轻松在窗口面板上绘制一个点。
1 | Canvas canvas = new Canvas(500, 500); |
当语法分析器获得绘图语句的结果后,使用循环语句在面板上画上若干个点,于是一切都结束了。
前端界面设计
画板大小:500px*500px
使用JFoenix和css样式对部分组件稍加美化
布局
窗口图标
1 | primaryStage.getIcons().add(new Image(Draw.class.getResourceAsStream("/draw.png"))); |
补充的功能
改变画笔颜色
添加一个拾色器组件,当拾色器组件的值发生变化,就以新的值为画笔颜色,清空画板,重新渲染。
1 | // 拾色器 |
改变画笔宽度
和上面的思路类似。
1 | // 滑动按钮 |
Help按钮
跳转到我的博客。
1 | // Help |
help的图标看上去好丑,我注释掉了。
Github按钮
跳转到我的github仓库。
1 | // Github |
日志
使用SLF4J和Logback
依赖项:
1 | dependencies { |
构建
使用Gradle管理依赖项
1 | plugins { |
运行
1 | gradlew run |