├── grammer ├── a4.txt ├── a2.txt ├── a3.txt ├── a1.txt └── a5.txt ├── .idea ├── .gitignore ├── vcs.xml ├── misc.xml ├── modules.xml └── uiDesigner.xml ├── README.md ├── 实验报告.doc ├── .DS_Store ├── out └── production │ └── Lexer-Parser-master │ ├── META-INF │ └── Lexer-Parser-master.kotlin_module │ ├── Main.class │ ├── lr0 │ ├── IE.class │ ├── Grammar.class │ ├── LR0Main.class │ ├── Grammar$1.class │ └── Production.class │ ├── compile │ ├── Lexer.class │ ├── Parser.class │ ├── Parser$1.class │ ├── MainComplier.class │ └── MainComplier$ActListener.class │ ├── frame │ ├── OutText.class │ └── ReadText.class │ ├── pojo │ ├── TokenList.class │ ├── MultiComment.class │ └── SingleComment.class │ ├── window │ ├── OutText.class │ └── ReadText.class │ └── entity │ ├── TokenList.class │ ├── MultiComment.class │ └── SingleComment.class ├── src ├── .DS_Store ├── Main.java ├── window │ ├── ReadText.java │ └── OutText.java ├── frame │ ├── ReadText.java │ └── OutText.java ├── pojo │ ├── SingleComment.java │ ├── MultiComment.java │ └── TokenList.java ├── entity │ ├── SingleComment.java │ ├── MultiComment.java │ └── TokenList.java ├── lr0 │ ├── IE.java │ ├── LR0Main.java │ ├── Production.java │ └── Grammar.java └── compile │ ├── MainComplier.java │ ├── Lexer.java │ └── Parser.java ├── 文法测试.txt ├── Lexer-Parser.iml └── Lexer-Parser-master.iml /grammer/a4.txt: -------------------------------------------------------------------------------- 1 | S→AaS|a 2 | A→a -------------------------------------------------------------------------------- /grammer/a2.txt: -------------------------------------------------------------------------------- 1 | S→AaS|BbS|d 2 | A→a 3 | B→ε|c -------------------------------------------------------------------------------- /grammer/a3.txt: -------------------------------------------------------------------------------- 1 | X→ABCd 2 | A→a|ε 3 | B→b|ε 4 | C→c|ε -------------------------------------------------------------------------------- /grammer/a1.txt: -------------------------------------------------------------------------------- 1 | E→T|E+T|E-T 2 | T→F|T*F|T/F 3 | F→(E)|i -------------------------------------------------------------------------------- /grammer/a5.txt: -------------------------------------------------------------------------------- 1 | E->aA|bB 2 | C->ε 3 | A->cA|d 4 | B->cB|d -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2 | ## 编译原理课程设计,包含词法分析程序、LL1语法分析程序、LR0语法分析程序。 3 | ## SDUST编译原理实践结课作业。 4 | -------------------------------------------------------------------------------- /实验报告.doc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/实验报告.doc -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/.DS_Store -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/META-INF/Lexer-Parser-master.kotlin_module: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/Main.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/Main.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/lr0/IE.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/lr0/IE.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/lr0/Grammar.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/lr0/Grammar.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/lr0/LR0Main.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/lr0/LR0Main.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/compile/Lexer.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/compile/Lexer.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/compile/Parser.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/compile/Parser.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/frame/OutText.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/frame/OutText.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/frame/ReadText.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/frame/ReadText.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/lr0/Grammar$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/lr0/Grammar$1.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/lr0/Production.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/lr0/Production.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/pojo/TokenList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/pojo/TokenList.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/window/OutText.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/window/OutText.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/window/ReadText.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/window/ReadText.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/compile/Parser$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/compile/Parser$1.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/entity/TokenList.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/entity/TokenList.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/pojo/MultiComment.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/pojo/MultiComment.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/compile/MainComplier.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/compile/MainComplier.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/entity/MultiComment.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/entity/MultiComment.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/entity/SingleComment.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/entity/SingleComment.class -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/pojo/SingleComment.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/pojo/SingleComment.class -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /out/production/Lexer-Parser-master/compile/MainComplier$ActListener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DanielSun11/CourseDesignofCompiling/HEAD/out/production/Lexer-Parser-master/compile/MainComplier$ActListener.class -------------------------------------------------------------------------------- /src/Main.java: -------------------------------------------------------------------------------- 1 | import compile.MainComplier; 2 | 3 | import java.io.*; 4 | 5 | public class Main { 6 | public static void main(String[] args)throws IOException { 7 | new MainComplier(); //对象的引用 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /文法测试.txt: -------------------------------------------------------------------------------- 1 | 文法1: 2 | E→T|E+T|E-T 3 | T→F|T*F|T/F 4 | F→(E)|i 5 | 输入:i+i*i 6 | 7 | 文法2: 8 | S→AaS|BbS|d 9 | A→a 10 | B→ε|c 11 | 输入:aabd 12 | 输入:aaaa 13 | 14 | 文法3: 15 | X→ABCd 16 | A→a|ε 17 | B→b|ε 18 | C→c|ε 19 | 输入:abcd 20 | 21 | 文法4. 非LL(1)文法 22 | S→AaS|a 23 | A→a 24 | 25 | 文法5 LR0文法 26 | E->aA|bB 27 | C->ε 28 | A->cA|d 29 | B->cB|d 30 | 输入:bccd 31 | -------------------------------------------------------------------------------- /src/window/ReadText.java: -------------------------------------------------------------------------------- 1 | package window; 2 | 3 | import java.awt.*; 4 | 5 | /** 6 | * 输入区域,读取文本域的信息 7 | */ 8 | public class ReadText extends TextArea{ 9 | public ReadText(int rows,int columns) { 10 | setBackground(Color.white); 11 | setForeground(Color.black); 12 | setRows(rows); 13 | setColumns(columns); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/frame/ReadText.java: -------------------------------------------------------------------------------- 1 | package frame; 2 | 3 | import java.awt.*; 4 | 5 | /** 6 | * 输入区域,读取文本域的信息 7 | */ 8 | public class ReadText extends TextArea{ 9 | public ReadText(int rows,int columns) { 10 | setBackground(Color.white); 11 | setForeground(Color.black); 12 | setRows(rows); 13 | setColumns(columns); 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/frame/OutText.java: -------------------------------------------------------------------------------- 1 | package frame; 2 | 3 | import java.awt.*; 4 | 5 | /** 6 | * 输出域,将词法分析结果或者语法分析结果输出到这个域中 7 | */ 8 | public class OutText extends TextArea{ 9 | public OutText(int rows,int columns) { 10 | setBackground(Color.white); 11 | setForeground(Color.black); 12 | setRows(rows); 13 | setColumns(columns); 14 | setFont(new Font("Courier",1,12)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/window/OutText.java: -------------------------------------------------------------------------------- 1 | package window; 2 | 3 | import java.awt.*; 4 | 5 | /** 6 | * 输出域,将词法分析结果或者语法分析结果输出到这个域中 7 | */ 8 | public class OutText extends TextArea{ 9 | public OutText(int rows,int columns) { 10 | setBackground(Color.white); 11 | setForeground(Color.black); 12 | setRows(rows); 13 | setColumns(columns); 14 | setFont(new Font("Courier",1,12)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Lexer-Parser.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Lexer-Parser-master.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/pojo/SingleComment.java: -------------------------------------------------------------------------------- 1 | package pojo; 2 | 3 | /** 4 | * 用于存储单行注释的信息 5 | */ 6 | @SuppressWarnings("all") 7 | public class SingleComment { 8 | 9 | //相关定义 10 | private int row;//行 11 | private int column;//列 12 | 13 | //构造函数 14 | public SingleComment(int row, int column) { 15 | this.row = row; 16 | this.column = column; 17 | } 18 | //生成相应的 get-set方法 19 | public int getRow() { 20 | return row; 21 | } 22 | public void setRow(int row) { 23 | this.row = row; 24 | } 25 | public int getColumn() { 26 | return column; 27 | } 28 | public void setColumn(int column) { 29 | this.column = column; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/entity/SingleComment.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | /** 4 | * 用于存储单行注释的信息 5 | */ 6 | @SuppressWarnings("all") 7 | public class SingleComment { 8 | 9 | //相关定义 10 | private int row;//行 11 | private int column;//列 12 | 13 | //构造函数 14 | public SingleComment(int row, int column) { 15 | this.row = row; 16 | this.column = column; 17 | } 18 | //生成相应的 get-set方法 19 | public int getRow() { 20 | return row; 21 | } 22 | public void setRow(int row) { 23 | this.row = row; 24 | } 25 | public int getColumn() { 26 | return column; 27 | } 28 | public void setColumn(int column) { 29 | this.column = column; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/entity/MultiComment.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | //专门用来存储多行注释的行列信息,/*存放在奇数位置,*/存放在偶数位置 4 | @SuppressWarnings("all") 5 | public class MultiComment { 6 | private int row;//多行注释的行号 7 | private int column;//多行注释的列号 8 | private String comment;//注释 9 | 10 | //构造方法 11 | public MultiComment(int row,int column,String comment) { 12 | this.row = row; 13 | this.column = column; 14 | this.comment = comment; 15 | } 16 | 17 | //生成相应的get set方法 18 | public void setComment(String comment) { 19 | this.comment = comment; 20 | } 21 | public String getComment() { 22 | return comment; 23 | } 24 | public void setRow(int row) { 25 | this.row = row; 26 | } 27 | public int getRow() { 28 | return row; 29 | } 30 | public void setColumn(int column) { 31 | this.column = column; 32 | } 33 | public int getColumn() { 34 | return column; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/pojo/MultiComment.java: -------------------------------------------------------------------------------- 1 | package pojo; 2 | 3 | //专门用来存储多行注释的行列信息,/*存放在奇数位置,*/存放在偶数位置 4 | @SuppressWarnings("all") 5 | public class MultiComment { 6 | private int row;//多行注释的行号 7 | private int column;//多行注释的列号 8 | private String comment;//注释 9 | 10 | //构造方法 11 | public MultiComment(int row,int column,String comment) { 12 | this.row = row; 13 | this.column = column; 14 | this.comment = comment; 15 | } 16 | 17 | //生成相应的get set方法 18 | public void setComment(String comment) { 19 | this.comment = comment; 20 | } 21 | public String getComment() { 22 | return comment; 23 | } 24 | public void setRow(int row) { 25 | this.row = row; 26 | } 27 | public int getRow() { 28 | return row; 29 | } 30 | public void setColumn(int column) { 31 | this.column = column; 32 | } 33 | public int getColumn() { 34 | return column; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/entity/TokenList.java: -------------------------------------------------------------------------------- 1 | package entity; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 定义tocken序列 8 | */ 9 | @SuppressWarnings("all") 10 | public class TokenList { 11 | 12 | private List tokenList = new ArrayList<>();//用一个arraylist来存储token序列 13 | private int row;//记录每一行的记号 14 | private List identifier;//为语法分析做准备存储的记号类型 15 | 16 | //第一次实验词法分析所用到的构造函数 17 | public TokenList(int row,List tokenList) { 18 | this.row = row; 19 | this.tokenList = tokenList; 20 | } 21 | 22 | //生成相应的get,set方法 23 | public void setRow(int row) { 24 | this.row = row; 25 | } 26 | public int getRow() { 27 | return row; 28 | } 29 | public void setTokenList(List tokenList) { 30 | this.tokenList = tokenList; 31 | } 32 | public List getTokenList() { 33 | return tokenList; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return super.toString(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/pojo/TokenList.java: -------------------------------------------------------------------------------- 1 | package pojo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * 定义tocken序列的实体类 8 | */ 9 | @SuppressWarnings("all") 10 | public class TokenList { 11 | 12 | private List tokenList = new ArrayList<>();//用一个arraylist来存储token序列 13 | private int row;//记录每一行的记号 14 | private List identifier;//为语法分析做准备存储的记号类型 15 | 16 | //第一次实验词法分析所用到的构造函数 17 | public TokenList(int row,List tokenList) { 18 | this.row = row; 19 | this.tokenList = tokenList; 20 | } 21 | 22 | //生成相应的get,set方法 23 | public void setRow(int row) { 24 | this.row = row; 25 | } 26 | public int getRow() { 27 | return row; 28 | } 29 | public void setTokenList(List tokenList) { 30 | this.tokenList = tokenList; 31 | } 32 | public List getTokenList() { 33 | return tokenList; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | return super.toString(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/lr0/IE.java: -------------------------------------------------------------------------------- 1 | package lr0; 2 | 3 | public class IE { 4 | //一个项目集到另一个项目集 5 | int orgin; 6 | int aim; 7 | String value; 8 | 9 | public IE(int orgin, String value, int aim) { 10 | this.orgin = orgin; 11 | this.aim = aim; 12 | this.value = value; 13 | } 14 | 15 | @Override 16 | public boolean equals(Object o) { 17 | if (this == o) return true; 18 | if (o == null || getClass() != o.getClass()) return false; 19 | 20 | IE IE = (IE) o; 21 | 22 | if (orgin != IE.orgin) return false; 23 | if (aim != IE.aim) return false; 24 | return value != null ? value.equals(IE.value) : IE.value == null; 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | int result = orgin; 30 | result = 31 * result + aim; 31 | result = 31 * result + (value != null ? value.hashCode() : 0); 32 | return result; 33 | } 34 | public String toString(){ 35 | return "\nI"+orgin+"--"+value+"-->"+"I"+aim; 36 | } 37 | public int getOrgin() { 38 | return orgin; 39 | } 40 | 41 | public void setOrgin(int orgin) { 42 | this.orgin = orgin; 43 | } 44 | 45 | public int getAim() { 46 | return aim; 47 | } 48 | 49 | public void setAim(int aim) { 50 | this.aim = aim; 51 | } 52 | 53 | public String getValue() { 54 | return value; 55 | } 56 | 57 | public void setValue(String value) { 58 | this.value = value; 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/lr0/LR0Main.java: -------------------------------------------------------------------------------- 1 | package lr0; 2 | import frame.OutText; 3 | import frame.ReadText; 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.FileReader; 7 | import java.util.ArrayList; 8 | import java.util.HashSet; 9 | 10 | public class LR0Main { 11 | private static final char Njump = 'ε'; 12 | 13 | public static void run(OutText outText, ReadText readText) { 14 | String S="E";//开始符 15 | // String P[]={"E->aA|bB","A->cA|d","B->cB|d"};//规则集 16 | HashSet productionSet = readFile(outText); 17 | String P[]=productionSet.toArray(new String[productionSet.size()]);//规则集 18 | 19 | Grammar G=new Grammar(P,S); 20 | G.out(outText); 21 | if(G.isLRO == false){ 22 | outText.append("输入文法不是LR0文法!!\r\n"); 23 | return; 24 | } 25 | try { 26 | if(G.contains(readText.getText()) == false){ 27 | outText.append("不符合所给的LR0文法 分析失败!!"); 28 | } 29 | else{ 30 | outText.append("分析成功!!"); 31 | } 32 | } catch (Exception e) { 33 | e.printStackTrace(); 34 | } 35 | } 36 | public static HashSet readFile(OutText outText) { 37 | BufferedReader br = null; 38 | outText.append("从文件读入的文法为:"+"\r\n"); 39 | HashSet result = new HashSet<>(); 40 | try { 41 | String path = System.getProperty("user.dir")+File.separator+"grammer"+File.separator; 42 | br = new BufferedReader(new FileReader(path+"a5.txt")); 43 | String s = null; 44 | while ((s = br.readLine()) != null) { 45 | outText.append("\t" + s+"\r\n"); 46 | result.add(s.trim()); 47 | } 48 | br.close(); 49 | } catch (Exception e) { 50 | e.printStackTrace(); 51 | } 52 | return result; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/compile/MainComplier.java: -------------------------------------------------------------------------------- 1 | package compile; 2 | 3 | import frame.OutText; 4 | import frame.ReadText; 5 | import lr0.LR0Main; 6 | 7 | import javax.swing.*; 8 | import java.awt.*; 9 | import java.awt.event.*; 10 | import java.io.*; 11 | 12 | /** 13 | * @description 这是主运行窗口 14 | */ 15 | @SuppressWarnings("all") 16 | public class MainComplier extends JFrame { 17 | 18 | //UI组件,运行窗口一些按钮 19 | JButton jButton1 = new JButton("词法分析"); 20 | JButton jButton2 = new JButton("清空"); 21 | JButton jButton3 = new JButton("LL1文法1"); 22 | JButton jButton4 = new JButton("LL1文法2"); 23 | JButton jButton5 = new JButton("LL1文法3"); 24 | JButton jButton6 = new JButton("LL1文法4"); 25 | JButton jButton7 = new JButton("LR0文法"); 26 | 27 | JLabel inLabel = new JLabel("待分析文件"); 28 | JLabel outLabel = new JLabel("分析结果"); 29 | ReadText readText = new ReadText(7, 90);//输入区 30 | OutText outText = new OutText(30, 90);//输出区 31 | 32 | //供子类继承使用 33 | public MainComplier(ReadText readText, OutText outText) throws HeadlessException { 34 | this.readText = readText; 35 | this.outText = outText; 36 | } 37 | //事件监听器 38 | public void initListener() { 39 | ActListener actListener = new ActListener(); 40 | jButton1.addActionListener(actListener); 41 | jButton2.addActionListener(actListener); 42 | jButton3.addActionListener(actListener); 43 | jButton4.addActionListener(actListener); 44 | jButton5.addActionListener(actListener); 45 | jButton6.addActionListener(actListener); 46 | jButton7.addActionListener(actListener); 47 | 48 | } 49 | //构建事件监听器 50 | class ActListener implements ActionListener { 51 | @Override 52 | public void actionPerformed(ActionEvent e) { 53 | if (e.getSource() == jButton1) { 54 | new Lexer(readText, outText).Analysis(); 55 | } else if (e.getSource() == jButton2) { 56 | readText.setText(""); 57 | outText.setText(""); 58 | } else if (e.getSource() == jButton3) { 59 | new Parser(readText, outText,1).Main(); 60 | } 61 | else if (e.getSource() == jButton4) { 62 | new Parser(readText, outText,2).Main(); 63 | } 64 | else if (e.getSource() == jButton5) { 65 | new Parser(readText, outText,3).Main(); 66 | } 67 | else if (e.getSource() == jButton6) { 68 | new Parser(readText, outText,4).Main(); 69 | } 70 | else if(e.getSource() == jButton7){ 71 | LR0Main.run(outText,readText); 72 | } 73 | } 74 | } 75 | //主窗口 76 | public MainComplier() throws IOException { 77 | super("词法分析器"); 78 | setSize(775, 780); 79 | this.setLocation(400, 70); 80 | setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 81 | this.setLayout(new FlowLayout(FlowLayout.CENTER));//中间对齐 82 | this.add(this.inLabel); 83 | this.add(this.readText); 84 | this.add(this.outLabel); 85 | this.add(this.outText); 86 | this.add(this.jButton1); 87 | this.add(this.jButton2); 88 | this.add(this.jButton3); 89 | this.add(this.jButton4); 90 | this.add(this.jButton5); 91 | this.add(this.jButton6); 92 | this.add(this.jButton7); 93 | initListener(); 94 | this.setVisible(true);//设置窗口可输入文本 95 | } 96 | } -------------------------------------------------------------------------------- /src/lr0/Production.java: -------------------------------------------------------------------------------- 1 | package lr0; 2 | 3 | import java.util.ArrayList; 4 | 5 | import static java.util.Arrays.sort; 6 | 7 | public class Production {//语句 8 | private static final char Point = '・'; 9 | private static final char Njump = 'ε'; 10 | String left; 11 | String right; 12 | 13 | //left->right 14 | public Production(String str) { 15 | String s[] = str.split("->"); 16 | left = s[0]; 17 | right = s[1]; 18 | } 19 | public Production() { } 20 | 21 | public String getLeft() { 22 | return left; 23 | } 24 | 25 | public void setLeft(String left) { 26 | this.left = left; 27 | } 28 | 29 | public String getRight() { 30 | return right; 31 | } 32 | 33 | public void setRight(String right) { 34 | this.right = right; 35 | } 36 | 37 | public boolean isSimple() { 38 | if (right.indexOf("|") == -1) 39 | return true; 40 | else 41 | return false; 42 | } 43 | //简化产生式 44 | public ArrayList toSimple() { 45 | ArrayList productionList = new ArrayList(); 46 | String b[] = right.split("\\|"); 47 | for (int i = 0; i < b.length; i++) { 48 | // System.out.println(b[i]); 49 | Production ib = new Production(left + "->" + b[i]); 50 | productionList.add(ib); 51 | } 52 | return productionList; 53 | } 54 | 55 | public String toString() { 56 | return left + "->" + right; 57 | } 58 | 59 | public Production insertDian() {//加点 60 | Production a; 61 | if(right.equals(String.valueOf(Njump))){// A->ε 转 A->・ 62 | a=new Production(left + "->" + Point); 63 | }else{ 64 | a=new Production(left + "->" + Point +right); 65 | } 66 | 67 | return a; 68 | } 69 | public Production deleteDian() {//去除点 70 | Production a=new Production(); 71 | a.setLeft(left); 72 | int iD=right.indexOf(Point); 73 | StringBuffer ab=new StringBuffer(right); 74 | ab.deleteCharAt(iD); 75 | if(ab.length()==0){//A->・ 转 A->ε 76 | ab.append(Njump); 77 | } 78 | a.setRight(ab.toString()); 79 | return a; 80 | } 81 | public Production moveDian() {//向右移动点 82 | Production a=new Production(); 83 | a.setLeft(left); 84 | int iD=right.indexOf(Point); 85 | StringBuffer ab=new StringBuffer(right); 86 | ab.deleteCharAt(iD); 87 | ab.insert(iD+1, Point); 88 | a.setRight(ab.toString()); 89 | return a; 90 | } 91 | @Override 92 | public boolean equals(Object obj) { 93 | Production other = (Production) obj; 94 | if(!left.equals(other.left)){ 95 | return false; 96 | } 97 | String[] a = right.split("\\|"); 98 | sort(a); 99 | String[] b = other.right.split("\\|"); 100 | sort(b); 101 | if (a.length == b.length) { 102 | for (int i = 0; i < b.length; i++) { 103 | if (!a[i].equals(b[i])) 104 | return false; 105 | } 106 | return true; 107 | } else { 108 | return false; 109 | } 110 | 111 | } 112 | 113 | @Override 114 | public int hashCode() {//不写的话HashSet认为同一“A->B”生成的Production(值)不相等 115 | int result = 0; 116 | String b[] = right.split("\\|"); 117 | for (String ib : b) { 118 | result += ib.hashCode(); 119 | } 120 | result += left.hashCode() * 31; 121 | return result; 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /src/compile/Lexer.java: -------------------------------------------------------------------------------- 1 | package compile; 2 | 3 | import entity.MultiComment; 4 | import entity.SingleComment; 5 | import entity.TokenList; 6 | import frame.OutText; 7 | import frame.ReadText; 8 | import java.awt.*; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.StringTokenizer; 12 | 13 | /** 14 | * @description 这是词法分析的具体实现 15 | */ 16 | @SuppressWarnings("all") 17 | public class Lexer extends MainComplier{ 18 | 19 | //词法分析解释规则,定义字符数组 20 | String[] keyWords = {"if", "else", "while", "for","read", "write", "int", "double","float","public","static","void","main","class"}; //关键字数组 21 | String[] operator = {"+", "-", "*", "/"};//运算符数组 22 | String[] roperator = {">", "<", "==", "!=",">=","<="};//关系运算符数组 23 | String[] sepretor = {";", "{", "}", "(", ")", "."};//分隔符数组 24 | 25 | String RegexToId = "^[a-zA-Z]([a-zA-Z_0-9])*[a-zA-Z0-9]$||[a-zA-Z]";//标识符的正则表达式 26 | String RegexToNumber = "^-?\\d+$";//整数的正则表达式 27 | String RegexToFloat = "^(-?\\d+)(\\.\\d+)?$";//浮点数的正则表达式 28 | String RegexToArray = "[a-zA-Z]+(\\[[0-9][1-9]*\\])+";//数组变量的正则表达式 29 | 30 | //将父类的readText, outText继承过来 31 | public Lexer(ReadText readText, OutText outText) throws HeadlessException { 32 | super(readText, outText); 33 | } 34 | 35 | //分析过程,此处为语法分析和词法分析提供已经修饰过的源程序 36 | public List getTokens() { 37 | List tokenLists = new ArrayList<>();//用于记录Token的信息 38 | String inputText = readText.getText(); 39 | StringTokenizer totalStrt = new StringTokenizer(inputText, "\r\n");//用回车与换行区分 40 | int row = 0;//行号 41 | //获取所有的记号以及记号的信息 42 | while (totalStrt.hasMoreTokens()) { 43 | List Tokens = new ArrayList<>();//行记号,一行中所有的Token 44 | StringTokenizer rowOfStrt = new StringTokenizer(totalStrt.nextToken(), " \n\r\t;(){}<>\"\'+-*/=", true); 45 | //所有可能的界符,初步得到所有的Token,但需要进一步的合并 46 | while (rowOfStrt.hasMoreTokens()) { 47 | Tokens.add(rowOfStrt.nextToken()); 48 | } 49 | TokenList tokenList = new TokenList(row, Tokens); 50 | tokenLists.add(tokenList); 51 | row++; 52 | } 53 | //对于初步得到的记号集合的进一步判断与整合,用于区别注释和*,/;以及=与==,以及<与<> 54 | for (int i = 0; i < tokenLists.size(); i++) { 55 | List tokenList = tokenLists.get(i).getTokenList();//获取行记号组 56 | for (int j = 0; j < tokenList.size() - 1; j++) { 57 | if (tokenList.get(j).equals("/") && tokenList.get(j + 1).equals("/")) { 58 | //单行注释记号的识别 59 | tokenList.set(j, "//"); 60 | tokenList.remove(j + 1); 61 | } else if (tokenList.get(j).equals("/") && tokenList.get(j + 1).equals("*")) { 62 | //多行注释的识别 63 | tokenList.set(j, "/*"); 64 | tokenList.remove(j + 1); 65 | } else if (tokenList.get(j).equals("*") && tokenList.get(j + 1).equals("/")) { 66 | //多行注释的识别 67 | tokenList.set(j, "*/"); 68 | tokenList.remove(j + 1); 69 | } else if (tokenList.get(j).equals("=") && tokenList.get(j + 1).equals("=")) { 70 | tokenList.set(j, "=="); 71 | tokenList.remove(j + 1); 72 | } else if (tokenList.get(j).equals("!") && tokenList.get(j + 1).equals("=")) { 73 | tokenList.set(j, "!="); 74 | tokenList.remove(j + 1);//判断不等于符号 75 | }else if (tokenList.get(j).equals(">") && tokenList.get(j + 1).equals("=")) { 76 | tokenList.set(j, ">="); 77 | tokenList.remove(j + 1);//判断不等于符号 78 | }else if (tokenList.get(j).equals("<") && tokenList.get(j + 1).equals("=")) { 79 | tokenList.set(j, "<="); 80 | tokenList.remove(j + 1);//判断不等于符号 81 | } 82 | } 83 | } 84 | //第二次对记号进行判断整合,主要用于去除各种分隔符 85 | for (int i = 0; i < tokenLists.size(); i++) { 86 | List tokenList = tokenLists.get(i).getTokenList();//获取行记号组 87 | String Pattern = "\\s+|\t|\r\n";//匹配空字符制表符换行符 88 | int j = 0; 89 | while(j multiComments = new ArrayList<>();//存放多行注释的位置信息 103 | List singleComments = new ArrayList<>();//存放单行注释的位置信息 104 | for (int i = 0; i < tokenLists.size(); i++)//多行注释的记号获取 105 | { 106 | List TokenOfrow = tokenLists.get(i).getTokenList(); 107 | int rowCount = tokenLists.get(i).getRow();//多行注释行号 108 | for (int j = 0; j < TokenOfrow.size(); j++) { 109 | if (TokenOfrow.get(j).equals("//")) { 110 | SingleComment singleComment = new SingleComment(rowCount, j); 111 | singleComments.add(singleComment);//记录单行注释位置 112 | } 113 | if (TokenOfrow.get(j).equals("/*")) { 114 | MultiComment multiComment = new MultiComment(rowCount, j, "/*");//j为列号 115 | multiComments.add(multiComment); 116 | } else if (TokenOfrow.get(j).equals("*/")) { 117 | MultiComment multiComment = new MultiComment(rowCount, j, "*/"); 118 | multiComments.add(multiComment); 119 | } 120 | } 121 | } 122 | for (int i = 0; i < multiComments.size(); i = i + 2)//去除多行注释中的整行注释 123 | { 124 | if ((multiComments.size() % 2) == 0 && i <= multiComments.size() - 2)//判断注释是否未闭合 125 | { 126 | if (multiComments.get(i).getComment().equals("/*") && multiComments.get(i + 1).getComment().equals("*/")) { 127 | int tempj = multiComments.get(i).getRow(); 128 | for (int j = multiComments.get(i).getRow() ; j <=multiComments.get(i + 1).getRow(); j++) { 129 | tokenLists.remove(tempj); 130 | } 131 | /*List StartLine = tokenLists.get(multiComments.get(i).getRow()).getTokenList();//注释行起始 132 | List EndLine = tokenLists.get(multiComments.get(i + 1).getRow()).getTokenList();//注释行结束 133 | for (int j = multiComments.get(i).getColumn(); j < StartLine.size(); )//因为随着元素的删除减少,size大小也会发生改变 134 | { 135 | StartLine.remove(j); 136 | } 137 | int position = multiComments.get(i).getColumn();//位置指针 138 | for (int j = 0; j <= position; )//同理,元素的数量的减少导致size改变 139 | { 140 | EndLine.remove(j); 141 | position--; 142 | }*/ 143 | } 144 | } else { 145 | outText.append("无法继续分析"); 146 | outText.append("第" + multiComments.get(i).getRow() + "行第" + multiComments.get(i).getColumn() + "处的注释未闭合"); 147 | return new ArrayList<>(); 148 | //break; 149 | } 150 | } 151 | for (int i = 0; i < singleComments.size(); i++) { 152 | List SignleLine = tokenLists.get(singleComments.get(i).getRow()).getTokenList(); 153 | for (int j = singleComments.get(i).getColumn(); j < SignleLine.size(); ) { 154 | SignleLine.remove(j);//去除单行注释 155 | } 156 | } 157 | return tokenLists; 158 | } 159 | 160 | //所有的记号处理都做好,此处纯分析记号 161 | public void Analysis() { 162 | List tokenLists = getTokens(); 163 | for (int i = 0; i < tokenLists.size(); i++) { 164 | List tokenList = tokenLists.get(i).getTokenList(); 165 | int lineid = tokenLists.get(i).getRow(); 166 | outText.append("--------------------------------------------------分析第" + (lineid + 1) + "行--------------------------------------------------" + "\r\n"); 167 | for (int j = 0; j < tokenList.size(); j++) { 168 | int Count = 0; 169 | for (int k = 0; k < keyWords.length; k++) { 170 | if (tokenList.get(j).equals(keyWords[k])) { 171 | outText.append(tokenList.get(j) + " 是关键字" + "\r\n"); 172 | Count++; 173 | } 174 | } 175 | for (int k = 0; k < operator.length; k++) { 176 | if (tokenList.get(j).equals(operator[k])) { 177 | outText.append(tokenList.get(j) + " 是运算符" + "\r\n"); 178 | Count++; 179 | } 180 | } 181 | for (int k = 0; k < roperator.length; k++) { 182 | if (tokenList.get(j).equals(roperator[k])) { 183 | outText.append(tokenList.get(j) + " 是关系运算符" + "\r\n"); 184 | Count++; 185 | } 186 | } 187 | for (int k = 0; k < sepretor.length; k++) { 188 | if (tokenList.get(j).equals(sepretor[k])) { 189 | outText.append(tokenList.get(j) + " 是分隔符" + "\r\n"); 190 | Count++; 191 | } 192 | } 193 | if (tokenList.get(j).matches(RegexToId) && (Count == 0)) { 194 | outText.append(tokenList.get(j) + " 是标识符" + "\r\n"); 195 | } else if (tokenList.get(j).matches(RegexToNumber)) { 196 | outText.append(tokenList.get(j) + " 是整数" + "\r\n"); 197 | } else if (tokenList.get(j).matches(RegexToFloat)) { 198 | outText.append(tokenList.get(j) + " 是浮点数" + "\r\n"); 199 | } else if (tokenList.get(j).matches(RegexToArray)) { 200 | outText.append(tokenList.get(j) + " 是数组变量" + "\r\n"); 201 | } else if (tokenList.get(j).equals("=")) { 202 | outText.append(tokenList.get(j) + " 是赋值号" + "\r\n"); 203 | } else if (Count == 0) { 204 | outText.append(tokenList.get(j) + " 标识符命名错误" + "\r\n"); 205 | } 206 | } 207 | } 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/lr0/Grammar.java: -------------------------------------------------------------------------------- 1 | package lr0; 2 | 3 | import frame.OutText; 4 | 5 | import java.io.PrintStream; 6 | import java.util.*; 7 | 8 | public class Grammar { 9 | private static final char Njump = 'ε'; 10 | private static final char Point = '・'; 11 | Set VN;//非终结符 12 | Set VT;//终结符集 13 | Set P;//规则集 14 | String S;//开始符 15 | Set IESet;//活前缀项目集间的边集 16 | ArrayList> IList;//项目集的数组 17 | ArrayList PList;//规则集的数组 18 | String[][] LRTable; 19 | ArrayList tableHead; 20 | Boolean isLRO = true; 21 | 22 | public Grammar(Set VN, Set VT, Set p, String s) { 23 | this.VN = VN; 24 | this.VT = VT; 25 | P = p; 26 | S = s; 27 | } 28 | 29 | public Grammar(String[] productions, String S) { 30 | this.S = "S'";//拓广文法 31 | VN = new HashSet<>(); 32 | VT = new HashSet<>(); 33 | P = new HashSet<>(); 34 | VN.add(S); 35 | P.add(new Production(this.S + "->" + S)); 36 | for (int i = 0; i < productions.length; i++) { 37 | Production p = new Production(productions[i]); 38 | VN.add(p.getLeft()); 39 | if (p.isSimple()) { 40 | P.add(p); 41 | String pr = p.getRight(); 42 | for (int j = 0; j < pr.length(); j++) { 43 | VT.add(String.valueOf(pr.charAt(j))); 44 | } 45 | } else { 46 | for (Production sp : p.toSimple()) { 47 | P.add(sp); 48 | String spr = sp.getRight(); 49 | for (int j = 0; j < spr.length(); j++) { 50 | VT.add(String.valueOf(spr.charAt(j))); 51 | } 52 | } 53 | } 54 | } 55 | VT.removeAll(VN); 56 | VT.remove(String.valueOf(Njump)); 57 | 58 | Set I0 = new HashSet<>();//活前缀项目集的开始集 59 | I0.add(new Production(this.S + "->" + Point + S)); 60 | calculationCLOSURE(I0); 61 | IList = new ArrayList<>(); 62 | IList.add(I0); 63 | calculationDFA(); 64 | if (!(isLRO = createLRTable())) { 65 | System.out.println("NO LR(0)!"); 66 | } 67 | 68 | } 69 | 70 | //对项目集I进行闭包运算 71 | private void calculationCLOSURE(Set I) { 72 | Set nV = new HashSet<>();//点后面的非终结符 73 | int ISize; 74 | do { 75 | ISize = I.size(); 76 | for (Production i : I) { 77 | String iRight = i.right; 78 | int Di = iRight.indexOf(Point); 79 | //截取 . 后面的非终结符 80 | if (Di + 1 < iRight.length()) { 81 | String inV = iRight.substring(Di + 1, Di + 2); 82 | if (VN.contains(inV)) { 83 | nV.add(inV); 84 | } 85 | } 86 | } 87 | for (Production ip : P) { 88 | if (nV.contains(ip.left)) { 89 | I.add(ip.insertDian());//加点 90 | } 91 | } 92 | } while (ISize != I.size()); 93 | } 94 | 95 | //求活前缀DFA,得到边集、项目集 96 | private void calculationDFA() { 97 | IESet = new HashSet<>();//存放DFA的边 98 | Queue> queue = new LinkedList<>(); 99 | queue.add(IList.get(0)); 100 | Set nI; 101 | Map> nIMap; 102 | 103 | while (!queue.isEmpty()) { 104 | Set iI = queue.poll(); 105 | nIMap = new HashMap<>(); 106 | //求转换 107 | for (Production i : iI) { 108 | String iRight = i.right; 109 | int Di = iRight.indexOf(Point); 110 | if (Di + 1 < iRight.length()) { 111 | String iV = iRight.substring(Di + 1, Di + 2); 112 | nI = nIMap.get(iV); 113 | if (nI == null) { 114 | nI = new HashSet<>(); 115 | nI.add(i.moveDian());//移点 116 | nIMap.put(iV, nI); 117 | } else { 118 | nI.add(i.moveDian()); 119 | } 120 | } 121 | } 122 | //求闭包 123 | int iList = IList.indexOf(iI); 124 | for (String v : nIMap.keySet()) { 125 | nI = nIMap.get(v); 126 | calculationCLOSURE(nI); 127 | int jList = IList.indexOf(nI); 128 | if (jList == -1) { 129 | queue.add(nI); 130 | IList.add(nI); 131 | jList = IList.size() - 1; 132 | } 133 | //加入边集 134 | IESet.add(new IE(iList, v, jList)); 135 | } 136 | //清空 137 | nIMap.clear(); 138 | } 139 | } 140 | public String format(int len,String str){ 141 | if(str.length() == len)return str; 142 | String temp = str; 143 | for (int i = str.length(); i <= len; i++) { 144 | temp+=" "; 145 | } 146 | return temp; 147 | } 148 | 149 | public void out(OutText outText) { 150 | outText.append("非终结符集 VN:{ "); 151 | for (Object iVN : VN) { 152 | outText.append(iVN.toString()+" "); 153 | } 154 | outText.append("}\r\n"); 155 | outText.append("终结符集 VT:{ "); 156 | 157 | for (Object iVT : VT) { 158 | outText.append(iVT.toString()+" "); 159 | 160 | } 161 | outText.append("}\r\n"); 162 | outText.append("产生式集 P:{\r\n"); 163 | for (Object ip : PList) { 164 | outText.append(ip.toString()+" \r\n"); 165 | } 166 | outText.append("}\r\n"); 167 | 168 | outText.append("开始符 S: "+S+"\r\n"); 169 | outText.append("DFA:\r\n\n"+IESet); 170 | PrintStream ps = null; 171 | ps = new PrintStream(System.out) { 172 | public void println(String x) { 173 | outText.append(x + "\r\n"); 174 | } 175 | public PrintStream printf(String format, Object ... args){ 176 | outText.append(String.format(format,args)); 177 | return null; 178 | } 179 | public void print(String s) { 180 | outText.append(s); 181 | } 182 | public void println(int x){ 183 | outText.append(x+"\r\n"); 184 | } 185 | }; 186 | System.setOut(ps); 187 | outText.append("\r\n\n\n"); 188 | 189 | outText.append("LR0表:"); 190 | outText.append("\r\n"); 191 | outText.append(format(80, " ")); 192 | for (String i : tableHead) { 193 | outText.append(format(10, i)); 194 | } 195 | outText.append("\r\n"); 196 | 197 | for (int i = 0; i < LRTable.length; i++) { 198 | outText.append(format(80, "S" + i + IList.get(i).toString())); 199 | outText.append("\r\n"); 200 | outText.append(format(80, " ")); 201 | 202 | for (int j = 0; j < LRTable[0].length; j++) { 203 | if (LRTable[i][j] != null) { 204 | outText.append(format(10, LRTable[i][j])); 205 | } 206 | 207 | else 208 | { 209 | outText.append(format(10, " ")); 210 | 211 | } 212 | } 213 | outText.append("\r\n"); 214 | //System.out.print("\n"); 215 | } 216 | } 217 | 218 | //构造LR0分析表 219 | public boolean createLRTable() { 220 | PList = new ArrayList<>(); 221 | PList.addAll(P); 222 | tableHead = new ArrayList<>(); 223 | tableHead.addAll(VT); 224 | tableHead.add("#"); 225 | tableHead.addAll(VN); 226 | tableHead.remove(S); 227 | 228 | 229 | // ArrayList> IList;//项目集的数组 230 | LRTable = new String[IList.size()][tableHead.size()]; 231 | //构造GO表 232 | int go[][] = new int[IList.size()][tableHead.size()]; 233 | for (IE ie : IESet) { 234 | int ivalue = tableHead.indexOf(ie.getValue()); 235 | int k = ie.getOrgin(); 236 | if (go[k][ivalue] == 0) 237 | go[k][ivalue] = ie.getAim(); 238 | else 239 | return false; //说明一个表内有重复值 也就是说识别一个字符到达两个状态 240 | } 241 | //填Action表 242 | for (int k = 0; k < IList.size(); k++) { 243 | for (Production ip : IList.get(k)) { 244 | String right = ip.getRight(); 245 | int iD = right.indexOf(Point); 246 | if (iD < right.length() - 1) { //A->α・aβ GO(Ik,a)=Ij 247 | String a = right.substring(iD + 1, iD + 2); 248 | if (VT.contains(a)) {//a为终结符 249 | int ia = tableHead.indexOf(a); 250 | if (LRTable[k][ia] == null) 251 | LRTable[k][ia] = "S" + go[k][ia]; 252 | else 253 | return false;//有重复值 出错 254 | } 255 | } else {//A->α・ 256 | if (ip.getLeft().equals(S)) { 257 | if (LRTable[k][VT.size()] == null) 258 | LRTable[k][VT.size()] = "acc"; 259 | else 260 | return false; 261 | } else { 262 | for (int ia = 0; ia < VT.size() + 1; ia++) { 263 | 264 | if (LRTable[k][ia] == null) 265 | LRTable[k][ia] = "r" + PList.indexOf(ip.deleteDian()); 266 | else 267 | return false; 268 | } 269 | } 270 | } 271 | } 272 | } 273 | 274 | 275 | //合并表 276 | for (int j = VT.size(); j < tableHead.size(); j++) { 277 | for (int k = 0; k < IList.size(); k++) { 278 | if (go[k][j] != 0) { 279 | if (LRTable[k][j] == null) 280 | LRTable[k][j] = "" + go[k][j]; 281 | else 282 | return false; 283 | } 284 | } 285 | } 286 | return true; 287 | } 288 | 289 | //判断st是否符合文法,LR0分析器 290 | public boolean contains(String st) throws Exception { 291 | if (isLRO) { 292 | st += "#"; 293 | Stack stateStack = new Stack<>(); 294 | Stack signStack = new Stack<>(); 295 | stateStack.push(0); 296 | signStack.push("#"); 297 | Production p; 298 | int VTL = VT.size(); 299 | int bz = 0;//步骤数 300 | for (int i = 0; i < st.length(); i++) { 301 | if (true) {//显示分析过程 302 | System.out.println(++bz); 303 | System.out.print("状态栈:"); 304 | System.out.println(stateStack); 305 | System.out.println(" "); 306 | System.out.print("符号栈:"); 307 | System.out.println(signStack); 308 | System.out.println(" "); 309 | System.out.print("输入串:"); 310 | System.out.println(st.substring(i)); 311 | System.out.println(" "); 312 | 313 | } 314 | String a = st.substring(i, i + 1); 315 | int ai = tableHead.indexOf(a); 316 | String ag = LRTable[stateStack.peek()][ai]; 317 | if (ag == null) return false; 318 | else if (ag.equals("acc")) { 319 | return true; 320 | } 321 | if (ai < VT.size() + 1) {//action 322 | int nub = Integer.valueOf(ag.substring(1)); 323 | if (ag.charAt(0) == 'S') { 324 | stateStack.push(nub); 325 | signStack.push(a); 326 | } else {//r 327 | p = PList.get(nub); 328 | int k = p.getRight().length(); 329 | if (!p.getRight().equals(String.valueOf(Njump))) {//排除归约为 A->ε 330 | while (k-- > 0) { 331 | stateStack.pop(); 332 | signStack.pop(); 333 | } 334 | } 335 | //goto 336 | String go = LRTable[stateStack.peek()][tableHead.indexOf(p.getLeft())]; 337 | if (go == null) return false; 338 | stateStack.push(Integer.valueOf(go)); 339 | signStack.push(p.getLeft()); 340 | i--; 341 | } 342 | } 343 | } 344 | return false; 345 | } 346 | throw new Exception("无法判断:该文法不是LR(0)文法!"); 347 | 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /src/compile/Parser.java: -------------------------------------------------------------------------------- 1 | package compile; 2 | 3 | import frame.OutText; 4 | import frame.ReadText; 5 | import java.awt.*; 6 | import java.io.BufferedReader; 7 | import java.io.File; 8 | import java.io.FileReader; 9 | import java.security.PublicKey; 10 | import java.util.*; 11 | 12 | /** 13 | * @description 这是词法分析的具体实现 14 | */ 15 | @SuppressWarnings("all") 16 | public class Parser extends MainComplier{ 17 | //语法分析的规则 18 | public static final String PATH = "./grammar2";// 文法 19 | private static String START; // 开始符号 20 | private static HashSet VN, VT; // 非终结符号集、终结符号集 21 | private static HashMap>> MAP;// key:产生式左边 value:产生式右边(含多条) 22 | private static HashMap oneLeftFirst;// "|" 分开的单条产生式对应的FIRST集合,用于构建预测分析表 23 | private static HashMap> FIRST, FOLLOW; // FIRST、FOLLOW集合 24 | private static String[][] FORM; // 存放预测分析表的数组,用于输出 25 | private static HashMap preMap;// 存放预测分析表的map,用于快速查找 26 | private int choice; 27 | 28 | //将父类的readText, outText继承过来 29 | public Parser(ReadText readText, OutText outText, int choice) throws HeadlessException { 30 | super(readText, outText); 31 | this.choice=choice; 32 | } 33 | 34 | //程序入口 35 | public void Main() { 36 | init(); // 初始化变量 37 | identifyVnVt(readFile(new File(PATH)));// 符号分类,并以key-value形式存于MAP中 38 | reformMap();// 消除左递归和提取左公因子 39 | findFirst(); // 求FIRST集合 40 | findFollow(); // 求FOLLOW集合 41 | if (isLL1()) { 42 | preForm(); // 构建预测分析表 43 | printAutoPre(readText.getText()); 44 | } 45 | } 46 | // 从文件读文法 47 | public ArrayList readFile(File file) { 48 | BufferedReader br = null; 49 | outText.append("从文件读入的文法为:"+"\r\n"); 50 | ArrayList result = new ArrayList<>(); 51 | try { 52 | String path = System.getProperty("user.dir")+File.separator+"grammer"+File.separator; 53 | if (choice == 1) { 54 | br = new BufferedReader(new FileReader(path+"a1.txt")); 55 | } else if (choice == 2){ 56 | br = new BufferedReader(new FileReader(path+"a2.txt")); 57 | } else if (choice == 3){ 58 | br = new BufferedReader(new FileReader(path+"a3.txt")); 59 | } else if (choice == 4){ 60 | br = new BufferedReader(new FileReader(path+"a4.txt")); 61 | } 62 | String s = null; 63 | while ((s = br.readLine()) != null) { 64 | outText.append("\t" + s+"\r\n"); 65 | result.add(s.trim()); 66 | } 67 | br.close(); 68 | } catch (Exception e) { 69 | e.printStackTrace(); 70 | } 71 | return result; 72 | } 73 | // 变量初始化 74 | private static void init() { 75 | VN = new HashSet<>(); 76 | VT = new HashSet<>(); 77 | MAP = new HashMap<>(); 78 | FIRST = new HashMap<>(); 79 | FOLLOW = new HashMap<>(); 80 | oneLeftFirst = new HashMap<>(); 81 | preMap = new HashMap<>(); 82 | } 83 | // 符号分类 84 | private void identifyVnVt(ArrayList list) { 85 | START = list.get(0).charAt(0) + "";// 存放开始符号 86 | 87 | for (int i = 0; i < list.size(); i++) { 88 | String oneline = list.get(i); 89 | String[] vnvt = oneline.split("→");// 用定义符号分割 90 | String left = vnvt[0].trim(); // 文法的左边 91 | VN.add(left); 92 | 93 | // 文法右边 94 | ArrayList> mapValue = new ArrayList<>(); 95 | ArrayList right = new ArrayList<>(); 96 | 97 | for (int j = 0; j < vnvt[1].length(); j++) { // 用 “|”分割右边 98 | if (vnvt[1].charAt(j) == '|') { 99 | VT.addAll(right); 100 | mapValue.add(right); 101 | // right.clear();// 清空之后,依然是同一个地址,需要重新new对象 102 | right = null; 103 | right = new ArrayList<>(); 104 | continue; 105 | } 106 | // 如果产生式某字符的左边含有中文或英文的单引号,则视为同一个字符 107 | if (j + 1 < vnvt[1].length() && (vnvt[1].charAt(j + 1) == '\'' || vnvt[1].charAt(j + 1) == '’')) { 108 | right.add(vnvt[1].charAt(j) + "" + vnvt[1].charAt(j + 1)); 109 | j++; 110 | } else { 111 | right.add(vnvt[1].charAt(j) + ""); 112 | } 113 | } 114 | VT.addAll(right); 115 | mapValue.add(right); 116 | 117 | MAP.put(left, mapValue); 118 | } 119 | VT.removeAll(VN); // 从终结字符集中移除非终结符 120 | // 打印Vn、Vt 121 | outText.append("\nVn集合:\r\n\t{" + String.join("、", VN.toArray(new String[VN.size()])) + "}"+"\r\n"); 122 | outText.append("Vt集合:\n\t{" + String.join("、", VT.toArray(new String[VT.size()])) + "}"+"\r\n"); 123 | 124 | } 125 | // 消除直接左递归 126 | private void reformMap() { 127 | boolean isReForm = false;// MAP是否被修改 128 | Set keys = new HashSet<>(); 129 | keys.addAll(MAP.keySet()); 130 | Iterator it = keys.iterator(); 131 | ArrayList nullSign = new ArrayList<>(); 132 | nullSign.add("ε"); 133 | while (it.hasNext()) { 134 | String left = it.next(); 135 | boolean flag = false;// 是否有左递归 136 | ArrayList> rightList = MAP.get(left); 137 | ArrayList oldRightCell = new ArrayList<>(); // 旧产生的右边 138 | ArrayList> newLeftNew = new ArrayList<>();// 存放新的左边的新的右边 139 | 140 | // 消除直接左递归 141 | for (int i = 0; i < rightList.size(); i++) { 142 | ArrayList newRightCell = new ArrayList<>(); // 新产生式的右边 143 | if (rightList.get(i).get(0).equals(left)) { 144 | //P‘的右部分 145 | for (int j = 1; j < rightList.get(i).size(); j++) { 146 | newRightCell.add(rightList.get(i).get(j)); 147 | } 148 | flag = true; 149 | newRightCell.add(left + "\'"); 150 | newLeftNew.add(newRightCell); 151 | } else { 152 | //P的右部分 153 | for (int j = 0; j < rightList.get(i).size(); j++) { 154 | oldRightCell.add(rightList.get(i).get(j)); 155 | } 156 | oldRightCell.add(left + "\'"); 157 | } 158 | } 159 | // 如果有左递归,则更新MAP 160 | if (flag) { 161 | isReForm = true; 162 | newLeftNew.add(nullSign); 163 | MAP.put(left + "\'", newLeftNew); 164 | VN.add(left + "\'"); // 加入新的VN 165 | VT.add("ε"); // 加入ε到VT 166 | ArrayList> newLeftOld = new ArrayList<>();// 存放原先,但是产生新的右边 167 | newLeftOld.add(oldRightCell); 168 | MAP.put(left, newLeftOld); 169 | } 170 | } 171 | // 如果文法被修改,则输出修改后的文法 172 | if (isReForm) { 173 | outText.append("消除文法的左递归:"+"\r\n"); 174 | Set kSet = new HashSet<>(MAP.keySet()); 175 | Iterator itk = kSet.iterator(); 176 | while (itk.hasNext()) { 177 | String k = itk.next(); 178 | ArrayList> leftList = MAP.get(k); 179 | outText.append("\t" + k + "→"); 180 | for (int i = 0; i < leftList.size(); i++) { 181 | outText.append(String.join("", leftList.get(i).toArray(new String[leftList.get(i).size()]))); 182 | if (i + 1 < leftList.size()) { 183 | outText.append("|"); 184 | } 185 | } 186 | outText.append("\r\n"); 187 | } 188 | } 189 | } 190 | // 求每个非终结符号的FIRST集合 和 分解单个产生式的FIRST集合 191 | private void findFirst() { 192 | outText.append("\nFIRST集合:"+"\r\n"); 193 | Iterator it = VN.iterator(); 194 | while (it.hasNext()) { 195 | HashSet firstCell = new HashSet<>();// 存放单个非终结符号的FIRST 196 | String key = it.next(); 197 | ArrayList> list = MAP.get(key); 198 | // System.out.println(key+":"); 199 | // 遍历单个产生式的左边 200 | for (int i = 0; i < list.size(); i++) { 201 | ArrayList listCell = list.get(i);// listCell为“|”分割出来 202 | HashSet firstCellOne = new HashSet<>();// 产生式左边用“ | ”分割的单个式子的First(弃用) 203 | String oneLeft = String.join("", listCell.toArray(new String[listCell.size()])); 204 | // System.out.println("oneLeft: "+oneLeft); 205 | if (VT.contains(listCell.get(0))) { 206 | firstCell.add(listCell.get(0)); 207 | firstCellOne.add(listCell.get(0)); 208 | oneLeftFirst.put(key + "$" + listCell.get(0), key + "→" + oneLeft); 209 | } else { 210 | boolean[] isVn = new boolean[listCell.size()];// 标记是否有定义为空,如果有则检查下一个字符 211 | isVn[0] = true;// 第一个为非终结符号 212 | int p = 0; 213 | while (isVn[p]) { 214 | // System.out.println(p+" "+listCell.size()); 215 | if (VT.contains(listCell.get(p))) { 216 | firstCell.add(listCell.get(p)); 217 | firstCellOne.add(listCell.get(p)); 218 | oneLeftFirst.put(key + "$" + listCell.get(p), key + "→" + oneLeft); 219 | break; 220 | } 221 | String vnGo = listCell.get(p);// 222 | Stack stack = new Stack<>(); 223 | stack.push(vnGo); 224 | //遍历非终结符的产生式右端 225 | while (!stack.isEmpty()) { 226 | ArrayList> listGo = MAP.get(stack.pop()); 227 | for (int k = 0; k < listGo.size(); k++) { 228 | ArrayList listGoCell = listGo.get(k); 229 | if (VT.contains(listGoCell.get(0))) { // 如果第一个字符是终结符号 230 | if ("ε".equals(listGoCell.get(0))) { 231 | if (!key.equals(START)) { // 开始符号不能推出空 232 | firstCell.add(listGoCell.get(0)); 233 | firstCellOne.add(listGoCell.get(0)); 234 | oneLeftFirst.put(key + "$" + listGoCell.get(0), key + "→" + oneLeft); 235 | } 236 | if (p + 1 < isVn.length) {// 如果为空,可以查询下一个字符 237 | isVn[p + 1] = true; 238 | } 239 | } else { // 非空的终结符号加入对应的FIRST集合 240 | firstCell.add(listGoCell.get(0)); 241 | firstCellOne.add(listGoCell.get(0)); 242 | oneLeftFirst.put(key + "$" + listGoCell.get(0), key + "→" + oneLeft); 243 | } 244 | } else {// 不是终结符号,入栈 245 | stack.push(listGoCell.get(0)); 246 | } 247 | } 248 | } 249 | p++; 250 | if (p > isVn.length - 1) { 251 | break; 252 | } 253 | } 254 | } 255 | FIRST.put(key + "→" + oneLeft, firstCellOne); 256 | } 257 | FIRST.put(key, firstCell); 258 | // 输出key的FIRST集合 259 | outText.append( 260 | "\tFIRST(" + key + ")={" + String.join("、", firstCell.toArray(new String[firstCell.size()])) + "}"+"\r\n"); 261 | } 262 | } 263 | private void MyfindFollow(){ 264 | outText.append("\nFOLLOW集合:"+"\r\n"); 265 | HashMap> keyFollow = new HashMap<>(); 266 | HashSetStartFollow = new HashSet<>(); 267 | StartFollow.add("#"); 268 | keyFollow.put(START,StartFollow); 269 | boolean isChange = true; 270 | while(isChange){ 271 | isChange = false; 272 | Iterator it = VN.iterator(); 273 | while (it.hasNext()){ 274 | String key = it.next(); 275 | ArrayList>lists = new ArrayList<>(); 276 | lists = MAP.get(key); 277 | for (int i = 0; i < lists.size(); i++) { 278 | ArrayList listCell = lists.get(i); 279 | for (int j = 0; j < listCell.size(); j++) { 280 | String v = listCell.get(j); 281 | if(VN.contains(v)){ 282 | if(j+1 >= listCell.size()){ 283 | continue; 284 | } 285 | HashSetfollow = new HashSet<>(); 286 | if(keyFollow.containsKey(v)){ 287 | follow = keyFollow.get(v); 288 | } 289 | int followsize = follow.size(); 290 | if(VT.contains(listCell.get(j+1))){ 291 | follow.add(listCell.get(j+1)); 292 | } 293 | else{ 294 | if(FIRST.get(listCell.get(j+1)).contains("ε") == false){ 295 | follow.addAll(FIRST.get(listCell.get(j+1))); 296 | } 297 | else{ 298 | Set set = FIRST.get(listCell.get(j+1)); 299 | set.remove("ε"); 300 | follow.addAll(set); 301 | if(keyFollow.containsKey(listCell.get(j+1))){ 302 | follow.addAll(keyFollow.get(listCell.get(j+1))); 303 | } 304 | } 305 | } 306 | if(followsize!=follow.size()){ 307 | isChange = true; 308 | keyFollow.put(v,follow); 309 | } 310 | } 311 | } 312 | } 313 | 314 | } 315 | } 316 | Iterator itF = keyFollow.keySet().iterator(); 317 | while (itF.hasNext()) { 318 | String key = itF.next(); 319 | HashSet f = keyFollow.get(key); 320 | outText.append("\tFOLLOW(" + key + ")={" + String.join("、", f.toArray(new String[f.size()])) + "}"+"\r\n"); 321 | } 322 | 323 | 324 | } 325 | // 求每个非终结符号的FOLLOW集合 326 | private void findFollow() { 327 | outText.append("\nFOLLOW集合:"+"\r\n"); 328 | Iterator it = VN.iterator(); 329 | HashMap> keyFollow = new HashMap<>(); 330 | 331 | ArrayList> vn_VnList = new ArrayList<>();// 用于存放/A->...B 或者 A->...Bε的组合 332 | 333 | HashSet vn_VnListLeft = new HashSet<>();// 存放vn_VnList的左边和右边 334 | HashSet vn_VnListRight = new HashSet<>(); 335 | // 开始符号加入# 336 | keyFollow.put(START, new HashSet() { 337 | private static final long serialVersionUID = 1L; 338 | { 339 | add(new String("#")); 340 | } 341 | }); 342 | 343 | while (it.hasNext()) { 344 | String key = it.next(); 345 | ArrayList> list = MAP.get(key); 346 | ArrayList listCell; 347 | 348 | // 先把每个VN作为keyFollow的key,之后在查找添加其FOLLOW元素 349 | if (!keyFollow.containsKey(key)) { 350 | keyFollow.put(key, new HashSet<>()); 351 | } 352 | keyFollow.toString(); 353 | 354 | for (int i = 0; i < list.size(); i++) { 355 | listCell = list.get(i); 356 | 357 | // (1)直接找非终结符号后面跟着终结符号 358 | for (int j = 1; j < listCell.size(); j++) { 359 | HashSet set = new HashSet<>(); 360 | if (VT.contains(listCell.get(j))) { 361 | // System.out.println(listCell.get(j - 1) + ":" + listCell.get(j)); 362 | set.add(listCell.get(j)); 363 | if (keyFollow.containsKey(listCell.get(j - 1))) { 364 | set.addAll(keyFollow.get(listCell.get(j - 1))); 365 | } 366 | keyFollow.put(listCell.get(j - 1), set); 367 | } 368 | } 369 | // (2)找...VnVn...组合 370 | for (int j = 0; j < listCell.size() - 1; j++) { 371 | HashSet set = new HashSet<>(); 372 | if (VN.contains(listCell.get(j)) && VN.contains(listCell.get(j + 1))) { 373 | set.addAll(FIRST.get(listCell.get(j + 1))); 374 | set.remove("ε"); 375 | 376 | if (keyFollow.containsKey(listCell.get(j))) { 377 | set.addAll(keyFollow.get(listCell.get(j))); 378 | } 379 | keyFollow.put(listCell.get(j), set); 380 | } 381 | } 382 | 383 | // (3)A->...B 或者 A->...Bε(可以有n个ε)的组合存起来 384 | for (int j = 0; j < listCell.size(); j++) { 385 | HashMap vn_Vn; 386 | if (VN.contains(listCell.get(j)) && !listCell.get(j).equals(key)) {// 是VN且A不等于B 387 | boolean isAllNull = false;// 标记VN后是否为空 388 | if (j + 1 < listCell.size()) {// 即A->...Bε(可以有n个ε) 389 | for (int k = j + 1; k < listCell.size(); k++) { 390 | if ((FIRST.containsKey(listCell.get(k)) ? FIRST.get(listCell.get(k)).contains("ε") 391 | : false)) {// 如果其后面的都是VN且其FIRST中包含ε 392 | isAllNull = true; 393 | } else { 394 | isAllNull = false; 395 | break; 396 | } 397 | } 398 | } 399 | // 如果是最后一个为VN,即A->...B 400 | if (j == listCell.size() - 1) { 401 | isAllNull = true; 402 | } 403 | if (isAllNull) { 404 | vn_VnListLeft.add(key); 405 | vn_VnListRight.add(listCell.get(j)); 406 | 407 | // 往vn_VnList中添加,分存在和不存在两种情况 408 | boolean isHaveAdd = false; 409 | for (int x = 0; x < vn_VnList.size(); x++) { 410 | HashMap vn_VnListCell = vn_VnList.get(x); 411 | if (!vn_VnListCell.containsKey(key)) { 412 | vn_VnListCell.put(key, listCell.get(j)); 413 | vn_VnList.set(x, vn_VnListCell); 414 | isHaveAdd = true; 415 | break; 416 | } else { 417 | // 去重 418 | if (vn_VnListCell.get(key).equals(listCell.get(j))) { 419 | isHaveAdd = true; 420 | break; 421 | } 422 | continue; 423 | } 424 | } 425 | if (!isHaveAdd) {// 如果没有添加,表示是新的组合 426 | vn_Vn = new HashMap<>(); 427 | vn_Vn.put(key, listCell.get(j)); 428 | vn_VnList.add(vn_Vn); 429 | } 430 | } 431 | } 432 | } 433 | } 434 | } 435 | 436 | keyFollow.toString(); 437 | 438 | // (4)vn_VnListLeft减去vn_VnListRight,剩下的就是入口产生式, 439 | vn_VnListLeft.removeAll(vn_VnListRight); 440 | Queue keyQueue = new LinkedList<>();// 用栈或者队列都行 441 | Iterator itVnVn = vn_VnListLeft.iterator(); 442 | while (itVnVn.hasNext()) { 443 | keyQueue.add(itVnVn.next()); 444 | } 445 | while (!keyQueue.isEmpty()) { 446 | String keyLeft = keyQueue.poll(); 447 | for (int t = 0; t < vn_VnList.size(); t++) { 448 | HashMap vn_VnListCell = vn_VnList.get(t); 449 | if (vn_VnListCell.containsKey(keyLeft)) { 450 | HashSet set = new HashSet<>(); 451 | // 原来的FOLLOW加上左边的FOLLOW 452 | if (keyFollow.containsKey(keyLeft)) { 453 | set.addAll(keyFollow.get(keyLeft)); 454 | } 455 | if (keyFollow.containsKey(vn_VnListCell.get(keyLeft))) { 456 | set.addAll(keyFollow.get(vn_VnListCell.get(keyLeft))); 457 | } 458 | keyFollow.put(vn_VnListCell.get(keyLeft), set); 459 | keyQueue.add(vn_VnListCell.get(keyLeft)); 460 | 461 | // 移除已处理的组合 462 | vn_VnListCell.remove(keyLeft); 463 | vn_VnList.set(t, vn_VnListCell); 464 | } 465 | } 466 | } 467 | 468 | // 此时keyFollow为完整的FOLLOW集 469 | FOLLOW = keyFollow; 470 | // 打印FOLLOW集合 471 | Iterator itF = keyFollow.keySet().iterator(); 472 | while (itF.hasNext()) { 473 | String key = itF.next(); 474 | HashSet f = keyFollow.get(key); 475 | outText.append("\tFOLLOW(" + key + ")={" + String.join("、", f.toArray(new String[f.size()])) + "}"+"\r\n"); 476 | } 477 | } 478 | // 判断是否是LL(1)文法 479 | private boolean isLL1() { 480 | outText.append("\n正在判断是否是LL(1)文法...."+"\r\n"); 481 | boolean flag = true;// 标记是否是LL(1)文法 482 | Iterator it = VN.iterator(); 483 | while (it.hasNext()) { 484 | String key = it.next(); 485 | ArrayList> list = MAP.get(key);// 单条产生式 486 | if (list.size() > 1) { // 如果单条产生式的左边包含两个式子以上,则进行判断 487 | for (int i = 0; i < list.size(); i++) { 488 | String aLeft = String.join("", list.get(i).toArray(new String[list.get(i).size()])); 489 | for (int j = i + 1; j < list.size(); j++) { 490 | String bLeft = String.join("", list.get(j).toArray(new String[list.get(j).size()])); 491 | if ("ε".equals(aLeft) || "ε".equals(bLeft)) { // (1)若b=ε,则要FIRST(A)∩FOLLOW(A)=φ 492 | HashSet retainSet = new HashSet<>(); 493 | // retainSet=FIRST.get(key);//需要要深拷贝,否则修改retainSet时FIRST同样会被修改 494 | retainSet.addAll(FIRST.get(key)); 495 | if (FOLLOW.get(key) != null) { 496 | retainSet.retainAll(FOLLOW.get(key)); 497 | } 498 | if (!retainSet.isEmpty()) { 499 | flag = false;// 不是LL(1)文法,输出FIRST(a)FOLLOW(a)的交集 500 | outText.append("\tFIRST(" + key + ") ∩ FOLLOW(" + key + ") = {" 501 | + String.join("、", retainSet.toArray(new String[retainSet.size()])) + "}\r\n"); 502 | break; 503 | } else { 504 | outText.append("\tFIRST(" + key + ") ∩ FOLLOW(" + key + ") = φ"+"\r\n"); 505 | } 506 | } else { // (2)b!=ε若,则要FIRST(a)∩FIRST(b)= Ф 507 | HashSet retainSet = new HashSet<>(); 508 | retainSet.addAll(FIRST.get(key + "→" + aLeft)); 509 | retainSet.retainAll(FIRST.get(key + "→" + bLeft)); 510 | if (!retainSet.isEmpty()) { 511 | flag = false;// 不是LL(1)文法,输出FIRST(a)FIRST(b)的交集 512 | outText.append("\tFIRST(" + aLeft + ") ∩ FIRST(" + bLeft + ") = {" 513 | + String.join("、", retainSet.toArray(new String[retainSet.size()])) + "}"+"\r\n"); 514 | break; 515 | } else { 516 | outText.append("\tFIRST(" + aLeft + ") ∩ FIRST(" + bLeft + ") = φ"+"\r\n"); 517 | } 518 | } 519 | } 520 | } 521 | } 522 | } 523 | if(flag) { 524 | outText.append("\t是LL(1)文法,继续分析!"+"\r\n"); 525 | }else { 526 | outText.append("\t不是LL(1)文法,退出分析!"+"\r\n"); 527 | } 528 | return flag; 529 | } 530 | // 构建预测分析表FORM 531 | private void preForm() { 532 | HashSet set = new HashSet<>(); 533 | set.addAll(VT); 534 | set.remove("ε"); 535 | FORM = new String[VN.size() + 1][set.size() + 2]; 536 | Iterator itVn = VN.iterator(); 537 | Iterator itVt = set.iterator(); 538 | 539 | // (1)初始化FORM,并根据oneLeftFirst(VN$VT,产生式)填表 540 | for (int i = 0; i < FORM.length; i++){ 541 | for (int j = 0; j < FORM[0].length; j++) { 542 | if (i == 0 && j > 0) {// 第一行为Vt 543 | if (itVt.hasNext()) { 544 | FORM[i][j] = itVt.next(); 545 | } 546 | if (j == FORM[0].length - 1) {// 最后一列加入# 547 | FORM[i][j] = "#"; 548 | } 549 | } 550 | if (j == 0 && i > 0) {// 第一列为Vn 551 | if (itVn.hasNext()) { 552 | FORM[i][j] = itVn.next(); 553 | } 554 | } 555 | if (i > 0 && j > 0) {// 其他情况先根据oneLeftFirst填表 556 | String oneLeftKey = FORM[i][0] + "$" + FORM[0][j];// 作为key查找其First集合 557 | FORM[i][j] = oneLeftFirst.get(oneLeftKey); 558 | } 559 | } 560 | } 561 | 562 | // (2)如果有推出了ε,则根据FOLLOW填表 563 | for (int i = 1; i < FORM.length; i++) { 564 | String oneLeftKey = FORM[i][0] + "$ε"; 565 | if (oneLeftFirst.containsKey(oneLeftKey)) { 566 | HashSet followCell = FOLLOW.get(FORM[i][0]); 567 | Iterator it = followCell.iterator(); 568 | while (it.hasNext()) { 569 | String vt = it.next(); 570 | for (int j = 1; j < FORM.length; j++) { 571 | for (int k = 1; k < FORM[0].length; k++) { 572 | if (FORM[j][0].equals(FORM[i][0]) && FORM[0][k].equals(vt)) { 573 | FORM[j][k] = oneLeftFirst.get(oneLeftKey);//Vn->ε 574 | } 575 | } 576 | } 577 | } 578 | } 579 | } 580 | 581 | // (3)打印预测表,并存于Map的数据结构中用于快速查找 582 | outText.append("\n该文法的预测分析表为:"+"\r\n"); 583 | for (int i = 0; i < FORM.length; i++) { 584 | for (int j = 0; j < FORM[0].length; j++) { 585 | if (FORM[i][j] == null) { 586 | outText.append(" " + "\t"); 587 | } 588 | else { 589 | outText.append(FORM[i][j] + "\t"); 590 | if (i > 0 && j > 0) { 591 | String[] tmp = FORM[i][j].split("→"); 592 | preMap.put(FORM[i][0] + "" + FORM[0][j], tmp[1]); 593 | } 594 | } 595 | } 596 | outText.append("\r\n"); 597 | } 598 | outText.append("\r\n"); 599 | } 600 | // 输入的单词串分析推导过程 601 | public void printAutoPre(String str) { 602 | outText.append(str + "的分析过程:"+"\r\n"); 603 | Queue queue = new LinkedList<>();// 句子拆分存于队列 604 | for (int i = 0; i < str.length(); i++) { 605 | String t = str.charAt(i) + ""; 606 | if (i + 1 < str.length() && (str.charAt(i + 1) == '\'' || str.charAt(i + 1) == '’')) { 607 | t += str.charAt(i + 1); 608 | i++; 609 | } 610 | queue.offer(t); 611 | } 612 | queue.offer("#");// "#"结束 613 | // 分析栈 614 | Stack stack = new Stack<>(); 615 | stack.push("#");// "#"开始 616 | stack.push(START);// 初态为开始符号 617 | boolean isSuccess = false; 618 | int step = 1; 619 | while (!stack.isEmpty()) { 620 | String left = stack.peek(); 621 | String right = queue.peek(); 622 | // (1)分析成功 623 | if (left.equals(right) && "#".equals(right)) { 624 | isSuccess = true; 625 | outText.append((step++) + "\t#\t#\t" + "分析成功"+"\r\n"); 626 | break; 627 | } 628 | // (2)匹配栈顶和当前符号,均为终结符号,消去 629 | if (left.equals(right)) { 630 | String stackStr = String.join("", stack.toArray(new String[stack.size()])); 631 | String queueStr = String.join("", queue.toArray(new String[queue.size()])); 632 | outText.append((step++) + "\t" + stackStr + "\t" + queueStr + "\t匹配成功" + left + "\r\n"); 633 | stack.pop(); 634 | queue.poll(); 635 | continue; 636 | } 637 | // (3)从预测表中查询 638 | if (preMap.containsKey(left + right)) { 639 | String stackStr = String.join("", stack.toArray(new String[stack.size()])); 640 | String queueStr = String.join("", queue.toArray(new String[queue.size()])); 641 | outText.append((step++) + "\t" + stackStr + "\t" + queueStr + "\t用" + left + "→" 642 | + preMap.get(left + right) + "," + right + "逆序进栈" + "\r\n"); 643 | stack.pop(); 644 | String tmp = preMap.get(left + right); 645 | for (int i = tmp.length() - 1; i >= 0; i--) {// 逆序进栈 646 | String t = ""; 647 | if (tmp.charAt(i) == '\'' || tmp.charAt(i) == '’') { 648 | t = tmp.charAt(i-1)+""+tmp.charAt(i); 649 | i--; 650 | }else { 651 | t=tmp.charAt(i)+""; 652 | } 653 | if (!"ε".equals(t)) { 654 | stack.push(t); 655 | } 656 | } 657 | continue; 658 | } 659 | break;// (4)其他情况失败并退出 660 | } 661 | if (!isSuccess) { 662 | outText.append((step++) + "\t#\t#\t" + "分析失败"+"\r\n"); 663 | } 664 | } 665 | } 666 | --------------------------------------------------------------------------------