【任务】完成以下描述的Java词法分析器
1、标识符的语法规则:
·标识符由字母、下划线、美元符号和数字组成,长度不受限制。
·标识符的第一个字符不能是数字字符。
·标识符不能是关键字。
·标识符不能是true、false和null(尽管不是Java关键字)。
2、Java关键字(50个)。
3、运算符(算术运算符、关系运算符、位运算符、逻辑运算符、赋值运算符、条件运算符)。
4、分界符(.,,,;,’,",{,},(,),[,])。
5、区分大小写,字母a-z,A-Z,数字0-9.
6、"/…/","//"为注释部分(应为斜杠,java中会无法匹配注释部分)。
要求】
1、给出各单词符号的类别编码。
2、词法分析程序应能发现输入串中的错误。
3、词法分析作为单独一遍编写,词法分析结果为二元式序列组成的中间文件。
4、设计两个测试用例(尽可能完备),并给出测试结果。
public class JavaLexer {
// java中的50个关键字;
public static String[] keyWords = { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char",
"class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "final", "fianlly",
"float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native",
"new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super",
"switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while" };
// 算术运算符
public static String[] arithmeticOperation = { "+", "-", "*", "/", "%", "++", "--" };
// 关系运算符
public static String[] relationOperation = { "<", ">", "<=", ">=", "==", "!=" };
// 位运算符
public static String[] bitOperation = { "&", "|", "^", "~", "<<", ">>", ">>>" };
// 逻辑运算符
public static String[] logicOperation = { "&&", "||", "!" };
// 赋值运算符
public static String[] assignmentOperation = { "=", "+=", "-=", "/=", "*=", "%=", "<<=", ">>=", "&=", "^=", "|=" };
//标识符由不是数字开头,$、_、字母(区分大小写)和数字组成(true、false、null和关键字不是标识符)不限长度的字符串。
public static String[] noIdentifier = { "true", "false", "null" };
// 分界符 (\"在此指的是",java中用转义字符输出原字符)
public static String[] limiterWords = { ".", ",", ";", "[", "]", "{", "}", "(", ")", "\"", "'", ":" };
// 单元运算符
public static String[] unaryOperation = { "+", "-", "*", "/", "%", "<", ">", "&", "|", "^", "~", "!", "=" };
// 双元运算符
public static String[] binaryOperation = { "++", "--", "<=", ">=", "==", "!=", "<<", ">>", "&&", "||", "+=", "-=",
"/=", "*=", "%=", "&=", "^=", "|=" };
// 三元运算符
public static String[] ternaryOperation = { ">>>", "<<=", ">>=" };
/**
*
* @作者:John丶woo
* @描述:判断是否为数字串,是就返回种别码,否就返回0;
* @param s
* @return
*/
public int isNum(String s) {
int flag = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) <= '9' && s.charAt(i) >= '0') {
flag = 98;
//出现不是数字的字符,跳出循环;
} else {
flag = 0;
break;
}
}
return flag;
}
/**
*
* @作者:John丶woo
* @描述:判断是否为分界符,是就返回种别码,否就返回0;
* @param s
* @return
*/
public int isLimiterWords(String s) {
int flag = 0;
for (int i = 0; i < limiterWords.length; i++) {
if (limiterWords[i].equals(s)) {
flag = 85 + i;
break;
}
}
return flag;
}
/**
*
* @作者:John丶woo
* @描述:判断是否为运算符,是就返回种别码,否就返回0;
* @param s
* @return
*/
public int isOperation(String s) {
int flag = 0;
// 判断是否为算数运算符
for (int i = 0; i < arithmeticOperation.length; i++) {
if (arithmeticOperation[i].equals(s)) {
flag = 51 + i;
break;
}
}
// 判断是否为关系运算符
for (int j = 0; j < relationOperation.length; j++) {
if (relationOperation[j].equals(s)) {
flag = 58 + j;
break;
}
}
// 判断是否为位运算符
for (int l = 0; l < bitOperation.length; l++) {
if (bitOperation[l].equals(s)) {
flag = 64 + l;
break;
}
}
// 判断是否为逻辑运算符
for (int m = 0; m < logicOperation.length; m++) {
if (logicOperation[m].equals(s)) {
flag = 71 + m;
break;
}
}
// 判断是否为赋值运算符
for (int n = 0; n < assignmentOperation.length; n++) {
if (assignmentOperation[n].equals(s)) {
flag = 74 + n;
break;
}
}
return flag;
}
/**
*
* @作者:John丶woo
* @描述:判断是否为关键字,是就返回种别码,否就返回0;
* @param s
* @return
*/
public int isKeyWords(String s) {
int flag = 0;
for (int i = 0; i < keyWords.length; i++) {
if (keyWords[i].equals(s)) {
flag = i + 1;
break;
}
}
return flag;
}
/**
*
* @作者:John丶woo
* @描述:判断该字符是否为标识符或者关键字,是就返回种别码,否就返回0;
* @param s
* @return
*/
public int isIdentifier(String s) {
int flag = 0;
// 当该字符串全为字母时;
if (s.matches("[a-zA-Z]+")) {
// 关键字
if (isKeyWords(s) > 0) {
flag = isKeyWords(s);
}
else {
for (int i = 0; i < noIdentifier.length; i++) {
// 该字符串为"true","false","null";
if (noIdentifier[i].equals(s)) {
flag = 99 + i;
break;
}
flag = 97;
}
}
}
// 判断字符串首字符是否为"$","_"或者字母;
else if (s.indexOf("$") == 0 || s.indexOf("_") == 0
|| (s.charAt(0) >= 'a' && s.charAt(0) <= 'z'
|| s.charAt(0) >= 'A' && s.charAt(0) <= 'Z')) {
// 遍历字符串;
for (int i = 1; i < s.length(); i++) {
// 检查字符串中是否存在不是标识符组成元素;
if ((s.charAt(i) >= 'a' && s.charAt(i) <= 'z'
|| s.charAt(i) >= 'A' && s.charAt(i) <= 'Z')
|| s.charAt(i) >= '0' && s.charAt(i) <= '9'
|| s.charAt(i) == '$' || s.charAt(i) == '_') {
flag = 97;
// 存在不为标识符组成元素,即刻跳出循环;
} else {
flag = 0;
break;
}
}
}
return flag;
}
/**
*
* @作者:John丶woo
* @描述:打印分析结果(二元式序列组成的中间文件);
*/
public void codePrinting(int a, String s) {
System.out.println("<" + a + "," + s + ">");
}
/**
*
* @作者:John丶woo
* @描述:深层分析未能直接解析的字符串。
* @param s
*/
public void splitString(String s) {
int num = -1;
String[] str = s.split("");
for (int i = 0; i < str.length; i++) {
if (i <= num) {
continue;
}
num = -1;
// 判断是否存在运算符
for (int j = 0; j < unaryOperation.length; j++) {
// 当匹配到为单元运算符时
if (unaryOperation[j].equals(str[i])) {
// 判断是否到字符串结尾部分
if (i + 1 < s.length()) {
for (int l = 0; l < binaryOperation.length; l++) {
// 当匹配到为双元运算符时
if (binaryOperation[l].equals(s.substring(i, i + 2))) {
// 判断是否到字符串结尾部分
if (i + 2 < s.length()) {
for (int m = 0; m < ternaryOperation.length; m++) {
// 当匹配到三元运算符时
if (ternaryOperation[m].equals(s.substring(i, i + 3))) {
codePrinting(isOperation(s.substring(i, i + 3)), s.substring(i, i + 3));
num = i + 2;
break;
}
}
// 不是三元运算符输出双元运算符
if (num != i + 2) {
codePrinting(isOperation(s.substring(i, i + 2)), s.substring(i, i + 2));
num = i + 1;
break;
}
// 字符串长度到底,直接输出双元运算符
} else {
codePrinting(isOperation(s.substring(i, i + 2)), s.substring(i, i + 2));
num = i + 1;
break;
}
}
}
// 当没有匹配到双元或者三元运算符时,输出单元运算符
if (num == -1) {
codePrinting(isOperation(str[i]), str[i]);
num = 0;
break;
}
// 字符串长度到底,直接输出单元运算符
} else {
codePrinting(isOperation(str[i]), str[i]);
num = 0;
break;
}
}
}
// 判断是否匹配到运算符,匹配到时值不为-1
if (num != -1) {
continue;
}
// 判断是否为分界符
if (isLimiterWords(str[i]) > 0) {
codePrinting(isLimiterWords(str[i]), str[i]);
continue;
}
// 判断是否存在数字
else if(s.charAt(i) <= '9' && s.charAt(i) >= '0') {
int n = i;
for(int j=i+1; j<str.length;j++) {
if(s.charAt(j) <= '9' && s.charAt(j) >= '0') {
n = j;
}else {
break;
}
}
if(n>i) {
codePrinting(98, s.substring(i, n+1));
num = n;
continue;
}else {
codePrinting(98, str[i]);
continue;
}
// 判断是否存在标识符
// 当字符为"$"、"_"开头时
} else if (str[i] == "$" || str[i] == "_") {
int n = i;
for (int j = i + 1; j < s.length(); j++) {
if (str[j] == "$" || str[j] == "_"
|| s.charAt(j) >= 'a' && s.charAt(j) <= 'z'
|| s.charAt(j) >= 'A' && s.charAt(j) <= 'Z'
|| s.charAt(j) <= '9' && s.charAt(j) >= '0') {
n = j;
} else {
break;
}
}
if (n > i) {
codePrinting(97, s.substring(i, n + 1));
num = n;
continue;
} else {
codePrinting(97, str[i]);
continue;
}
// 判断是否存在标识符、特殊字符或者关键字
// 当字符是字母开头时
} else if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z'
|| s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
int n = i;
for(int j = i+1; j<s.length();j++) {
if (s.charAt(j) >= 'a' && s.charAt(j) <= 'z' || s.charAt(j) >= 'A' && s.charAt(j) <= 'Z') {
n = j;
}else {
break;
}
}
if (n > i) {
// 关键字
if (isKeyWords(s.substring(i, n + 1)) > 0) {
codePrinting(isKeyWords(s.substring(i, n + 1)), s.substring(i, n + 1));
num = n;
continue;
} else {
// 特殊字符
for (int j = 0; j < noIdentifier.length; j++) {
if (noIdentifier[j].equals(s.substring(i, n + 1))) {
codePrinting(99 + j, noIdentifier[j]);
num = n;
break;
}
}
}
if (num != n) {
// 标识符
codePrinting(97, s.substring(i, n + 1));
num = n;
continue;
} else {
continue;
}
} else {
// 标识符
codePrinting(97, str[i]);
continue;
}
}else {
System.out.println("<未知字符!,"+str[i]+">");
}
}
}
/**
*
* @作者:John丶woo
* @描述:运行分析器;
*/
public void runLexer() {
String[] str;
//输入测试文件的路径;
String path = "F:\\Document\\你的测试文件地址\\编译原理\\testFile.txt";
try {
FileReader fileReader = new FileReader(path);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String strLine = null; // 存储每行的文件信息
int lineIndex = -1, num = 0, lastIndex = -1, firstIndex = -1;
// 一行一行打印文件信息
while ((strLine = bufferedReader.readLine()) != null) {
// firstIndex多行注释开始符号“/*”位置
firstIndex = strLine.indexOf("/*");
// lastInedx多行注释结束符号“*/”位置
lastIndex = strLine.indexOf("*/");
// 等于0时,代表“/*”不存在,不需要匹配“*/”。
if(num == 0) {
if(firstIndex >= 0) {
strLine = strLine.substring(0, firstIndex);
num =1;
} else {
strLine = strLine.substring(0);
}
// 等于1时,代表“/*”已经存在,匹配“*/”。
}else if (num == 1) {
// 匹配不成功,跳出循环
if(lastIndex < 0) {
continue;
// 匹配成功,重新赋值0
}else {
strLine = strLine.substring(lastIndex+2);
num = 0;
}
}
// 判断该行字符串是不是空格
if (strLine.length() <= 0) {
continue;
}
// 单行注释符的位置,index之后的为注释
lineIndex = strLine.trim().indexOf("//");
if (lineIndex < 0) {
str = strLine.trim().split("[ \\t\\n\\x0B\\f\\r]");
// 注释符在开头直接跳出循环
} else if (lineIndex == 0) {
continue;
} else {
str = strLine.trim().substring(0, lineIndex).split("[ \\t\\n\\x0B\\f\\r]");
}
for (int i = 0; i < str.length; i++) {
// 输出分界符
if (isLimiterWords(str[i]) > 0) {
codePrinting(isLimiterWords(str[i]), str[i]);
// 输出数字串
} else if (isNum(str[i]) > 0) {
codePrinting(isNum(str[i]), str[i]);
// 输出运算符
} else if (isOperation(str[i]) > 0) {
codePrinting(isOperation(str[i]), str[i]);
// 输出标识符和关键字
} else if (isIdentifier(str[i]) > 0) {
codePrinting(isIdentifier(str[i]), str[i]);
// 其他暂时未识别的字符串
} else {
splitString(str[i]);
}
}
}
bufferedReader.close();
}
catch (Exception e) {
//输出异常
System.out.println(e);
}
}
}
大家可以用一个测试文件运行一下,(生成二元式序列组成的中间文件);
public class Compiler {
public static void main(String[] args) {
JavaLexer javaLexer = new JavaLexer();
javaLexer.runLexer();
}
}
我的测试文件内容时这样的;
新手出道不喜勿喷,有什么意见或者想法都可以跟我交流,十分感谢大家。