java中的画图公式_GitHub - oneSaber/Compiler-java: 函数绘图语言java实现

本文介绍了一个使用Java编写的函数绘图语言解释器,它通过递归下降子程序方法解析并绘制函数图形。解释器能处理包含ORIGIN、SCALE、ROT、FOR等指令的源程序,并直接在屏幕上展示图形。文章还详细描述了词法分析和语法语义分析的过程,包括记号类型定义、正规式DFA和主要的递归下降子程序。
摘要由CSDN通过智能技术生成

简易解释器

68747470733a2f2f7472617669732d63692e6f72672f66656e6c616e2f436f6d70696c65722d6a6176612e7376673f6272616e63683d6d6173746572

68747470733a2f2f636f6465626561742e636f2f6261646765732f35373431373133652d616266362d343936332d393738652d343738376366373235623439

68747470733a2f2f6769746875622d73697a652d62616467652e6865726f6b756170702e636f6d2f66656e6c616e2f436f6d70696c65722d6a6176612e737667

68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c616e67756167652d6a6176612d626c75652e737667

68747470733a2f2f696d672e736869656c64732e696f2f62616467652f706c6174666f726d2d4c696e75782d6f72616e67652e737667

简单介绍

程序为实现一个简单的函数绘图语言的解释器,该解释器接受用绘图语言编写的源程序,经过语法和语义分析之后,直接将源程序所规定的图形显示在显示屏(或显示窗口)中。

实现方法

用java语言和递归下降子程序的方法编写完整的解释器,运行函数绘图语言的解释器,以该语言书写的源程序为输入,就会从屏幕上看到源程序所规定的图形。异于c实现,java实现没有构建语法树,在进行语法分析时同时进行了语义分析,其中for语法通过反复读取DRAW函数的参数,反复计算,将所有的点记录下来,最后一次遍历所有的点绘出图形。

运行环境

Ubuntu 16.04

IntelliJ IDEA-2017.2

JDK-1.8

已实现代码功能: 词法分析、词法分析测试、语法语义分析,编译绘图

绘图源程序示例

源程序一:

ORIGIN IS(360, 240);// 横、纵坐标平移距离

ROT IS PI/2;// 旋转角度

SCALE IS (100,100/3);// 横、纵坐标比例因子

FOR T FROM 0 TO 2*PI STEP PI/50 DRAW (COS(T), SIN(T));

绘图结果:

program1.png

源程序二:

ROT IS 0;

ORIGIN IS (50,400);

SCALE IS (2,1);

FOR T FROM 0 TO 300 STEP 1 DRAW(0,-T);

FOR T FROM 0 TO 300 STEP 2 DRAW(T,0);

FOR T FROM 0 TO 300 STEP 1 DRAW(T,-T);

SCALE IS (2,0.1);

FOR T FROM 0 TO 55 STEP 1 DRAW(T,-(T*T));

SCALE IS (10,5);

FOR T FROM 0 TO 60 STEP 1 DRAW(T,-SQRT(T));

SCALE IS (20,0.1);

FOR T FROM 0 TO 8 STEP 0.1 DRAW(T,-EXP(T));

绘图结果

program2.png

词法分析

记号

private int type; // 记号类型

private String lexeme; // 构成记号字符串

private double value; // 记号为常数时,记号的值

记号类型

public class TokenType {

public static final int ORIGIN = 0;// 保留字

public static final int SCALE = 1;

public static final int ROT = 2;

public static final int IS = 3;

public static final int TO = 4;

public static final int STEP = 5;

public static final int DRAW = 6;

public static final int FOR = 7;

public static final int FROM = 8;// 保留字

public static final int T = 9;// 参数

public static final int SEMICO = 10;

public static final int L_BRACKET = 11;

public static final int R_BRACKET = 12;

public static final int COMMA = 13;// 分隔符

public static final int PLUS = 14;// 运算符

public static final int MINUS = 15;

public static final int MUL = 16;

public static final int DIV = 17;

public static final int POWER = 18;// 运算符

public static final int FUNC = 19;

public static final int CONST_ID = 20;

public static final int NONTOKEN = 21;// 空记号

public static final int ERRTOKEN = 22;// 错误记号

}

程序中的保留字、参数、分隔符、运算符等采用的是"一字一码",即一个记号就是一个实例;函数和常数可以有多个实例,FUNC可以是sin,也可以是cos等;空记号标记源程序已经结束;出错记号用于标记非法输入,当分析到非法字符或字符串时,词法分析器就返回一个错误记号,以便语法分析器的错误处理。

描述词法的正规式

tokentable.png

词法分析正规式DFA

DFA.png

根据正规式DFA编写出GetToken()方法,每次识别一个记号,返回值为一个记号类型。大体编程框架:

AddCharTokenString(_char);

if (Character.isAlphabetic(_char)) { ... ... }// 字符记号

else if (Character.isDigit(_char)) { ... ... }// 数字常数记号

else {// 操作符号

switch (_char) {

case ';': token.setType(TokenType.SEMICO); token.setLexeme(";"); break;

... ...

}

}

词法分析流程

scanner.png

词法分析器提供记号给语法分析器分析: InitScanner初始化词法分析器并打开源程序文件,如果文件打不开则指出错误告知语法分析器停止分析;GetToken返回一个记号;CloseScanner关闭词法分析器。初始化完后不断调用GetToken识别记号,当识别当NONTOKEN时调用CloseScanner来关闭词法分析器。

语法语义分析

在我的c实现的解释器中,语法语义分析分开进行,在java代码中,将语法语义分析同时进行,在进行语法分析时将表达式的结果求解出来,不再构建语法树,这种方法适合于比较简单的语法分析,较复杂的语法,应尽量构建语法树,构建语法树有利于语言本身扩展语法。

文法

Program --> { Statement SEMICO }

Statement --> OriginStatement | ScaleStatement | RotStatement | ForStatement

OriginStatement --> ORIGINIS L_BRACKET Expression COMMA Expression R_BRACKET

ScaleStatement --> SCALE IS L_BRACKET Expression COMMA Expression R_BRACKET

RotStatement --> ROT IS Expression

ForStatement

--> FOR T FROM Expression TO Expression STEP Expression

DRAW L_BRACKET Expression COMMA Expression R_BRACKET

Expression --> Term {(PLUS|MINUS) Term}

Term --> Factor {(MUL|DIV) Factor}

Factor --> PLUS Factor | MINUS Factor | Component

Component --> Atom POWER Component | Atom

Atom --> CONST_ID

| T

| FUNC L_BRACKET Expression R_BRACKET

| L_BRACKET Expression R_BRACKET

主要的递归下降子程序

public static void Parser(String FileName) { ... ... }

private static void Program() { ... ... }

private static void Statement() { ... ... }

private static void OriginStatement() { ... ... }

private static void RotStatement() { ... ... }

private static void ScaleStatement() { ... ... }

private static void ForStatement() { ... ... }

private static double Expression() { ... ... }

private static double Term() { ... ... }

private static double Factor() { ... ... }

private static double Component() { ... ... }

private static double Atom() { ... ... }

全程变量

private static doubleParameter=0,

Origin_x=0,Origin_y=0,

Scale_x=1,Scale_y=1,

Rot_angle=0;

For语句处理

c处理ForStatement是构建语法树,处理For的每次循环,只需要查询语法树,给变量T赋值,计算坐标。java实现没有构建语法树,本程序采用的方法是如下:

词法分析ForStatement到DRAW子句,从(开始缓冲之后的记号,直到)(包括))。

计算DRAW子句的坐标,放入坐标点集合中。

判断是否需要下一次循环,如果需要循环,将缓冲内容退回到源文件读取流中,计算变量T的下一个值。重复步骤1、2。

如果不需要循环,将缓冲区清空,进行下一个Statement分析。

缺陷

语法分析没有扩展性

循环读取字符流增加了程序耗时

程序不够模块化,程序思路不清晰

c实现源码地址

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值