1. 程式人生 > >哈工大編譯原理實驗2——語法分析

哈工大編譯原理實驗2——語法分析

此次試驗由於指導書的文法比較簡單,且沒有消除左遞迴(我懶),因此使用學長的文法,並加上了陣列判斷。

S -> func funcs
funcs -> func funcs
funcs -> $
func -> type IDN ( args ) func_body
type -> int
type -> short
type -> long
type -> char
type -> float
type -> double
type -> void
type -> unsigned type
args -> type IDN arg
args -> $
arg -> , type IDN arg
arg -> $
func_body -> ;
func_body -> block
block -> { define_stmts stmts }
define_stmts -> define_stmt define_stmts
define_stmts -> $
define_stmt -> type IDN init vars ;
init -> = expression
init -> [ INT10 ]
init -> $
vars -> , IDN init vars
vars -> $
stmts -> stmt stmts
stmts -> $
stmt -> assign_stmt
stmt -> jump_stmt
stmt -> iteration_stmt
stmt -> branch_stmt
assign_stmt -> expression ;
jump_stmt -> continue ;
jump_stmt -> break ;
jump_stmt -> return isnull_expr ;
iteration_stmt -> while ( logical_expression ) block_stmt
iteration_stmt -> for ( isnull_expr ; isnull_expr ; isnull_expr ) block_stmt
iteration_stmt -> do block_stmt while ( logical_expression ) ;
branch_stmt -> if ( logical_expression ) block_stmt result
result -> else block_stmt
result -> $
logical_expression -> ! expression bool_expression
logical_expression -> expression bool_expression
bool_expression -> lop expression bool_expression
bool_expression -> $
lop -> &&
lop -> ||
branch_stmt -> switch ( IDN ) { case_stmt case_stmts default_stmt }
case_stmts -> case_stmt case_stmts
case_stmts -> $
case_stmt -> case const : stmts
default_stmt -> default : stmts
block_stmt -> { stmts }
isnull_expr -> expression
isnull_expr -> $
expression -> value operation
operation -> compare_op value
operation -> equal_op value
operation -> $
compare_op -> >
compare_op -> >=
compare_op -> <
compare_op -> <=
compare_op -> ==
compare_op -> !=
equal_op -> =
equal_op -> +=
equal_op -> -=
equal_op -> *=
equal_op -> /=
equal_op -> %=
value -> item value'
value' -> + item value'
value' -> - item value'
value' -> $
item -> factor item'
item' -> * factor item'
item' -> / factor item'
item' -> % factor item'
item' -> $
factor -> ( value )
factor -> IDN call_func
factor -> const
call_func -> ( es )
call_func -> $
es -> isnull_expr isnull_es
isnull_es -> , isnull_expr isnull_es
isnull_es -> $
const -> num_const
const -> FLOAT
const -> CHAR
const -> STR
num_const -> INT10
num_const -> INT8
num_const -> INT16
//獲取First集
	public void getFirst(){
		//終結符全部求出first集
		ArrayList<String> first;
		//求出所有終結符的First集
		for (int i = 0; i < terminals.size(); i++) {
			first = new ArrayList<String>();
			first.add(terminals.get(i));
			firsts.put(terminals.get(i), first);
		}
		
		//給所有非終結符註冊一下
		for (int i = 0; i < nonterminals.size(); i++) {
			first = new ArrayList<String>();
			firsts.put(nonterminals.get(i), first);
		}
			
		boolean flag;
		while (true) {
			flag = true;
			String left;
			String right;
			String[] rights;
			for (int i = 0; i < productions.size(); i++) {
				//遍歷每一個產生式
				left = productions.get(i).returnLeft();
				rights = productions.get(i).returnRights();
				for (int j = 0; j < rights.length; j++) {
					//遍歷每個產生式右部的每個元素
					right = rights[j];
					//right是否存在,遇到空怎麼辦
					//如果right不為空
					if(!right.equals("$")) {
						for (int l = 0; l < firsts.get(right).size(); l++) {
							if(firsts.get(left).contains(firsts.get(right).get(l))){
								continue;
							}
							else {
								firsts.get(left).add(firsts.get(right).get(l));
								flag=false;
							}
						}
					}
					//如果右部可以為空
					if (isCanBeNull(right)) {
							continue;
					}
					else {
						break;
					}
				}
			}
			if (flag == true) {
				break;
			}				
		}
	//非終結符的first集
	}
	
	//判斷是否產生$
	public boolean isCanBeNull(String symbol) {
		String[] rights;
		for (int i = 0; i < productions.size(); i++) {
			//找到產生式
			if (productions.get(i).returnLeft().equals(symbol)) {
				rights = productions.get(i).returnRights();
				if (rights[0].equals("$")) {
					return true;
				}
			}
		}
		return false;
	}
//獲得Follow集
	public void getFollow() {
		//所有非終結符的follow集初始化一下
		ArrayList<String> follow;
		for (int i = 0; i < nonterminals.size(); i++) {
			follow = new ArrayList<String>();
			follows.put(nonterminals.get(i), follow);
		}
		//將#加入到follow(S)中
		follows.get("S").add("#");
		
		boolean flag;
		boolean fab;
		while (true) {
			flag = true;
			//迴圈,遍歷所有產生式
			for (int i = 0; i < productions.size(); i++) {
				String left;
				String right;
				String[] rights;
				rights = productions.get(i).returnRights();
				//遍歷產生式右部
				for (int j = 0; j < rights.length; j++) {
					right = rights[j];
						
					//非終結符
					if (nonterminals.contains(right)) {
						fab = true;
						for(int k = j+1; k < rights.length; k++) {
						    //查詢first集
							for(int v = 0; v < firsts.get(rights[k]).size(); v++) {
									//將後一個元素的first集加入到前一個元素的follow集中
									if(follows.get(right).contains(firsts.get(rights[k]).get(v))) {
										continue;
									}
									else {
										follows.get(right).add(firsts.get(rights[k]).get(v));
										flag=false;
									}
								}
								if (isCanBeNull(rights[k])) {
									continue;
								}
								else {
									fab = false;
									break;
								}
							}
						    //如果存在一個產生式A→αB,或存在產生式A→αBβ且FIRST(β) 包含ε,
						    //那麼 FOLLOW(A)中的所有符號都在FOLLOW(B)中
							if(fab) {
								left = productions.get(i).returnLeft();
								for (int p = 0; p < follows.get(left).size(); p++) {
									if (follows.get(right).contains(follows.get(left).get(p))) {
										continue;
									}
									else {
										follows.get(right).add(follows.get(left).get(p));
										flag = false;
									}
								}
							}
						}				
					}
				}
			    //全部處理後跳出迴圈
				if(flag==true){
					break;
				}	
			}			
		    //清除follow集中的#
		    String left;
		    for (int j = 0; j < nonterminals.size(); j++) {
			    left = nonterminals.get(j);
			    for (int v=0; v<follows.get(left).size(); v++) {
					if(follows.get(left).get(v).equals("#"))
						follows.get(left).remove(v);
			}
		}
	}
//獲取Select集 
	public void getSelect() {
		String left;
		String right;
		String[] rights;
		ArrayList<String> follow = new ArrayList<String>();
		ArrayList<String> first = new ArrayList<String>();
			
		for (int i = 0; i < productions.size(); i++) {
			left = productions.get(i).returnLeft();
			rights = productions.get(i).returnRights();
			if(rights[0].equals("$")) {
				// select(i) = follow(A)
				follow = follows.get(left);
				for (int j = 0; j < follow.size(); j++) {
					if(productions.get(i).select.contains(follow.get(j))){
						continue;
					}
					else {
						productions.get(i).select.add(follow.get(j));
					}
				}		
			}
			//如果文法G的第i個產生式為A→aβ,則定義
			//SELECT(i)={a}
			else {
				boolean flag = true;
				for (int j = 0; j < rights.length; j++) {
					right = rights[j];
					first = firsts.get(right);
					for (int v = 0; v < first.size(); v++) {
						if (productions.get(i).select.contains(first.get(v))) {
							continue;
						}
						else {
							productions.get(i).select.add(first.get(v));
						}
					}
					if(isCanBeNull(right)) {
						continue;
					}
					else {
						flag = false;
						break;
					}
				}
				//First集中有空
				if (flag) {
					follow = follows.get(left);
					for (int j = 0; j < follow.size(); j++) {
						if (productions.get(i).select.contains(follow.get(j))) {
							continue;
						}
						else {
							productions.get(i).select.add(follow.get(j));
						}
					}
				}
			}
		}		
	}
//語法分析
	public void Parsing() {
		//遍歷輸入緩衝區
		/*for(int i = 0; i < inputCache.size(); i++) {
			System.out.println(inputCache.get(i));
		}*/
		//初始符號壓入棧
		stack.add("S");
	    String right;
		String leftandinput;
		String process="";
		//當棧非空,輸入緩衝區存在
        while (stack.size()>0 && inputCache.size()>0 ) {
           //輸入緩衝區與推導符號串第一個字元相等的話,刪掉
			try {
				if(inputCache.get(0).equals(stack.get(stack.size()-1))) {
					inputCache.remove(0);
					stack.remove(stack.size()-1);
					continue;
				}
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			
			//匹配字元
			leftandinput = stack.get(stack.size()-1)+"-"+inputCache.get(0);
			//能夠找到匹配的
			if((right=predictMap.get(leftandinput))!=null) {
                //輸出產生式和推導過程
				process = "";
				for (int i = stack.size()-1; i>-1; i--) {
					process = process + stack.get(i)+" ";
				}
                //輸出
				DefaultTableModel tableModel = (DefaultTableModel) jtable4.getModel();
                tableModel.addRow(new Object[] {stack.get(stack.size()-1)+" -> "+right, process});
                jtable4.invalidate();
				//刪掉產生的字元,壓入堆疊
				stack.remove(stack.size()-1);
				if(right.equals("$")) {
					//只彈不壓
				}
				//壓入後序字元
				else {
					String[] arg = right.split(" ");
					for(int i = arg.length-1; i>-1; i--) {
						//反向壓入堆疊
						stack.add(arg[i]);
					}
				}				
			}
			//否則的話報錯
			else {
				//重新書寫process
				process="";
				for (int i = stack.size()-1; i>-1; i--) {
					process = process + stack.get(i)+ " ";
				}
				//tbmodel_lex_result.addRow(new String[]{process, "ERROR!  無法識別的字元"+input_cache.get(0)+"產生式"+leftandinput});
				DefaultTableModel tableModel = (DefaultTableModel) jtable2.getModel();
                tableModel.addRow(new Object[] { "無法識別的字元:"+ inputCache.get(0),"產生式:"+leftandinput});
                jtable4.invalidate();
				inputCache.remove(0);
			}
		}
	}