上一篇文章主要介绍了这个代数运算编译器的起因,这一篇我们就来开始写这个项目。
首先我们需要先设置一些系统的基础类如系统符号类,保留字类、错误提示信息类、自定义异常、输入读取类等,下面简单地说一下这几个类。
系统符号类:
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(),负责从输入流中读取到字符串并将其按分号进行分割,如果输入末尾不是分号则会抛出一个异常提示用户。
好了,有了上述这些类,词法分析的准备工作就算完成了,接下来我们可以开始我们的编译器词法分析了。