上一篇文章主要介绍了这个代数运算编译器的起因,这一篇我们就来开始写这个项目。
首先我们需要先设置一些系统的基础类如系统符号类,保留字类、错误提示信息类、自定义异常、输入读取类等,下面简单地说一下这几个类。
系统符号类:
package com.liu.system;
/*
* 系统符号集合
* 创建于2017.3.7
* @author lyq
* */
public class Symbol {
/*加号*/
public static final char plus = '+';
/*减号*/
public static final char minus = '-';
/*乘号*/
public static final char times = '*';
/*除号*/
public static final char slash = '/';
/*左括号*/
public static final char lparen = '(';
/*右括号*/
public static final char rparen = ')';
/*结束符*/
public static final char semicolon = ';';
/*赋值符*/
public static final char eql = '=';
/*小数点*/
public static final char point ='.';
//运算及赋值符号数组
public static final char[] symbols = {
plus,minus,times,slash,lparen,rparen,eql
};
}
这个类主要时存储了一些系统预制符号,还用一个字符串数组存储了可用于四则运算以及赋值的符号,方便后面的词法分析。
保留字类:
package com.liu.system;
/*
* 系统保留字类
* 创建时间2017.3.7
* @author lyq
* */
public class Word {
/*输出函数的函数名*/
public static final String PRINT = "print";
/*保留字数组*/
public static final String[] WORDS = {PRINT};
}
由于作业要求里面只提到了print这一个关键字,因此这个类非常简单,但把它封装成类更方便今后程序的拓展。
错误提示类:
package com.liu.system;
/*
* 错误提示信息类
* 创建时间2017.3.7
* @author lyq
* */
public class Error {
public static final String END_WITH_NO_SEM = "The program ended without a semicolon.";//结尾没有结束符
public static final String NUMBER_SPACE_NUMBER = "There is gaps between the two numbers.";//数字间有空白符
public static final String NUMBER_SPACE_LETTER = "There are gaps between numbers and variables.";//数字和字母间有空白符
public static final String LETTER_SPACE_LETTER = "There are graps between variables.";//字母间有空白符
public static final String LETTER_SPACE_NUMBER = "There are gaps between numbers and variables.";//字母和数字间有空白符
public static final String LETTER_AFTER_NUMBER = "There is a variable which is not initialized.";//数字之后紧跟字母,可能是变量名不符合规定
public static final String POINT_AFTER_SPACE = "There is gaps before a point.";//小数点前面有空格
public static final String POINT_AFTER_LETTER = "There is a letter before a point.";//小数点前面有字母
public static final String POINT_AFTER_POINT = "There are too many points in a number.";//一个数字中有多个小数点
public static final String NUMBER_END_POINT = "There is a number which ended with a point.";//一个数字以小数点结尾
public static final String NO_THIS_TYPE = "The system cannot recognize this symbol.";//计算表达式时找不到匹配该变量的符号类型
public static final String NO_THIS_VARIBLE ="A varible has be used which not be initialized.";//使用了未经初始化的变量进行运算
public static final String DIVIDED_BY_ZERO ="The divisor can not be zero.";//除数为0
public static final String WRONG_FORMAT_OF_EXPRESSION = "There is error in expression.";//错误的表达式
public static final String INCORRECT_ASSIGNMENT = "There is a error in assignment statement.";//赋值语句有误
public static final String NAME_WITH_KEYWORD = "A varible named by keyword.";//使用保留字进行命名
public static final String CONTAIN_UNKNOWN_CAHR = "There is a character which is not recognized by the system.";//输入中包含未知字符
public static final String UNRECOGNIZED_SENTENCE = "There is a sentence which is not recognized by the system.";//包含无法识别的语句
}
这个类主要用来存储一些错误提示信息,由于首先主要是做词法分析,因此这里我们主要存储的是与词法有关的错误。
我的异常类:
package com.liu.system;
/*
* 自定义异常类
* 创建时间2017.3.7
* @author lyq
* */
public class MyException extends Exception{
private static final long serialVersionUID = 1L;
public MyException() {
super();
// TODO Auto-generated constructor stub
}
public MyException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public MyException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public MyException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public MyException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
}
}
自定义异常类继承自Exception,方便报错。
输入读取类:
package com.liu.system;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
/*
* 按分号读取输入
* 创建于2017.3.7
* @author lyq
* */
public class Read {
/*
* 读取系统输入的方法
* @param input 输入流
* @return 返回按结束符分割的字符串数组
* @exception 当输入不是以分号结尾时抛出MyException异常
* @exception i/o异常
* */
public static String[] getInput(InputStream input) throws Exception {
BufferedReader bf = new BufferedReader(new InputStreamReader(input));
StringBuffer sb = new StringBuffer();
String str = null;
while ((str = bf.readLine()) != null) {
sb.append(str);
}
String content = sb.toString();
//如果结尾不是分号则报错
if(!content.endsWith(Symbol.semicolon)){
throw new MyException(Error.END_WITH_NO_SEM);
}
return content.split(Symbol.semicolon);
}
}
这个类有一个静态方法getInput(),负责从输入流中读取到字符串并将其按分号进行分割,如果输入末尾不是分号则会抛出一个异常提示用户。
好了,有了上述这些类,词法分析的准备工作就算完成了,接下来我们可以开始我们的编译器词法分析了。