1、词法分析器实现
词法分析器是编译器中的一个关键组件,用于将源代码解析成词法单元。
词法分析器的结构与组件:
- 通常,词法分析器由两个主要组件构成:扫描器(Scanner)和记号流(Token Stream)。
- 扫描器负责从源代码中读取字符流,并按照预定义的词法规则将字符流解析为词法单元。
- 扫描器通常由一个有限自动机实现,用于根据词法规则进行状态转换,识别出不同的词法单元。
有限自动机的代码实现:
- 有限自动机是实现词法分析器的关键技术之一。它根据输入的字符进行状态转换,并输出识别的词法单元。
- 以下是一个用Python实现的简单有限自动机示例:
# 定义有限自动机的状态 def isAlpha(ch): return ch.isalpha() def isDigit(ch): return ch.isdigit() def scan(attr, i, s, n): # 核心子程序(语法分析程序) # 实现词法分析逻辑,根据字符流识别词法单元 # ... pass
错误处理与诊断:
- 在词法分析过程中,可能会遇到无法识别的字符或不符合词法规则的输入。
- 词法分析器通常需要进行错误处理与诊断,例如跳过无法识别的字符、发出错误提示或错误修复。
import java.io.*;
import java.util.*;
/**
* 词法分析器实现
*/
public class LexicalAnalyzer {
private static final Map<String, String> word = new HashMap<>();
private static final List<Node> aa = new ArrayList<>();
static class Node {
String id;
String s;
Node(String id, String s) {
this.id = id;
this.s = s;
}
}
public static void mapInit() {
word.put("main", "0");
word.put("return", "3");
word.put("if", "4");
word.put("else", "5");
word.put("int", "6");
word.put("char", "7");
word.put("(", "8");
word.put(")", "9");
word.put("{", "10");
word.put("}", "11");
word.put(",", "12");
word.put(";", "13");
word.put("=", "14");
word.put("!=", "15");
word.put(">", "16");
word.put("<", "17");
word.put(">=", "18");
word.put("<=", "19");
word.put("==", "20");
word.put("+", "21");
word.put("*", "22");
word.put("/", "23");
}
public static void main(String[] args) {
mapInit();
char ch;
int len = 0;
StringBuilder word1;
String str;
System.out.println("-----------------词法分析器-----------------");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入源文件地址:(路径中请不要包含中文)");
String dir = scanner.nextLine();
System.out.println("请输入目标文件地址:");
String targetDir = scanner.nextLine();
try (BufferedReader infile = new BufferedReader(new FileReader(dir));
BufferedWriter outfile = new BufferedWriter(new FileWriter(targetDir))) {
StringBuilder buf = new StringBuilder();
while ((ch = (char) infile.read()) != (char) -1) {
buf.append(ch);
}
str = buf.toString();
int csize = str.length();
for (int i = 0; i < csize; i++) {
while (str.charAt(i) == ' ' || str.charAt(i) == '\n') i++;
if (Character.isAlphabetic(str.charAt(i))) {
word1 = new StringBuilder(String.valueOf(str.charAt(i++)));
while (Character.isAlphabetic(str.charAt(i)) || Character.isDigit(str.charAt(i))) {
word1.append(str.charAt(i++));
}
if (word.containsKey(word1.toString())) {
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else {
System.out.println("(1," + word1 + ")");
aa.add(new Node("1", word1.toString()));
}
i--;
} else if (Character.isDigit(str.charAt(i))) {
word1 = new StringBuilder(String.valueOf(str.charAt(i++)));
while (Character.isDigit(str.charAt(i))) {
word1.append(str.charAt(i++));
}
if (Character.isAlphabetic(str.charAt(i))) {
System.out.println("error1!");
break;
} else {
System.out.println("(2," + word1 + ")");
aa.add(new Node("2", word1.toString()));
}
i--;
} else if (str.charAt(i) == '<') {
word1 = new StringBuilder(String.valueOf(str.charAt(i++)));
if (str.charAt(i) == '>') {
word1.append(str.charAt(i));
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else if (str.charAt(i) == '=') {
word1.append(str.charAt(i));
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else if (str.charAt(i) != ' ' || !Character.isDigit(str.charAt(i)) || !Character.isAlphabetic(str.charAt(i))) {
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else {
System.out.println("error2!");
break;
}
i--;
} else if (str.charAt(i) == '>') {
word1 = new StringBuilder(String.valueOf(str.charAt(i++)));
if (str.charAt(i) == '=') {
word1.append(str.charAt(i));
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else if (str.charAt(i) != ' ' || !Character.isDigit(str.charAt(i)) || !Character.isAlphabetic(str.charAt(i))) {
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else {
System.out.println("error3!");
break;
}
i--;
} else if (str.charAt(i) == ':') {
word1 = new StringBuilder(String.valueOf(str.charAt(i++)));
if (str.charAt(i) == '=') {
word1.append(str.charAt(i));
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else if (str.charAt(i) != ' ' || !Character.isDigit(str.charAt(i)) || !Character.isAlphabetic(str.charAt(i))) {
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
} else {
System.out.println("error4!");
break;
}
i--;
} else {
word1 = new StringBuilder(String.valueOf(str.charAt(i)));
if (word.containsKey(word1.toString())) {
System.out.println("(" + word.get(word1.toString()) + "," + word1 + ")");
aa.add(new Node(word.get(word1.toString()), word1.toString()));
}
}
}
for (Node node : aa) {
outfile.write("(" + node.id + "," + node.s + ")\n");
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("输入任意键关闭");
scanner.nextLine();
}
}
2、语法分析器实现
语法分析器是编译器中的关键组件,用于检查源代码是否遵循编程语言的语法规则。
语法分析器的结构与组件:
- 自顶向下语法分析器从文法的开始符号出发,试图推导出与输入单词串相匹配的句子。
- 通常,自顶向下语法分析器由递归下降分析器构成,它根据预定义的文法规则逐步构建语法树。
- 语法树表示源代码的层次结构,其中每个节点对应一个语法规则或终结符。
递归下降分析器的代码实现:
- 递归下降分析器是自顶向下语法分析的一种常见方法。
- 以下是一个简单的递归下降分析器示例(使用Python):
# 定义文法规则 def expr(): term() while lookahead == '+': match('+') term() def term(): factor() while lookahead == '*': match('*') factor() def factor(): if lookahead.isdigit(): match(lookahead) elif lookahead == '(': match('(') expr() match(')') # 初始化 lookahead = input() # 输入的单词串 # 匹配函数 def match(expected): if lookahead == expected: lookahead = input() else: raise SyntaxError("Unexpected token: " + lookahead) # 开始分析 expr()
错误处理与诊断:
- 语法分析过程中,可能会遇到不符合文法规则的输入。
- 递归下降分析器通常需要进行错误处理与诊断,例如报告无法识别的符号或缺失的符号。
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;
import java.util.Set;
import java.util.Stack;
/**
* 语法分析器实现
*/
public class Parser {
public static final String PATH = "C:\\code\\idea\\CompilePrinciple\\src\\grammar.txt";
private static String START;
private static HashSet<String> VN, VT;
private static HashMap<String, ArrayList<ArrayList<String>>> MAP;
private static HashMap<String, String> oneLeftFirst;
private static HashMap<String, HashSet<String>> FIRST, FOLLOW;
private static HashMap<String, String> preMap;
public static void main(String[] args) {
init();
identifyVnVt(readFile(new File(PATH)));
reformMap();
findFirst();
findFollow();
if (isLL1()) {
preForm();
System.out.println("请输入要分析的单词串:");
Scanner in = new Scanner(System.in);
printAutoPre(in.nextLine());
in.close();
}
}
// 变量初始化
private static void init() {
VN = new HashSet<>();
VT = new HashSet<>();
MAP = new HashMap<>();
FIRST = new HashMap<>();
FOLLOW = new HashMap<>();
oneLeftFirst = new HashMap<>();
preMap = new HashMap<>();
}
// 判断是否是LL(1)文法
private static boolean isLL1() {
System.out.println("\n正在判断是否是LL(1)文法....");
boolean flag = true;
for (String key : VN) {
ArrayList<ArrayList<String>> list = MAP.get(key);
if (list.size() > 1)
for (int i = 0; i < list.size(); i++) {
String aLeft = String.join("", list.get(i).toArray(new String[0]));
for (int j = i + 1; j < list.size(); j++) {
String bLeft = String.join("", list.get(j).toArray(new String[0]));
if (aLeft.equals("ε") || bLeft.equals("ε")) {
HashSet<String> retainSet = new HashSet<>(FIRST.get(key));
if (FOLLOW.get(key) != null)
retainSet.retainAll(FOLLOW.get(key));
if (!retainSet.isEmpty()) {
flag = false;
System.out.println("\tFIRST(" + key + ") ∩ FOLLOW(" + key + ") = {"
+ String.join("、", retainSet.toArray(new String[0])) + "}");
break;
} else {
System.out.println("\tFIRST(" + key + ") ∩ FOLLOW(" + key + ") = φ");
}
} else {
HashSet<String> retainSet = new HashSet<>(FIRST.get(key + "→" + aLeft));
retainSet.retainAll(FIRST.get(key + "→" + bLeft));
if (!retainSet.isEmpty()) {
flag = false;
System.out.println("\tFIRST(" + aLeft + ") ∩ FIRST(" + bLeft + ") = {"
+ String.join("、", retainSet.toArray(new String[0])) + "}");
break;
} else {
System.out.println("\tFIRST(" + aLeft + ") ∩ FIRST(" + bLeft + ") = φ");
}
}
}
}
}
if (flag)
System.out.println("\t是LL(1)文法,继续分析!");
else
System.out.println("\t不是LL(1)文法,退出分析!");
return flag;
}
// 构建预测分析表FORM
private static void preForm() {
HashSet<String> set = new HashSet<>(VT);
set.remove("ε");
String[][] FORM = new String[VN.size() + 1][set.size() + 2];
Iterator<String> itVn = VN.iterator();
Iterator<String> itVt = set.iterator();
for (int i = 0; i < FORM.length; i++)
for (int j = 0; j < FORM[0].length; j++) {
if (i == 0 && j > 0) {
if (itVt.hasNext()) {
FORM[i][j] = itVt.next();
}
if (j == FORM[0].length - 1)
FORM[i][j] = "#";
}
if (j == 0 && i > 0) {
if (itVn.hasNext())
FORM[i][j] = itVn.next();
}
if (i > 0 && j > 0) {
String oneLeftKey = FORM[i][0] + "$" + FORM[0][j];
FORM[i][j] = oneLeftFirst.get(oneLeftKey);
}
}
for (int i = 1; i < FORM.length; i++) {
String oneLeftKey = FORM[i][0] + "$ε";
if (oneLeftFirst.containsKey(oneLeftKey)) {
HashSet<String> followCell = FOLLOW.get(FORM[i][0]);
for (String vt : followCell) {
for (int j = 1; j < FORM.length; j++)
for (int k = 1; k < FORM[0].length; k++) {
if (FORM[j][0].equals(FORM[i][0]) && FORM[0][k].equals(vt))
FORM[j][k] = oneLeftFirst.get(oneLeftKey);
}
}
}
}
// 打印预测表,并存于Map的数据结构中用于快速查找
System.out.println("\n该文法的预测分析表为:");
for (int i = 0; i < FORM.length; i++) {
for (int j = 0; j < FORM[0].length; j++) {
if (FORM[i][j] == null)
System.out.print(" " + "\t");
else {
System.out.print(FORM[i][j] + "\t");
if (i > 0 && j > 0) {
String[] tmp = FORM[i][j].split("→");
preMap.put(FORM[i][0] + FORM[0][j], tmp[1]);
}
}
}
System.out.println();
}
System.out.println();
}
// 输入的单词串分析推导过程
public static void printAutoPre(String str) {
System.out.println(str + "的分析过程:");
Queue<String> queue = new LinkedList<>();
for (int i = 0; i < str.length(); i++) {
String t = str.charAt(i) + "";
if (i + 1 < str.length() && (str.charAt(i + 1) == '\'' || str.charAt(i + 1) == '’')) {
t += str.charAt(i + 1);
i++;
}
queue.offer(t);
}
queue.offer("#");
Stack<String> stack = new Stack<>();
stack.push("#");
stack.push(START);
boolean isSuccess = false;
int step = 1;
while (!stack.isEmpty()) {
String left = stack.peek();
String right = queue.peek();
if (left.equals(right) && right.equals("#")) {
isSuccess = true;
System.out.println((step++) + "\t#\t#\t" + "分析成功");
break;
}
if (left.equals(right)) {
String stackStr = String.join("", stack.toArray(new String[0]));
String queueStr = String.join("", queue.toArray(new String[0]));
System.out.println((step++) + "\t" + stackStr + "\t" + queueStr + "\t匹配成功" + left);
stack.pop();
queue.poll();
continue;
}
if (preMap.containsKey(left + right)) {
String stackStr = String.join("", stack.toArray(new String[0]));
String queueStr = String.join("", queue.toArray(new String[0]));
System.out.println((step++) + "\t" + stackStr + "\t" + queueStr + "\t用" + left + "→"
+ preMap.get(left + right) + "," + right + "逆序进栈");
stack.pop();
String tmp = preMap.get(left + right);
for (int i = tmp.length() - 1; i >= 0; i--) {
String t = "";
if (tmp.charAt(i) == '\'' || tmp.charAt(i) == '’') {
t = tmp.charAt(i-1)+""+tmp.charAt(i);
i--;
}else {
t=tmp.charAt(i)+"";
}
if (!t.equals("ε"))
stack.push(t);
}
continue;
}
break;
}
if (!isSuccess)
System.out.println((step++) + "\t#\t#\t" + "分析失败");
}
// 符号分类
private static void identifyVnVt(ArrayList<String> list) {
START = list.get(0).charAt(0) + "";
for (String oneline : list) {
String[] vnvt = oneline.split("→");
String left = vnvt[0].trim();
VN.add(left);
ArrayList<ArrayList<String>> mapValue = new ArrayList<>();
ArrayList<String> right = new ArrayList<>();
for (int j = 0; j < vnvt[1].length(); j++) {
if (vnvt[1].charAt(j) == '|') {
VT.addAll(right);
mapValue.add(right);
right = null;
right = new ArrayList<>();
continue;
}
if (j + 1 < vnvt[1].length() && (vnvt[1].charAt(j + 1) == '\'' || vnvt[1].charAt(j + 1) == '’')) {
right.add(vnvt[1].charAt(j) + "" + vnvt[1].charAt(j + 1));
j++;
} else {
right.add(vnvt[1].charAt(j) + "");
}
}
VT.addAll(right);
mapValue.add(right);
MAP.put(left, mapValue);
}
VT.removeAll(VN);
System.out.println("\nVn集合:\t{" + String.join("、", VN.toArray(new String[0])) + "}");
System.out.println("Vt集合:\t{" + String.join("、", VT.toArray(new String[0])) + "}");
}
// 求每个非终结符号的FIRST集合 和 分解单个产生式的FIRST集合
private static void findFirst() {
System.out.println("\nFIRST集合:");
for (String s : VN) {
HashSet<String> firstCell = new HashSet<>();
ArrayList<ArrayList<String>> list = MAP.get(s);
for (ArrayList<String> listCell : list) {
HashSet<String> firstCellOne = new HashSet<>();
String oneLeft = String.join("", listCell.toArray(new String[0]));
if (VT.contains(listCell.get(0))) {
firstCell.add(listCell.get(0));
firstCellOne.add(listCell.get(0));
oneLeftFirst.put(s + "$" + listCell.get(0), s + "→" + oneLeft);
} else {
boolean[] isVn = new boolean[listCell.size()];
isVn[0] = true;
int p = 0;
while (isVn[p]) {
if (VT.contains(listCell.get(p))) {
firstCell.add(listCell.get(p));
firstCellOne.add(listCell.get(p));
oneLeftFirst.put(s + "$" + listCell.get(p), s + "→" + oneLeft);
break;
}
String vnGo = listCell.get(p);
Stack<String> stack = new Stack<>();
stack.push(vnGo);
while (!stack.isEmpty()) {
ArrayList<ArrayList<String>> listGo = MAP.get(stack.pop());
for (ArrayList<String> listGoCell : listGo) {
if (VT.contains(listGoCell.get(0))) {
if (listGoCell.get(0).equals("ε")) {
if (!s.equals(START)) {
firstCell.add(listGoCell.get(0));
firstCellOne.add(listGoCell.get(0));
oneLeftFirst.put(s + "$" + listGoCell.get(0), s + "→" + oneLeft);
}
if (p + 1 < isVn.length) {
isVn[p + 1] = true;
}
} else {
firstCell.add(listGoCell.get(0));
firstCellOne.add(listGoCell.get(0));
oneLeftFirst.put(s + "$" + listGoCell.get(0), s + "→" + oneLeft);
}
} else {
stack.push(listGoCell.get(0));
}
}
}
p++;
if (p > isVn.length - 1)
break;
}
}
FIRST.put(s + "→" + oneLeft, firstCellOne);
}
FIRST.put(s, firstCell);
System.out.println(
"\tFIRST(" + s + ")={" + String.join("、", firstCell.toArray(new String[0])) + "}");
}
}
private static void findFollow() {
System.out.println("\nFOLLOW集合:");
Iterator<String> it = VN.iterator();
HashMap<String, HashSet<String>> keyFollow = new HashMap<>();
ArrayList<HashMap<String, String>> vn_VnList = new ArrayList<>();
HashSet<String> vn_VnListLeft = new HashSet<>();
HashSet<String> vn_VnListRight = new HashSet<>();
keyFollow.put(START, new HashSet<>() {
private static final long serialVersionUID = 1L;
{
add("#");
}
});
while (it.hasNext()) {
String key = it.next();
ArrayList<ArrayList<String>> list = MAP.get(key);
ArrayList<String> listCell;
if (!keyFollow.containsKey(key)) {
keyFollow.put(key, new HashSet<>());
}
keyFollow.toString();
for (ArrayList<String> strings : list) {
listCell = strings;
for (int j = 1; j < listCell.size(); j++) {
HashSet<String> set = new HashSet<>();
if (VT.contains(listCell.get(j))) {
set.add(listCell.get(j));
if (keyFollow.containsKey(listCell.get(j - 1)))
set.addAll(keyFollow.get(listCell.get(j - 1)));
keyFollow.put(listCell.get(j - 1), set);
}
}
for (int j = 0; j < listCell.size() - 1; j++) {
if (VN.contains(listCell.get(j)) && VN.contains(listCell.get(j + 1))) {
HashSet<String> set = new HashSet<>(FIRST.get(listCell.get(j + 1)));
set.remove("ε");
if (keyFollow.containsKey(listCell.get(j)))
set.addAll(keyFollow.get(listCell.get(j)));
keyFollow.put(listCell.get(j), set);
}
}
for (int j = 0; j < listCell.size(); j++) {
HashMap<String, String> vn_Vn;
if (VN.contains(listCell.get(j)) && !listCell.get(j).equals(key)) {
boolean isAllNull = false;
if (j + 1 < listCell.size())
for (int k = j + 1; k < listCell.size(); k++) {
if ((FIRST.containsKey(listCell.get(k)) && FIRST.get(listCell.get(k)).contains("ε"))) {
isAllNull = true;
} else {
isAllNull = false;
break;
}
}
if (j == listCell.size() - 1) {
isAllNull = true;
}
if (isAllNull) {
vn_VnListLeft.add(key);
vn_VnListRight.add(listCell.get(j));
boolean isHaveAdd = false;
for (int x = 0; x < vn_VnList.size(); x++) {
HashMap<String, String> vn_VnListCell = vn_VnList.get(x);
if (!vn_VnListCell.containsKey(key)) {
vn_VnListCell.put(key, listCell.get(j));
vn_VnList.set(x, vn_VnListCell);
isHaveAdd = true;
break;
} else {
if (vn_VnListCell.get(key).equals(listCell.get(j))) {
isHaveAdd = true;
break;
}
}
}
if (!isHaveAdd) {
vn_Vn = new HashMap<>();
vn_Vn.put(key, listCell.get(j));
vn_VnList.add(vn_Vn);
}
}
}
}
}
}
keyFollow.toString();
vn_VnListLeft.removeAll(vn_VnListRight);
Queue<String> keyQueue = new LinkedList<>(vn_VnListLeft);
while (!keyQueue.isEmpty()) {
String keyLeft = keyQueue.poll();
for (int t = 0; t < vn_VnList.size(); t++) {
HashMap<String, String> vn_VnListCell = vn_VnList.get(t);
if (vn_VnListCell.containsKey(keyLeft)) {
HashSet<String> set = new HashSet<>();
if (keyFollow.containsKey(keyLeft))
set.addAll(keyFollow.get(keyLeft));
if (keyFollow.containsKey(vn_VnListCell.get(keyLeft)))
set.addAll(keyFollow.get(vn_VnListCell.get(keyLeft)));
keyFollow.put(vn_VnListCell.get(keyLeft), set);
keyQueue.add(vn_VnListCell.get(keyLeft));
vn_VnListCell.remove(keyLeft);
vn_VnList.set(t, vn_VnListCell);
}
}
}
FOLLOW = keyFollow;
for (String key : keyFollow.keySet()) {
HashSet<String> f = keyFollow.get(key);
System.out.println("\tFOLLOW(" + key + ")={" + String.join("、", f.toArray(new String[0])) + "}");
}
}
private static void reformMap() {
boolean isReForm = false;
Set<String> keys = new HashSet<>(MAP.keySet());
Iterator<String> it = keys.iterator();
ArrayList<String> nullSign = new ArrayList<>();
nullSign.add("ε");
while (it.hasNext()) {
String left = it.next();
boolean flag = false;
ArrayList<ArrayList<String>> rightList = MAP.get(left);
ArrayList<String> oldRightCell = new ArrayList<>();
ArrayList<ArrayList<String>> newLeftNew = new ArrayList<>();
for (ArrayList<String> strings : rightList) {
ArrayList<String> newRightCell = new ArrayList<>();
if (strings.get(0).equals(left)) {
for (int j = 1; j < strings.size(); j++) {
newRightCell.add(strings.get(j));
}
flag = true;
newRightCell.add(left + "'");
newLeftNew.add(newRightCell);
} else {
oldRightCell.addAll(strings);
oldRightCell.add(left + "'");
}
}
if (flag) {
isReForm = true;
newLeftNew.add(nullSign);
MAP.put(left + "'", newLeftNew);
VN.add(left + "'");
VT.add("ε");
ArrayList<ArrayList<String>> newLeftOld = new ArrayList<>();
newLeftOld.add(oldRightCell);
MAP.put(left, newLeftOld);
}
}
if (isReForm) {
System.out.println("消除文法的左递归:");
Set<String> kSet = new HashSet<>(MAP.keySet());
for (String k : kSet) {
ArrayList<ArrayList<String>> leftList = MAP.get(k);
System.out.print("\t" + k + "→");
for (int i = 0; i < leftList.size(); i++) {
System.out.print(String.join("", leftList.get(i).toArray(new String[0])));
if (i + 1 < leftList.size())
System.out.print("|");
}
System.out.println();
}
}
MAP.toString();
}
public static ArrayList<String> readFile(File file) {
System.out.println("从文件读入的文法为:");
ArrayList<String> result = new ArrayList<>();
try {
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
while ((s = br.readLine()) != null) {
System.out.println("\t" + s);
result.add(s.trim());
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
E→TE'
E'→+E|ε
T→FT'
T'→T|ε
F→PF'
F'→*F'|ε
P→(E)|^|a|b