Java ExamplesZ-transformation题目输入输出用例ImplementsLiteral题目要求示例输入说明ImplementsMatrixCalculationImplementsStream题目要求 示例ImplementsCSVFile题目要求示例输出ResponseTime题目要求示例ImplementsFindPrimes 找质数题目要求输入格式输出格式示例 CurrencyExchange题目要求示例Bad MatrixImplementsMy MatrixImplementsTicTacToeLambda IntepreterAST.javaAbstraction.javaApplication.javaIdentifier.javaTokenType.javaLexer.javaParser.java
从控制台中读入一行字符串,随后读入一行数字N。
输出该字符串经过N行的Z型变换后的结果。
Z型变换的形式见用例。
第一行为待处理的字符串。
第二行为需要变换成的行数N。1<=N<=10
N行经过变换后的字符串。
输入:
12345678904
输出:
xxxxxxxxxx1 72 6 83 5 94 0
解释:Z型变换将字符串分为了N行,随后按照Z字形的顺序逐个向每行填入字符。
输入:
xxxxxxxxxxhelloworld3
输出:
xxxxxxxxxxh o le l w r dl o
请注意每行字符间的空格。
xxxxxxxxxx请修改src/main/java/ZTransformation.java中的main方法以完成本次作业
ximport java.util.Scanner;import java.util.*;public class ZTransformation { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str = scanner.nextLine(); int rows = scanner.nextInt(); if(rows==1){ for (int i = 0; i < str.length()-1; i++) { System.out.print(str.charAt(i)); System.out.print(" "); } System.out.print(str.charAt(str.length()-1)); return; } else if(rows > str.length()){ for (int i = 0; i < str.length()-1; i++) { System.out.println(str.charAt(i)); } System.out.print(str.charAt(str.length()-1)); return; } int circle = 2*rows-2; for (int row = 1; row <= rows; row++) { if(row == 1 || row == rows){ for (int j = row-1; j < str.length(); j+= circle) { System.out.print(str.charAt(j)); if(j+circle >= str.length()) continue; for (int k = 0; k < 2*(rows - 2) + 1; k++) { System.out.print(" "); } } }else{ for (int j = row-1; j < str.length(); j+= circle) { int begin = j; int end = (j/circle) * circle + circle - row+1; System.out.print(str.charAt(begin)); if(end >= str.length()) { continue; } for (int i = 0; i < 2*(rows - row - 1)+1; i++) { System.out.print(" "); } System.out.print(str.charAt(end)); if(begin + circle >= str.length()) { continue; } for (int i = 0; i < 2 * (row - 1) - 1; i++) { System.out.print(" "); } } } System.out.println(); } }}
从控制台中输入一个“字面量”字符串。判断这个字符串在java中对应哪种类型,并将其输出。
输入:
xxxxxxxxxx1
输出:
xxxxxxxxxxinteger
输入:
xxxxxxxxxx1L
输出:
xxxxxxxxxxlong
输入:
xxxxxxxxxx1.14f
输出:
xxxxxxxxxxfloat
输入:
xxxxxxxxxx'a'
输出:
xxxxxxxxxxchar
输入一定能对应一种基本数据类型。
xxxxxxxxxx请修改src/main/java/Literal.java中的main方法以完成本次作业
xxxxxxxxxximport java.util.Scanner;public class Literal { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String input = scanner.nextLine(); if (isNumber(input)) { System.out.println("integer"); } else if (isLong(input)) { System.out.println("long"); } else if (isDouble(input)) { System.out.println("double"); } else if (isFloat(input)) { System.out.println("float"); } else if (isBoolean(input)) { System.out.println("boolean"); } else if (isChar(input)) { System.out.println("char"); } } public static boolean isNumber(String input) { try { Integer.parseInt(input); return true; } catch (NumberFormatException e) { return false; } } //judge whether the input is a long like 123L public static boolean isLong(String input) { try { Long.parseLong(input.substring(0, input.length() - 1)); return true; } catch (NumberFormatException e) { return false; } } public static boolean isFloat(String input) { try { Float.parseFloat(input); if (input.charAt(input.length() - 1) != 'f') { return false; } return true; } catch (NumberFormatException e) { return false; } } public static boolean isChar(String input) { try { Character.valueOf(input.charAt(0)); return true; } catch (NumberFormatException e) { return false; } } public static boolean isDouble(String input) { try { Double.parseDouble(input); if(input.charAt(input.length()-1)=='f'){ return false; } return true; } catch (NumberFormatException e) { return false; } } public static boolean isBoolean(String input) { if(input.equals("true")||input.equals("false")){ return true; } else { return false; } }}实现矩阵的加法、乘法以及控制台输出
其中加法和乘法需要有两种实现方式
所有的数据均为int型
输入数据均默认为正确数据,不需要对输入数据进行校验
xxxxxxxxxxpackage edu.nju;import java.io.*;/** * 实现矩阵的加法、乘法以及控制台输出 * 其中加法和乘法需要有两种实现方式 * 1.传入一个矩阵进行2个矩阵的操作 * 2.从控制台(console)读入一个矩阵,再进行操作 * 所有的数据均为int型 * 输入数据均默认为正确数据,不需要对输入数据进行校验 * @author Ray Liu & Qin Liu */public class MatrixCalculation { /** * 实现矩阵加法,返回一个新的矩阵 * @return result matrix = A + B */ public int[][] plus(int[][] A, int[][] B){ int m = A.length; if(m==0) return A; int n = A[0].length; int[][] result = new int[m][n]; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ result[i][j] = A[i][j] + B[i][j]; } } return result; } /** * 实现矩阵乘法,返回一个新的矩阵 * @return result matrix = A * B */ public int[][] times(int[][] A, int[][] B){ int m = A.length; if(m==0) return A; int n = A[0].length; int p = B[0].length; int[][] result = new int[m][p]; for(int i = 0; i < m; i++){ for(int j = 0; j < p; j++){ for(int k = 0; k < n; k++){ result[i][j] += A[i][k] * B[k][j]; } } } return result; } /** * 从控制台读入矩阵数据,进行矩阵加法,读入数据格式如下: * m n * m * n 的数据方阵,以空格隔开 * 连续读入2个矩阵数据 * example: 4 3 1 2 3 1 2 3 1 2 3 1 2 3 4 3 1 2 3 1 2 3 1 2 3 1 2 3 * 返回一个新的矩阵 */ public int [][] plusFromConsole(){ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); int[][] matrix =readFromConsole(reader); int[][] matrix2 = readFromConsole(reader); return plus(matrix, matrix2); } /** * 输入格式同上方法相同 * 实现矩阵的乘法 * 返回一个新的矩阵 */ public int[][] timesFromConsole(){ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); int[][] matrix = readFromConsole(reader); int[][] matrix2 = readFromConsole(reader); return times(matrix, matrix2); } /** * 打印出该矩阵的数据 * 起始一个空行,结束一个空行 * 矩阵中每一行数据呈一行,数据间以空格隔开 * example: * * 1 2 3 * 1 2 3 * 1 2 3 * 1 2 3 * */ public int[][] readFromConsole(BufferedReader reader){ int[][] matrix = null; try { // 读取矩阵的行数和列数 String[] dimensions = reader.readLine().split(" "); int rows = Integer.parseInt(dimensions[0]); int cols = Integer.parseInt(dimensions[1]); // 读取矩阵 matrix = new int[rows][cols]; for (int i = 0; i < rows; i++) { String[] rowValues = reader.readLine().split(" "); for (int j = 0; j < cols; j++) { matrix[i][j] = Integer.parseInt(rowValues[j]); } } } catch (IOException e) { e.printStackTrace(); } return matrix; } public void print(int[][] A){ System.out.println(); int m = A.length; int n = A[0].length; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ if(j!=n-1) System.out.print(A[i][j] + " "); else System.out.print(A[i][j]); } System.out.println(); } } //test in the main class}假如给定一个名称列表,其中一些名称包含一个字符。系统会要求您在一个逗号分隔的字符串中返回名称,该字符串中不包含单字母的名称,每个名称的首字母都大写。
分别用命令式范式和函数式范式实现。
注意:使用英文标点符号。
对于 List("neal", "s", "stu", "j", "rich", "bob"),输出为: Neal,Stu,Rich,Bob
xxxxxxxxxximport java.util.ArrayList;import java.util.List;import java.lang.String;import java.util.stream.Collectors;public class Stream { // 使用命令式范式实现 public static String getNamesStringImperatively(List<String> nameList) { String result = ""; int lenth = nameList.size(); for (int i = 0; i < lenth; i++) { String name = nameList.get(i); if (name.length() != 1) { String firstcc = name.substring(0, 1).toUpperCase(); String rest = name.substring(1); name = firstcc + rest; result += name + ","; } } if (result.length() != 0) return result.substring(0, result.length() - 1); else return result; } //implement getNamesStringFunctionally public static String getNamesStringFunctionally(List<String> nameList) { String result = ""; //get the stream combined and filtered and clear the last comma result = nameList.stream() .filter(name -> name.length() > 1) .map(name -> name.substring(0, 1).toUpperCase() + name.substring(1)) .collect(Collectors.joining(",")); return result; }}编写一个程序,读入以下数据文件:
Ling,Mai,55900
Johnson,Jim,56500
Zarnecki,Sabrina,51500
处理该记录,并以格式化的表格形式显示结果,间隔均匀(4个空格)。
注意:标点符号均为英文标点符号。
Last First Salary
Ling Mai 55900
Johnson Jim 56500
Zarnecki Sabrina 51500
xxxxxxxxxximport java.io.*;public class CSVFile { public static void main(String[] args) { String filePath = CSVFile.class.getClassLoader().getResource("data.txt").getPath(); printCSVFile(filePath); } public static void printCSVFile(String filePath){ String[] array= new String[100]; int i = 0; try(BufferedReader br = new BufferedReader(new FileReader(filePath))){ String line; while((line = br.readLine()) != null){ array[i++]=array_Proc(line); } } catch(Exception e) { e.getStackTrace(); } System.out.println("Last First Salary"); for(int j=0;j<i-1;j++) System.out.println(array[j]); System.out.println(array[i-1]); } public static String array_Proc(String line){ String[] array = line.split(","); return array[0] + " " + array[1] + " " + array[2]; }}编写一个程序,提示输入某个网站的响应时间,以毫秒表示,不断让用户输入值,直到用户输入“done”。该程序应打印平均时间(mean),最小时间(min),最大时间(max)和标准差(standard deviation)。
注意:所有输入均为正整数,平均值和标准差保留两位小数,其他输出为整数。
输出: Enter a Number:
输入: 100
输出: Enter a Number:
输入: 200
输出: Enter a Number:
输入: 1000
输出: Enter a Number:
输入: 300
输出: Enter a Number:
输入: done
输出: Numbers:100,200,1000,300
输出: The average is 400.00.
输出: The minimum is 100.
输出: The maximum is 1000.
输出: The standard deviation is 353.55.
xxxxxxxxxximport java.util.Scanner;import java.text.DecimalFormat;public class ResponseTimeCalculation { public static void main(String[] args){ DecimalFormat df = new DecimalFormat("#.##"); int[] nums = new int[100]; int i = 0; Scanner input = new Scanner(System.in); System.out.println("Enter a number:"); String temp = input.nextLine(); while(!temp.equals("done")){ nums[i++] = Integer.parseInt(temp); System.out.println("Enter a number:"); temp = input.nextLine(); } System.out.print("Numbers:"); for(int j=0;j<i;j++){ System.out.print(nums[j]); if(j!=i-1){ System.out.print(","); } } System.out.println(); System.out.printf("The average is %.2f.\n",average(nums,i)); System.out.println("The minimum is " + min(nums,i)+"."); System.out.println("The maximum is " + max(nums,i)+"."); System.out.printf("The standard deviation is %.2f.\n",standardDeviation(nums,i)); } public static double average(int[] nums,int length){ int sum = 0; for(int i = 0; i < length; i++){ sum += nums[i]; } //control the precision of the result and limit to two decimal places return (double)sum/ (double)length; } public static int min(int[] nums,int length){ int min = nums[0]; for(int i = 0; i < length; i++){ if(nums[i] < min){ min = nums[i]; } } return min; } public static int max(int[] nums,int length){ int max = nums[0]; for(int i = 0; i < length; i++){ if(nums[i] > max){ max = nums[i]; } } return max; } public static double standardDeviation(int[] nums,int length){ double sum = 0; double average = average(nums,length); for(int i = 0; i < length; i++){ sum += Math.pow(nums[i] - average, 2); } return Math.sqrt(sum / length); }}是不是所有的偶数(除了 2),都可以用两个质数相加得到呢?
第一行输入仅一个整数 t 表示测试组数。 接下来 t 行,每行仅一个整数 n
输出两个整数,空格隔开,因为答案可能有多个,所有要求输出的这两个整数是所有答案中字典序最小的
输入:
3
4
8
20
输出:
2 2
3 5
3 17
xxxxxxxxxximport java.util.Scanner;public class FindPrimes { public static void main(String[] args) { Scanner input = new Scanner(System.in); int num = input.nextInt(); int temp; for(int i=1;i <= num;i++) { temp = input.nextInt(); //we need to express the temp as the sum of two primer numbers for(int j = 2;j<= temp;j++) { if(isPrime(j) && isPrime(temp-j)) { System.out.println(j + " " + (temp-j)); break; } } } } private static boolean isPrime(int i) { for(int j = 2;j <= Math.sqrt(i);j++) { if(i%j == 0) return false; } return true; }}编写一个货币兑换程序,将欧元兑换成美元。提示输入手中的欧元数,以及欧元的当前汇率。打印可以兑换的美元数。
注意:使用英文标点符号,输出中的数字保留两位小数。
输出: How many euros are you exchanging?
输入: 81
输出: What is the exchange rate?
输入: 137.51
输出: 81.00 euros at an exchange rate of 137.51 is 111.38 U.S. dollars.
xxxxxxxxxxjavimport java.util.Scanner;public class CurrencyCalculation { public static void main(String[] args) { Scanner input = new Scanner(System.in); System.out.println("How many euros are you exchanging?"); double euros = input.nextDouble(); System.out.println("What is the exchange rate?"); double rate = input.nextDouble(); double dollars = euros * rate / 100; //print with 2 decimal places System.out.printf("%.2f euros at an exchange rate of %.2f is %.2f U.S. dollars.", euros, rate, dollars); }}xxxxxxxxxx1. 实现矩阵的加法、乘法、toString方法。2. 理解如何overriding equals方法。
xxxxxxxxxximport java.util.Arrays;/** * 矩阵类,实现矩阵的加法,矩阵乘法 * 1.传入一个int[][]进行2个矩阵的操作 * 2.返回一个int[][] * 所有的数据均为int型 * 输入数据均默认为正确数据,不需要对输入数据进行校验 * @author Qin Liu * */public class BadMatrix { private int[][] data; /** * 构造函数,参数为2维int数组 * a[i][j]是矩阵中的第i+1行,第j+1列数据 * @param a */ public BadMatrix(int[][] a){ this.data = a; } public int[][] getData() { return data; } /** * 实现矩阵加法,返回一个新的矩阵 * @param b * @return */ public int[][] plus(int[][] b){ int m = this.data.length; int n = this.data[0].length; int[][] a = new int[m][n]; for (int i = 0; i < m; i++) { a[i] = Arrays.copyOf(this.data[i], n); } for (int i = 0; i < m; i++) { for (int j = 0; j < n ; j++) { a[i][j] += b[i][j]; } } return a; } /** * 实现矩阵乘法,返回一个新的矩阵 * @param b * @return */ public int[][] times(int[][] b){ int m = this.data.length; int n = this.data[0].length; int p = b[0].length; int[][] a = new int[m][p]; for (int i = 0; i < m; i++) { for (int j = 0; j < p ; j++) { for (int k = 0; k < n; k++) { a[i][j] += data[i][k] * b[k][j]; } } } return a; } //不要修改下面print方法 /** * 打印出该矩阵的数据 * */ public void print(){ System.out.print(this.toString()); } /** * 实现toString方法 * 起始一个空行,结束一个空行 * 矩阵中每一行数据呈一行,数据间以空格隔开 * example: * * 1 2 3 * 1 2 3 * 1 2 3 * 1 2 3 * */ public String toString(){ StringBuilder sb = new StringBuilder(); sb.append("\n"); for (int[] row : data) { for (int i : row) { sb.append(i).append(" "); } //delete the last space sb.deleteCharAt(sb.length() - 1); sb.append("\n"); } return sb.toString(); } //不要修改下面equals方法 public boolean equals(Object o){ if(this.toString().equals(((BadMatrix)o).toString())) return true; else return false; }}xxxxxxxxxx实现矩阵的加法、乘法、点乘以及转置
xxxxxxxxxximport java.util.Scanner;/** * 矩阵类,实现矩阵的加法,矩阵乘法,点乘以及转置方法 * 其中加法和点乘方法需要有两种实现方式 * 1.传入一个MyMatrix对象进行2个矩阵的操作 * 2.从控制台(console)读入一个矩阵数据,再进行操作 * 所有的数据均为int型 * 输入数据均默认为正确数据,不需要对输入数据进行校验 * @author Ray Liu & Qin Liu * */public class MyMatrix { private int[][] data; /** * 构造函数,参数为2维int数组 * a[i][j]是矩阵中的第i+1行,第j+1列数据 * @param a */ public MyMatrix(int[][] a){ this.data = a; } public int[][] getData() { return data; } /** * 实现矩阵加法,返回一个新的矩阵 * @param B * @return */ public MyMatrix plus(MyMatrix B){ MyMatrix newMatrix = new MyMatrix(this.data); int[][] newData = newMatrix.getData(); int[][] BData = B.getData(); for (int i = 0; i < newData.length; i++) { for (int j = 0; j < newData[0].length; j++) { newData[i][j] += BData[i][j]; } } return newMatrix; } /** * 实现矩阵乘法,返回一个新的矩阵 * @param B * @return */ public MyMatrix times(MyMatrix B){ int[][] newData = this.data; int[][] BData = B.getData(); int[][] result = new int[newData.length][BData[0].length]; for (int i = 0; i < newData.length; i++) { for (int j = 0; j < BData[0].length; j++) { for (int k = 0; k < newData[0].length; k++) { result[i][j] += newData[i][k] * BData[k][j]; } } } return new MyMatrix(result); } /** * 实现矩阵的点乘,返回一个新的矩阵 * @param b * @return */ public MyMatrix times(int b){ MyMatrix newMatrix = new MyMatrix(this.data); int[][] newData = newMatrix.getData(); for (int i = 0; i < newData.length; i++) { for (int j = 0; j < newData[0].length; j++) { newData[i][j] *= b; } } return newMatrix; } /** * 实现矩阵的转置,返回一个新的矩阵 * @return */ public MyMatrix transpose(){ int[][] newData = this.data; int[][] result = new int[newData[0].length][newData.length]; for (int i = 0; i < newData.length; i++) { for (int j = 0; j < newData[0].length; j++) { result[j][i] = newData[i][j]; } } return new MyMatrix(result); } /** * 从控制台读入矩阵数据,进行矩阵加法,读入数据格式如下: * m n * m * n 的数据方阵,以空格隔开 * example: * 4 3 * 1 2 3 * 1 2 3 * 1 2 3 * 1 2 3 * 返回一个新的矩阵 * @return */ public MyMatrix ReadfromConsole(Scanner sc){ int m = sc.nextInt(); int n = sc.nextInt(); int[][] A = new int[m][n]; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++) A[i][j] = sc.nextInt(); } return new MyMatrix(A); } public MyMatrix plusFromConsole(){ Scanner sc = new Scanner(System.in); MyMatrix newMatrix = ReadfromConsole(sc); return this.plus(newMatrix); } /** * 输入格式同上方法相同 * 实现矩阵的乘法 * 返回一个新的矩阵 * @return */ public MyMatrix timesFromConsole(){ Scanner sc = new Scanner(System.in); MyMatrix newMatrix = ReadfromConsole(sc); return this.times(newMatrix); } /** * 打印出该矩阵的数据 * 起始一个空行,结束一个空行 * 矩阵中每一行数据呈一行,数据间以空格隔开 * example: * * 1 2 3 * 1 2 3 * 1 2 3 * 1 2 3 * */ public void print(){ int[][] A=this.data; System.out.println(); int m = A.length; int n = A[0].length; for(int i = 0; i < m; i++){ for(int j = 0; j < n; j++){ if(j!=n-1) System.out.print(A[i][j] + " "); else System.out.print(A[i][j]); } System.out.println(); } System.out.println(); }}两个玩家,一个打叉(X),一个打圈(O), 轮流在n乘n的格上打自己的符号,n最多9,最少为3,注意棋盘是方的。 游戏落子有两种模式: 1.正常规则落子 2.当棋盘上己方已经落下5个子,之后在落下一个子之前,要移去第1个子。即棋盘上最多出现5个己方棋子。
游戏胜利条件有两种模式: 1.己方棋子横、竖、斜三个字连成一线即赢,若棋盘填满双方仍未分胜负则为平局 2.己方棋子横、竖三个字连成一线即赢,若棋盘填满双方仍未分胜负则为平局
我们在游戏开始时, 即Game类的playGame方法中会传入gamemode字符串来选择游戏模式,gamemode字符串长度为2,每个字符都只有0或1两种可能,其中第一个字符代表落子模式,第二个字符代表胜负条件 00:正常规则落子,横竖斜均能胜利 01:正常规则落子,横竖能胜利 10:5子模式,横竖斜均能胜利 11: 5子模式,横竖能胜利
本文件夹内附带的示意图是一个X方取胜的例子。其中棋盘大小为3*3,正常落子,横竖斜均可胜利
要求:
我们会同时检查【playGame方法返回的比赛结果】与【标准输出的内容】作为判题的依据。
4.额外说明 本题中棋盘的大小、落子的策略以及判断输赢的策略会发生改变 对于落子和判断输赢未来可能会添加新的策略,为了应对这种变更需要更加灵活的设计,请自行添加修改相应的类、接口以及继承关系来完成设计应对变更 本题不仅可以修改已有的文件,还可以添加任意多的文件,甚至删去已有的文件,实现方式自行选择(若要删去文件,请不要删去要测试方法所在的类) 题目中的3*3仅为范例,需要灵活修改。
(多文件警告)
public abstract class AST { public abstract String toString(); public abstract boolean equals(AST ast);}x
import java.util.ArrayList;public class Abstraction extends AST { Identifier param;//变量 AST body;//表达式 Abstraction(Identifier p, AST b){ param = p; body = b; } public String toString(){ return "\\"+"."+body.toString(); } public boolean equals(AST ast) { if (ast instanceof Abstraction) { if (this.body.equals(((Abstraction) ast).body)) return true; else return false; }else return false; }}import java.util.ArrayList;public class Application extends AST{ AST lhs;//左树 AST rhs;//右树 Application(AST l, AST s){ lhs = l; rhs = s; } public String toString(){ if (lhs == null) return rhs.toString(); else if(rhs == null) return lhs.toString(); else if(lhs!= null && rhs!= null) return "("+lhs.toString()+" "+rhs.toString()+")"; else return ""; } public boolean equals(AST ast) { if (ast instanceof Application) { if (this.lhs.equals(((Application) ast).lhs) && this.rhs.equals(((Application) ast).rhs)) return true; else return false; }else return false; }}public class Identifier extends AST { String name; //名字 String value;//De Bruijn index值 public Identifier(String n,String v){ name = n; value = v; } public String toString(){ return value; } public boolean equals(AST ast){ if(ast instanceof Identifier) { if (this.value.equals(((Identifier) ast).value)) return true; else return false; }else return false; }}public enum TokenType { EOF, LAMBDA, LPAREN, RPAREN, LCID, DOT}public class Lexer { private String source; public String tokenvalue; int index; /** * Lexer 类内构造函数 * * @param s */ public Lexer(String s) { source = s; index = 0; } /** * 解析函数,本次作业主任务 * * @return TokenType 当前合法的token的tokenType */ public TokenType nextToken() { TokenType result = getTokenAndNext(); System.out.println(result.toString()); return result; } public TokenType getTokenAndNext() { while (index < source.length() && currentChar() == ' ') index++; tokenvalue = new String(); if (index >= source.length()) return TokenType.EOF; if (currentChar() == '.') { index++; tokenvalue += "."; return TokenType.DOT; } if (currentChar() == '\\') { index++; tokenvalue += "\\"; return TokenType.LAMBDA; } if (currentChar() == '(') { index++; tokenvalue += "("; return TokenType.LPAREN; } if (currentChar() == ')') { index++; tokenvalue += ")"; return TokenType.RPAREN; } if (Character.isLowerCase(currentChar())) { tokenvalue += currentChar(); index++; while (Character.isLowerCase(currentChar()) || Character.isUpperCase(currentChar())) { tokenvalue += currentChar(); index++; } return TokenType.LCID; } return TokenType.EOF; } private char currentChar() { return source.charAt(index); } /** * check token == t 检查类型 * * @param t * @return 类型是否匹配 */ public boolean nextIsMatched(TokenType t) { if (t == TokenType.EOF) return index == source.length(); // skip space int temp_index = index; char tested_char = currentChar(); while (temp_index < source.length() && tested_char == ' ') { temp_index++; tested_char = source.charAt(temp_index); } switch (t) { case DOT: return tested_char == '.'; case LAMBDA: return tested_char == '\\'; case LPAREN: return tested_char == '('; case RPAREN: return tested_char == ')'; case LCID: return Character.isLowerCase(tested_char); } return false; } /** * 保证当前token的类型与传入的t相同,并解析下一个符合此法规则的token * 如果解析到不同于t的类型,则退出并报错 * * @param t */ public void checkAndNext(TokenType t) throws Exception { if (!nextIsMatched(t)) throw new Exception("Not expected token"); nextToken(); } /** * 跳过当前TokenType t,并解析下一个符合此法规则的token * * @param t * @return 是否skip成功 */ public boolean skipThisType(TokenType t) { return false; }}import java.util.ArrayList;public class Parser { Lexer lexer; public Parser(Lexer l){ lexer = l; } public AST parse(){//解析入口 AST ast = parseAsTerm(new ArrayList<>()); return ast; } /** *解析 term * @param ctx * @return */ private AST parseAsTerm(ArrayList<String> ctx) { if (lexer.nextIsMatched(TokenType.LAMBDA)) { lexer.nextToken(); if (lexer.nextIsMatched(TokenType.LCID)) { lexer.nextToken(); String name = lexer.tokenvalue; ctx.add(name); Identifier id = new Identifier(name, findIndexFor(name, ctx)); if (lexer.nextToken()!=TokenType.DOT) { return null; } AST ast = parseAsTerm(ctx); if (ast == null) { return null; } ctx.remove(ctx.size() - 1); return new Abstraction(id, ast); } } AST app; if((app=parseAsApplication(ctx))!=null) return app; return null; } /** *解析 application * @param ctx * @return */ private AST parseAsApplication(ArrayList<String> ctx){ AST result = parseAsAtom(ctx); //continuously to parse atom as APPLICATION :: = APPLICATION ATOM| ATOM while (true) { AST atom = parseAsAtom(ctx); if (atom != null) { result = new Application(result, atom); } else { break; } } return result; } /** *解析 atom * @param ctx * @return */ private AST parseAsAtom(ArrayList<String> ctx){ if(lexer.nextIsMatched(TokenType.EOF)){ return null; } else if(lexer.nextIsMatched(TokenType.LCID)) { lexer.nextToken(); String name = lexer.tokenvalue; return new Identifier(name, findIndexFor(name, ctx)); } else if(lexer.nextIsMatched(TokenType.LPAREN)){ lexer.nextToken(); AST ast = parseAsTerm(ctx);//parse term due to ATOM ::= LPAREN TERM RPAREN/IDENTIFIER if(ast==null){ return null; } if(!lexer.nextIsMatched(TokenType.RPAREN)){ return null; } lexer.nextToken(); return ast; } return null; } private String findIndexFor(String id, ArrayList<String> ctx) { for (int i = ctx.size() - 1; i >= 0; i--) { if (ctx.get(i).equals(id)) { return String.valueOf(ctx.size() - 1 - i); } } return "-1"; }}