前言
又到了做实验的时候了,而且是编译原理的实验,课程内容还没怎么听懂呢,但是也只能硬着头皮上了。
实现
我们先来看看实验要求吧:
允许用户自己输入程序并保存为文件
系统能够输出经过预处理后的源程序(去掉注释、换行、空格等)
能够将该源程序中所有的单词根据其所属类型(整数、保留字、运算符、标识符等。定义的类C 语言中的标识符只能以字母或下划线开头)进行归类显示,例如:识别保留字:if、int、for、while、do、return、break、continue 等,其他的都识别为标识符;常数为无符号整形数;运算符包括:+、-、*、/=、>、<、>=、<=、!=等;分隔符包括:,、;、{、}、(、)等。
实现文件的读取操作,而不是将文本以字符串形式预存于程序中。文本内容为待分析的类 C 语言程序。
我们先来看一看从控制台输入的程序和最后的结果。
运行结果如下:
直接上源码了:
MyMain.java
package java_project;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class MyMain{
Set<String> keyWordsSet = new HashSet<String>();
Set<String> operatorSet = new HashSet<String>();
Set<String> separatorSet= new HashSet<String>();
String fileStr = "",currentStr="";
int index = -1;
public static void main(String[] args){
MyMain my = new MyMain();
MyUtil.readProgram();
my.initSets();
my.readFile();
my.start();
}
private void start(){
for(int i=0;i<fileStr.length();i++){
currentStr = "";
String s = fileStr.charAt(i)+"";
index = i;
if(Character.isLetter(fileStr.charAt(i))||s.equals("_")){
dealLetter();
}else if(Character.isDigit(fileStr.charAt(i))){
dealDigit();
}else if(separatorSet.contains(s)){
dealSeparator();
}else if(operatorSet.contains(s)||s.equals("!")){
dealOperator();
}
i = index;
}
}
/**
* 初始化集合
*/
private void initSets(){
String keyWords[] = {"if","int","for","while","do","return","break","continue"};
keyWordsSet.addAll(Arrays.asList(keyWords));
String operators[] = {"+","-","*","/","=",">","<",">=","<=","!="};
operatorSet.addAll(Arrays.asList(operators));
String separators[] = {",",";","{","}",")","("};
separatorSet.addAll(Arrays.asList(separators));
}
/**
* 初始化需要读取的程序文件
*/
private void readFile(){
try {
InputStreamReader reader = new InputStreamReader(new FileInputStream("jc.c"));
int temp;
while((temp=reader.read())!=-1)
fileStr+=((char)temp);
} catch (Exception e){}
}
private void dealLetter(){
currentStr+=fileStr.charAt(index);
for(int i=index+1;i<fileStr.length();i++){
String s = fileStr.charAt(i)+"";
index = i;
if(s.equals("_")||Character.isLetterOrDigit(fileStr.charAt(i))){
currentStr+=fileStr.charAt(i);
}else{
break;
}
}
index--;
if(keyWordsSet.contains(currentStr)){
System.out.println("(1,"+"\""+currentStr+"\")");
}else{
System.out.println("(2,"+"\""+currentStr+"\")");
}
}
private void dealDigit(){
currentStr+=fileStr.charAt(index);
for(int i=index+1;i<fileStr.length();i++){
index = i;
if(Character.isDigit(fileStr.charAt(i))){
currentStr+=fileStr.charAt(i);
}else{
break;
}
}
index--;
System.out.println("(3,"+"\""+currentStr+"\")");
}
private void dealSeparator() {
currentStr+=fileStr.charAt(index);
System.out.println("(5,"+"\""+currentStr+"\")");
}
private void dealOperator(){
currentStr = fileStr.charAt(index)+"";
if(index+1<fileStr.length()){
String s1 = fileStr.charAt(index)+"";
s1 += fileStr.charAt(index+1)+"";
if(operatorSet.contains(s1)){
System.out.println("(4,"+"\""+s1+"\")");
index++;
}else{
System.out.println("(4,"+"\""+currentStr+"\")");
}
}else{
System.out.println("(4,"+"\""+currentStr+"\")");
}
}
}
MyUtil.java
package java_project;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
public class MyUtil {
public static String readProgram(){
String str = "";
Scanner reader = new Scanner(System.in);
System.out.println("请输入源程序(以#end#作为输入结束的标志):");
while(true){
String _S = reader.nextLine();
str+=_S+"\n";
if(_S.endsWith("#end#")){
str = str.replace("#end#", "");
break;
}
}
writeStrToFile(str);
return str;
}
private static void writeStrToFile(String str){
String s = dealString(str);
try {
FileWriter writer = new FileWriter("jc.c");
writer.write(s);
writer.flush();
writer.close();
} catch (IOException e){}
}
private static String dealString(String str){
str = str.replaceAll("//.{0,}\n",""); //处理类型为 //的注释/
str = str.replaceAll("\\s{1,}", " "); //处理空格和回车,把几个空格合并成一个
str = str.replaceAll("/[*].{0,}[*]/", ""); //处理类型为 /**/ 的注释
return str;
}
}
分析
实现的思路比较简单,因为需要从控制台输入程序,所以 我先得到输入的字符串,然后对字符串进行预处理,去除注释,回车,以及把连续的空格换成一个空格,就可以把处理之后的字符串写入文件里。接着所有的字符从文件里读取出来放在字符串中,然后从第一个字符串开始判断,如果该字符是字母或下划线,那么就有可能是标识符或者是关键字,如果是数字那么就是整数型,如果是分隔符或者运算符,这些都是比较好考虑的,然后继续判断下一个字符,直到遇到的字符不是与前面字符不是同一类的字符,那么字符读取完毕,接下来判断该单词到底是哪一个类型并将单词输出。然后从刚才停止的位置开始,继续读取单词进行判断,直到读取完毕。
【源码下载】