实验 编译技术综合应用-JAVA文件的自动打点

一、   实验目的

编译原理在JAVA可测试性中的应用。通过对源程序进行分析,在特定位置增加特定的打印语句,方便对程序执行过程的跟踪定位。比如:函数出入口增加打印语句。

  • 实验要求
  1. 读取一个JAVA文件,进行语法解析,在函数出入口增加打印语句,并将改写后的程序更新到JAVA文件中去。

输入: 从控制台读入一个JAVA程序文件

输出:更新后的JAVA程序文件, 增加了打印语句

2. 输入输出文件示例:(仅为示意)

输入文件:

public class helloworld {

   public static int Add(int a, int b){

      int ret;
      ret =a+b;
      return ret; 
   }

   public static void main(String[] args) {

      System.out.println("result="+Add(1,2)); 
   }

}

输出文件:

public class helloworld {

   public static int Add(int a, int b){

      System.out.println("Enter Function helloworld::Add(a="+a+",b="+b+")!");
      int ret;
      ret =a+b;
      System.out.println("Exit  Function helloworld::Add(a="+a+",b="+b+")!");
      return ret;
   }

   public static void main(String[] args) {

      System.out.println("Enter Function helloworld::main(args="+args.toString()+")!");
      System.out.println("result="+Add(1,2)); 
      System.out.println("Exit  Function helloworld::main(args="+args.toString()+")!");
   }

}

下面将上传词法分析,因为我饿了,要去吃饭了,张玲玲老师的编译原理实验课使人秃头


package test0601;

import java.util.ArrayList;
import java.util.Scanner;

/**
 * 项目名称:test 
 * 类名称:lex 
 * 类描述:
 *  
 * @author LYL 
 *Date 2018年12月6日
 */
public class lex {

	// 自定义的枚举类型,单词符号类别定义,与实验的表格要求一致
	public enum symbol {
		period(".", 0), plus("+", 1), minus("-", 2), times("*", 3), slash("/", 4), eql("=", 5), neq("<>", 6),
		lss("<", 7), leq("<=", 8), gtr(">", 9), geq(">=", 10), lparen("(", 11), rparen(")", 12), semicolon(";", 13),
		classsym("class", 14), publicsym("public", 15), privatesym("private", 16), ifsym("if", 17),
		staticsym("static", 18), whilesym("while", 19), returnsym("return", 20), ident("IDENT", 21),
		number("number", 22), nil("nil", 23), voidsym("void", 24), intsym("int", 25), charsym("char", 26),
		stringsym("String", 26), lbracesym("{", 27), rbrace("}", 28), lsquare("[", 29), rsquare("]", 29),
		protectedsym("protected", 30), finalsym("final", 31), commasym(",", 32), langsym("~", 33);

		private String strName;
		private int iIndex;

		private symbol(String name, int index) {
			this.strName = name;
			this.iIndex = index;
		}

		public String getStrName() {
			return strName;
		}

		public void setStrName(String strName) {
			this.strName = strName;
		}

		public int getiIndex() {
			return iIndex;
		}

		public void setiIndex(int iIndex) {
			this.iIndex = iIndex;
		}
	}

	// 单词类定义二元组:(单词类别, 单词名)
	public class aWord {
		String name;
		symbol symtype;

		private aWord(String name, symbol symtype) {
			this.name = name;
			this.symtype = symtype;
		}

		public String toString() {
			return "(" + this.symtype.iIndex + "," + this.name.trim() + ")";
		}
	}

	/********************************************************************************
	 * 变量说明: line 从终端读入的字符串; 当前所指位置在计数器 iCurPos, 字符为ch token 正在识别的单词字符串;当前所指位置在计数器
	 * iIndex sym 每个单词符号种类,来源于symbol, 例:symbol.number keyword 保留字表 , 包括:begin, do,
	 * end , if, then, while(已排好序) Symlist 识别出的符号表,每个元素是一个单词的二元组(sym, token)
	 *********************************************************************************/
	String line;
	int iCurPos = 0; // 当前所指位置在计数器 iCurPos
	char[] token; // 当前所指位置在计数器
	int iIndex = 0; // 当前所指位置在计数器 iInde
	int Err;
	symbol sym;
	String[] keyword = { "if", "while", "String", "class", "boolean", "char", "class", "int", "private", "protected",
			"public", "return", "static", "void" };
	ArrayList<aWord> Symlist;

	// 从终端读入一行程序
	public String getProgram() {
		// 此处需要从控制台输入文件内容 将多行文件处理为单行字符串
		System.out.println("请在此输入并以空行结束");
		StringBuilder str = new StringBuilder();
		Scanner scanner = new Scanner(System.in);
		while (true) {
			String text = scanner.nextLine().trim();
			if ("".equals(text)) {
				break;
			}
			str.append(text);
		}
		// 读取实现
		line = str.toString() + "~";
		return line;
	}

	// 增加一个单词到符号表里
	public void AddaWordtoList() {
		aWord aWord;
		aWord = new aWord((new String(token)).trim(), sym);
		Symlist.add(aWord);
	}

	// Main函数:主入口
	public static void main(String[] args) {
		lex lex = new lex();
		lex.Symlist = new ArrayList<aWord>();
		lex.Symlist.clear();
		lex.line = lex.getProgram();
		lex.iCurPos = 0;
		lex.Err = 0;
		System.out.println("预处理后的字符串:\n" + lex.line + "\n");

		// ==========词法&语法分析:一趟完成==========
//		lex.getSym(); // 向前看
		while ((lex.iCurPos < lex.line.length()) && (lex.line.charAt(lex.iCurPos) != '~')) {
			lex.getSym();
			// 把单词加到符号表中去
			lex.AddaWordtoList();
		}
		System.out.println("程序开始输出单词表");
		// 输出单词符号表
		for (int i = 0; i < lex.Symlist.size(); i++) {
			System.out.print(lex.Symlist.get(i).toString().trim() + " ");
			// 这个判断是为了格式化输出代码,在后期输出代码的过程中可以借鉴使用,哪里该加向后空格,哪里该向前空格,还是忙意思的
			if (lex.Symlist.get(i).name.equals(";") || lex.Symlist.get(i).name.equals("{")
					|| lex.Symlist.get(i).name.equals("}")) {
				System.out.println();
				System.out.print("    ");
			}
			
		}
		// 将文件写到新的文件中,多次操作覆盖原文件,懒的话就打印到控制台
		

		System.out.println("\n**********程序运行结束**********");
	}

	public void getSym() {
		boolean flag = false;
		iIndex = 0;
		token = new char[20];
		sym = symbol.nil;

		char ch = line.charAt(iCurPos++); // 当前指针所指字符,iCurPos全局指针,iIndex字符串局部指针

		/*********************************************************
		 *
		 *************** TODO: 单词识别 ***************
		 * 
		 * 只需要做的是:针对不同的字符识别出相应的 token 和 sym 值
		 *
		 *********************************************************/

		while (ch == ' ') {// 遇到空则继续读取下一个值,
			ch = line.charAt(iCurPos++);
		}

		if (ch >= '0' && ch <= '9') {
			// 继续读取数字,直到非数字出现
			do {
				token[iIndex++] = ch;
				ch = line.charAt(iCurPos++);
			} while (ch >= '0' && ch <= '9');
			// 去掉最后一次判断累加的1
			iCurPos--;
			// 处理数字
			sym = symbol.number;

		} else if (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z') {
			// 处理begin, do, end , if, then, while
			// 一直读单词直到再次读到非字母非数字
			do {
				token[iIndex++] = ch;
				ch = line.charAt(iCurPos++);
			} while (ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z' || ch >= '0' && ch <= '9');
			// 去掉最后一次判断累加的1
			iCurPos--;
			// char与String类型转换,去掉空格并且赋给key
			String key = String.valueOf(token).trim();

			// 匹配关键字

			for (int i = 0; i < keyword.length; i++) { // 表示取出数组keyword[]中的每一个元素,就是循环一次
				String string = keyword[i];
				if (string.equals(key)) {
					// 匹配枚举类的value()
					for (symbol c : symbol.values()) {
						String str = c.getStrName();
						if (str.equals(key)) {
							sym = c;
							// 修改标记
							flag = true;
							break;
						}
					}
					break;
				}
			}
			if (!flag) {
				sym = symbol.ident;
			}
		} else
			// 处理特殊字符
			switch (ch) {
			case '=': {
				token[iIndex] = ch;
				sym = symbol.eql;
				break;
			}
			case ',': {
				token[iIndex] = ch;
				sym = symbol.semicolon;
				break;
			}
			case '+': {
				token[iIndex++] = ch;
				sym = symbol.plus;
				break;
			}
			case '-': {
				token[iIndex++] = ch;
				sym = symbol.minus;
				break;
			}
			case '*': {
				token[iIndex++] = ch;
				sym = symbol.times;
				break;
			}
			case '"': // "打印的内容"
			{
				token[iIndex++] = ch;
				sym = symbol.times;
				break;
			}

			case '(': {
				token[iIndex++] = ch;
				sym = symbol.lparen;
				break;
			}
			case ')': {
				token[iIndex++] = ch;
				sym = symbol.rparen;
				break;
			}
			case ';': {
				token[iIndex++] = ch;
				sym = symbol.semicolon;
				break;
			}
			case '{': {
				token[iIndex++] = ch;
				sym = symbol.lbracesym;
				break;
			}
			case '}': {
				token[iIndex++] = ch;
				sym = symbol.rbrace;
				break;
			}
			case '[': {
				token[iIndex++] = ch;
				sym = symbol.lsquare;
				break;
			}
			case ']': {
				token[iIndex++] = ch;
				sym = symbol.rsquare;
				break;
			}
			case '.': {
				token[iIndex++] = ch;
				sym = symbol.period;
				break;
			}
			case '~': { // 作为结束标识符
				break;
			}
			}
		// 没有匹配到合适的单词符号,出错处理
		if (sym == symbol.nil) {
			System.out.println("Error: Position " + iCurPos + " occur the unexpected char \'" + ch + "\'.");
		}
	}
}

词法分析截图

我就分享到这里,下面的就自己动手把!

或者可以去用csdn积分去下载我的完整版项目代码,项目名称:南京晓庄学院编译原理实验六-JAVA文件的自动打点

我接下来的思路有两种:

第一种:直接对字符表进行操作,当字符找到需要打印的语句是就插入一个打印,可实现

第二种:进行语法分析,在语法分析的过程中检测到字符,拼接字符串加入Symlist中,可实现

有问题可Email留言:lyl94207@163.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

foreverlove111

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值