JAVA实现一个简单的代数运算语言编译器(三)--词法分析
来源:互联网 发布:投资域名后悔死了 编辑:程序博客网 时间:2024/05/17 07:47
上一篇文章我们为编译器编写了保留字、系统符号、出错提示等系统预制类,这一篇文章我们主要介绍编译器的词法分析部分。
我们首先创建一个名为WordAnalysis的类,为这个类编写一个共有静态方法 wordAnalysis 用来提供对外的词法分析接口。该方法接收一个字符串参数,即经过了分割的一个语句。返回一个字符串队列,即通过了词法分析并逐词分割后的语句,队列中的每一个字符串即为一个词,具体到这个项目中,词有可能是变量名、运算符号、赋值符号、保留字。
由于JAVA的字符类型char可以直接进行ASCII码的比较,因此这里我们可以编写对应的方法分别判断一个字符是字母、数字、空白符还是系统符号:
/* * 判断是否是字母 * @param ch 需要判断的字符 * @return true代表是字母,false代表不是字母 */private static boolean isLetter(char ch) {if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) {return true;}return false;}/* * 判断是否是数字 * @param ch 需要判断的字符 * @return true代表是数字,false代表不是数字 */private static boolean isDigit(char ch) {if (ch >= 48 && ch <= 57) {return true;}return false;}/* * 判断是否是空格或换行 * @param ch 需要判断的字符 * @return true代表是空白符,false代表不是 */private static boolean isSpace(char ch) {if (ch == 32 || ch == 10) {return true;}return false;}/* * 判断是否是小数点 * @param ch 需要判断的字符 * @return true代表是小数点,false代表不是 */private static boolean isPoint(char ch) {if (ch == 46) {return true;}return false;}/* * 判断是否是系统符号 * @param ch 需要判断的字符 * @return true代表是系统符号,false代表不是 */private static boolean isSymbol(char ch) {for (char symbol : Symbol.symbols) {if (symbol == ch) {return true;}}return false;}
有了以上分析,我选择用两个静态StringBuffer变量variableRegister、digitRegister和一个静态boolean变量anySpace来临时保存状态,这里我们不如就叫它们变量寄存器、数字寄存器以及空白寄存器吧。这里我们以语句 re= nu*2 来举例分析。
一开始变量寄存器和数字寄存器都是空的,空白寄存器值为false。
1.扫描到第一个字符r,判断其是一个字母,此时变量寄存器和数字寄存器都是空的,因此将其存入变量寄存器。
2.扫描到字符e,判断其是一个字母,而此时变量寄存器非空,数字寄存器是空的,因此将其存入变量寄存器。
3.扫描到字符=,判断其是系统符号,此时数字寄存器是空的,而变量寄存器值为re,因此将re添加到要返回的字符串队列当中,并将变量寄存器清空。
4.扫描到一个空白符,而此时变量寄存器和数字寄存器都是空的,因此不会有词法错误,仅仅将空白寄存器的值设为true.
5.扫描到字母n,此时变量寄存器和数字寄存器都是空的,因此将其存入变量寄存器,并将空白寄存器重新设为false.
6.扫描到字符u,判断其是一个字母,而此时变量寄存器非空,数字寄存器是空的,因此将其存入变量寄存器。
7.扫描到字符*,判断其是系统符号,此时数字寄存器是空的,而变量寄存器值为nu,因此将re添加到要返回的字符串队列当中,并将变量寄存器清空。
8.扫描到字符2,判断其是一个数字,此时变量寄存器和数字寄存器都是空的,因此将其存入数字寄存器。
9.字符串扫描完毕,此时变量寄存器是空的,数字寄存器中的值是2,因此将2添加到要返回的字符串队列当中,并将数字寄存器清空。
10.返回结果字符串队列。
以上就是对语句 re= nu*2 的一个词法分析以及按词分割的过程。而实际情况中可能会出现各种各样的词法错误,如变量名不规范,数字以小数点结尾、错误的空白符等等,对于这些情况,我都写在了wordAnalysis方法中,感兴趣的小伙伴可以仔细看一看。
WordAnalysis类的完整代码如下:
package com.liu.analysis;import java.util.ArrayList;import java.util.List;import com.liu.system.Error;import com.liu.system.MyException;import com.liu.system.Symbol;/* * 词法分析类 * 创建于2017.3.8 * @author lyq * */public class WordAnalysis {/* 变量名寄存字段,可临时寄存一个变量名 */private static StringBuffer variableRegister = new StringBuffer();/* 数字寄存字段,可临时寄存一个数字 */private static StringBuffer digitRegister = new StringBuffer();/* 是否存储有空白符 */private static boolean anySpace = false;/* * 判断是否是字母 * @param ch 需要判断的字符 * @return true代表是字母,false代表不是字母 */private static boolean isLetter(char ch) {if ((ch >= 65 && ch <= 90) || (ch >= 97 && ch <= 122)) {return true;}return false;}/* * 判断是否是数字 * @param ch 需要判断的字符 * @return true代表是数字,false代表不是数字 */private static boolean isDigit(char ch) {if (ch >= 48 && ch <= 57) {return true;}return false;}/* * 判断是否是空格或换行 * @param ch 需要判断的字符 * @return true代表是空白符,false代表不是 */private static boolean isSpace(char ch) {if (ch == 32 || ch == 10) {return true;}return false;}/* * 判断是否是小数点 * @param ch 需要判断的字符 * @return true代表是小数点,false代表不是 */private static boolean isPoint(char ch) {if (ch == 46) {return true;}return false;}/* * 判断是否是系统符号 * @param ch 需要判断的字符 * @return true代表是系统符号,false代表不是 */private static boolean isSymbol(char ch) {for (char symbol : Symbol.symbols) {if (symbol == ch) {return true;}}return false;}/* * 对一段输入的字符串进行词法分析 * @param str 需要分析的字符串 * @return 返回经过词法分析后的字符串队列 * @exception 数字前有空白符时出现异常 */public static List<String> wordAnalysis(String str) throws MyException {//用来存放分析结果List<String> result = new ArrayList<String>();for (int i = 0; i < str.length(); i++) {char ch = str.charAt(i);// 是字母if (isLetter(ch)) {if (!variableRegister.toString().equals("")) {// 字母-空白符-字母if (anySpace) {variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.LETTER_SPACE_LETTER);}// 字母-字母else {variableRegister.append(ch);continue;}}if (!digitRegister.toString().equals("")) {// 数字-空白符-字母if (anySpace) {variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.NUMBER_SPACE_LETTER);}// 数字-字母else {variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.LETTER_AFTER_NUMBER);}}variableRegister.append(ch);anySpace = false;continue;}// 是数字if (isDigit(ch)) {if (!variableRegister.toString().equals("")) {// 字母-空白符-数字if (anySpace) {variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.LETTER_SPACE_NUMBER);}// 字母-数字else {variableRegister.append(ch);continue;}}if (!digitRegister.toString().equals("")) {// 数字-空白符-数字if (anySpace) {variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.NUMBER_SPACE_NUMBER);}// 数字-数字else {digitRegister.append(ch);continue;}}digitRegister.append(ch);anySpace = false;continue;}// 是空白符,记录出现了空格符,然后继续循环if (isSpace(ch)) {anySpace = true;continue;}//是小数点if(isPoint(ch)){if(anySpace){variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.POINT_AFTER_SPACE);}else{if(!variableRegister.toString().equals("")){variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.POINT_AFTER_LETTER);}if(!digitRegister.toString().equals("")){if(digitRegister.toString().contains(String.valueOf(Symbol.point))){variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.POINT_AFTER_POINT);}digitRegister.append(ch);continue;}}}//是系统符号if(isSymbol(ch)){anySpace = false;//变量寄存器中存有变量if(!variableRegister.toString().equals("")){result.add(variableRegister.toString());//清空变量寄存器variableRegister.setLength(0);}//数字寄存器中存有数字if(!digitRegister.toString().equals("")){if(digitRegister.toString().endsWith(String.valueOf(Symbol.point))){variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.NUMBER_END_POINT);}result.add(digitRegister.toString());//清空变量寄存器digitRegister.setLength(0);}result.add(String.valueOf(ch));continue;}variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.CONTAIN_UNKNOWN_CAHR);}//变量寄存器中存有变量if(!variableRegister.toString().equals("")){result.add(variableRegister.toString());//清空变量寄存器variableRegister.setLength(0);}//数字寄存器中存有数字if(!digitRegister.toString().equals("")){if(digitRegister.toString().endsWith(String.valueOf(Symbol.point))){variableRegister.setLength(0);digitRegister.setLength(0);throw new MyException(Error.NUMBER_END_POINT);}result.add(digitRegister.toString());digitRegister.setLength(0);}return result;}}
以上就是整个的词法分析过程了,下一篇文章我们将介绍如何进行表达式的计算。
- JAVA实现一个简单的代数运算语言编译器(三)--词法分析
- JAVA实现一个简单的代数运算语言编译器(二)--词法分析准备
- JAVA实现一个简单的代数运算语言编译器(一)--写在前面
- JAVA实现一个简单的代数运算语言编译器(四)-- 表达式计算
- 一个简单词法分析器的实现代码(java实现)
- 一个简单词法分析器的实现代码(java实现)
- c语言词法分析器的一个简单实现
- 一个简单词法分析器的C语言实现
- C语言实现一个简单的词法分析器
- C++写的一个简单的词法分析器(分析C语言)
- C++写的一个简单的词法分析器(分析C语言)
- java简单地实现Tiny语言的词法分析器
- java正则表达式实现简单词法分析
- 一个简单C语言的词法分析器
- 一个简单的词法分析程序
- 一个简单的词法分析程序
- c语言词法分析器的简单实现
- Python实现的C语言词法分析
- vb.net教程 0-2 操作区域
- A+B
- Three.js入门篇之1
- 函数的返回值
- Comparable和Comparator接口是干什么的?列出它们的区别。
- JAVA实现一个简单的代数运算语言编译器(三)--词法分析
- 符号常量和变量
- HTML 5入门知识(三)
- Ruby_异常处理
- C++基础知识复习之--顺序表学生成绩管理系统
- 时间复杂度与空间复杂度
- JSON
- C++随机数 (rand srand)用法,注意随机数种子每次要更新。
- 哈利·波特的考试 (Dijkstra)