编译原理词法分析

  1. 本次实验从input.txt文件中读取一段程序,输出二元式到output.txt文件中。
  2. 代码中的文件路径请自己修改。
  3. 使用java实现。

Main类

每次调用词法分析获取一个单词,并输出到文件中。

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;

public class Main {

	public static void main(String[] args) {
		FileReader input = null;
		FileWriter output = null;

		try {
			input = new FileReader("D:\\WorkSpace\\java\\ComplierExperiment\\src\\complierExperiment1\\input.txt");
			output = new FileWriter("D:\\WorkSpace\\java\\ComplierExperiment\\src\\complierExperiment1\\output.txt");
			// 文件中读取的字符存放在charset中
			char[] charset = new char[1024 * 1024];
			// 从文件中读取的字符数量
			int codeNumber = input.read(charset);
			// 新建CodeScanner对象
			CodeSannner sc = new CodeSannner(codeNumber, charset);
			// 当没有读到结束的时候
			while (sc.getIndex() < codeNumber) {
				// 扫描一个单词,得到一个二元组
				Tuple tuple = sc.scan();
				// 将扫描得到的二元组写入到文件中
				output.write(tuple.getTypeNum() + "\t" + tuple.getStrToken() + "\n");
				// 清空strToken
				sc.clear();
			}
			// 清空输出文件缓冲区
			output.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (output != null) {
				try {
					output.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}

}

Tuple类

表示二元组

// 识别得到的一个单词的种别码和值
public class Tuple {

	public int getTypeNum() {
		return typeNum;
	}

	public void setTypeNum(int typeNum) {
		this.typeNum = typeNum;
	}

	public String getStrToken() {
		return strToken;
	}

	public void setStrToken(String strToken) {
		this.strToken = strToken;
	}

	private int typeNum; // 种别码

	private String strToken; // 单词

	public Tuple(int typeNum, String strToken) {
		this.typeNum = typeNum;
		this.strToken = strToken;
	}

}

CodeScanner类

核心总控程序是其中的scan方法,请仔细查看。

  1. 总控程序流程图,相当于scan方法总体思路

编译原理词法分析
2. 识别无符号数流程图
编译原理词法分析
3. 代码如下:

public class CodeSannner {

	private int errorNum = -1; // 出错
	private int keyWordsNum = 1; // 1代表关键字
	private int identifierNum = 2; // 2代表标识符
	private int constantNum = 3; // 3代表常数
	private int operationalCharsNum = 4; // 4代表运算符(不包括+-*/=)
	private int delimiterNum = 5; // 5代表界限符号
	private int addAndSubOp = 6; // 6代表加减运算符
	private int mulAndDivOp = 7; // 7代表乘除运算符
	private int assignOp = 8; // 8代表赋值运算符

	private char ch;
	private int index = 0; // 处理的下标
	private String strToken = ""; // 整个标识符
	private int charsSize = 0; // chars中有效字符的大小
	private char[] chars = null; // 输入文件读取到的字符数组

	// 接下来的String数组列出了目前可以识别的标识符、运算符、界符
	private String[] keyWords = { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class",
			"const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float",
			"for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new",
			"package", "private", "protected", "public", "return", "strictfp", "short", "static", "super", "switch",
			"synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while" };
	private String[] operationalChars = { "+", "-", "*", "/", "%", "++", "--", ">", "<", "=", "==", "+=", "-=", "*=",
			"/=", "%=" };
	private String[] Delimiter = { "(", ")", ";", ",", "{", "}", "[", "]" };

	public CodeSannner(int charsSize, char[] chars) {
		super();
		this.charsSize = charsSize;
		this.chars = chars;
	}

	// 获取index位置的字符,同时index向后移动一个位置
	private void getChar() {
		if (index < charsSize) {
			ch = chars[index];
			index++;
		}
	}

	// 判断ch是否为空白符
	// 还要有\r否则会出错
	// TODO
	public boolean isBC() {
		return (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
	}

	// 跳过空白符,直至ch为一非空白符,\r\n在windows的记事本中为换行
	public void getBlankCharacter() {
		while (index < charsSize && isBC()) {
			getChar();
		}
	}

	// 把当前字符ch连接到strToken
	public void concat() {
		strToken = strToken + ch;
	}

	// 判断当前字符ch是否为字母
	public boolean isLetter() {
		return ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'));
	}

	// 判断字符ch是否为数字
	public boolean isDigit() {
		return (ch >= '0' && ch <= '9');
	}

	// 对于strToken中的字符串查找保留字表,若它是保留字则给出他在保留字表中的下标,否则返回-1
	public int reserve() {
		for (int i = 0; i < keyWords.length; i++) {
			if (strToken.equals(keyWords[i])) {
				return i;
			}
		}
		return -1;
	}

	// 把搜索指针回调一个字符位置,同时更新ch
	public void retract() {
		index--;
		ch = chars[index];
	}

	// 判断字符是否为数字、字母、下划线、$
	public boolean isLetterOrDigitOr$Or_() {
		return (ch == '_' || ch == '$' || isLetter() || isDigit());
	}

	// 通过判断首字符,进入不同的判断程序中
	// 本次实验的核心部分
	public Tuple scan() {

		// 获取首字符
		// 这里调用两个函数的顺序不能互换,否则会出错!!
		// TODO
		getChar();
		getBlankCharacter();

		// 标识符的首字符不能以数字开头
		// TODO
		// 首字符是字母下划线$的,可能是标识符或者关键字
		if (isLetterOr$Or_()) {
			while (isLetterOrDigitOr$Or_()) {
				concat();
				getChar();
			}
			retract();
			int keyWordsIndex = -1;
			// 如果不是保留字
			if ((keyWordsIndex = reserve()) == -1) {
				return new Tuple(identifierNum, strToken);
			}
			// 如果是保留字
			else {
				return new Tuple(keyWordsNum, keyWords[keyWordsIndex]);
			}
		}
		// 首字符是数字
		else if (isDigit()) {
			// 处理整数部分
			while (isDigit()) {
				concat();
				getChar();
			}
			// 处理小数点以及之后的整数部分
			if (ch == '.') {
				concat();
				// 获取小数点后第一位字符
				getChar();
				if (isDigit()) {
					// 如果该字符是数字
					while (isDigit()) {
						concat();
						getChar();
					}
				}
				// 报错
				else {
					concat();
					return new Tuple(errorNum, "ERROR INFO: " + new String(strToken));
				}

			}
			// 判断ch是否为e
			if (ch == 'e' || ch == 'E') {
				concat();
				getChar();
				if (ch == '-' || ch == '+') {
					concat();
					getChar();
				}
				if (isDigit()) {
					while (isDigit()) {
						concat();
						getChar();
					}
				}
				// 报错
				else {
					concat();
					return new Tuple(errorNum, "ERROR INFO: " + new String(strToken));
				}
			}
			// 退掉多处理的字符
			retract();
			// 成功走到常数的末尾
			return new Tuple(constantNum, strToken);
		}
		// 首字符不是数字、字母、下划线、$
		else {
			switch (ch) {
			// 界符 5
			case ',':
				concat();
				return new Tuple(delimiterNum, strToken);
			case ';':
				concat();
				return new Tuple(delimiterNum, strToken);
			case '{':
				concat();
				return new Tuple(delimiterNum, strToken);
			case '}':
				concat();
				return new Tuple(delimiterNum, strToken);
			case '[':
				concat();
				return new Tuple(delimiterNum, strToken);
			case ']':
				concat();
				return new Tuple(delimiterNum, strToken);
			case '(':
				concat();
				return new Tuple(delimiterNum, strToken);
			case ')':
				concat();
				return new Tuple(delimiterNum, strToken);
			// 运算符 4
			case '=':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				// 赋值运算符
				return new Tuple(assignOp, strToken);
			case '+':
				concat();
				getChar();
				if (ch == '+') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				} else if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				// 加减法运算符
				return new Tuple(addAndSubOp, strToken);
			case '-':
				concat();
				getChar();
				if (ch == '-') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				} else if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				// 加减法运算符
				return new Tuple(addAndSubOp, strToken);
			case '*':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				// 乘除法法运算符
				return new Tuple(mulAndDivOp, strToken);

			case '/':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				// 乘除法法运算符
				return new Tuple(mulAndDivOp, strToken);
			case '%':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				return new Tuple(operationalCharsNum, strToken);
			case '>':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				return new Tuple(operationalCharsNum, strToken);
			case '<':
				concat();
				getChar();
				if (ch == '=') {
					concat();
					return new Tuple(operationalCharsNum, strToken);
				}
				retract();
				return new Tuple(operationalCharsNum, strToken);
			// 出错处理
			default:
				concat();
				return new Tuple(errorNum, "ERROR INFO: " + new String(strToken));
			}
		}
	}

	private boolean isLetterOr$Or_() {
		return isLetter() || ch == '$' || ch == '_';
	}

	public int getIndex() {
		return index;
	}

	public void clear() {
		strToken = "";
	}
}

上一篇:一、变量和数据类型


下一篇:Python3-接口自动化-12- header定义为字典格式,但是报错:for header in headers.items(): AttributeError: 'tuple'