項目的完整代碼在 C2j-Compilerjava
這個系列算做爲我本身在學習寫一個編譯器的過程的一些記錄,算法之類的都沒有記錄原理性的東西,想知道原理的在龍書裏都寫得很是清楚,可是我本身一開始是不怎麼看得下來,到如今都尚未完整的看完,它像是一本給已經有基礎的人寫的書。git
在parse包裏一共有8個文件,就是語法分析階段寫的全部東西啦github
項目的完整代碼在 C2j-Compiler算法
在上一篇說了,居然要驗證句子正確與否,天然就須要語法,也就是給出相應的語法推導式數據結構
全部語法的初始化工做都在SyntaxProductionInit裏完成工具
///EXT_DECL_LIST ->EXT_DECL_LIST COMMA EXT_DECL right = getProductionRight(new int[]{Token.EXT_DECL_LIST.ordinal(), Token.COMMA.ordinal(), Token.EXT_DECL.ordinal()}); production = new Production(productionNum, Token.EXT_DECL_LIST.ordinal(), 0, right); productionNum++; addProduction(production, false);
好比下面這個就對應C語言的變量聲明語句的推導式,PROGRAM是整個推導式的開始符號,EXT_DEF_LIST就是聲明列表,這裏的EXT_DEF_LIST -> EXT_DEF_LIST EXT_DEF須要注意一下是左遞歸狀況,LR語法是能夠處理的,關於這個能夠看以前的博文。學習
好比EXT_DECL_LIST -> EXT_DECL -> VAR_DECL 多個變量名稱聲明能夠推導是一個變量名稱聲明或者多個變量名稱聲明 + 逗號 + 變量名稱聲明ui
VAR_DECL 則能夠是一個標識符或者一個多重指針this
即一個從葉子節點不斷的推導,讀入終結符,最後推導到開始符號,且輸入流也已經讀完指針
/* * PROGRAM -> EXT_DEF_LIST * * EXT_DEF_LIST -> EXT_DEF_LIST EXT_DEF * * EXT_DEF -> OPT_SPECIFIERS EXT_DECL_LIST SEMI * | OPT_SPECIFIERS SEMI * * * EXT_DECL_LIST -> EXT_DECL * | EXT_DECL_LIST COMMA EXT_DECL * * EXT_DECL -> VAR_DECL * * OPT_SPECIFIERS -> CLASS TTYPE * | TTYPE * | SPECIFIERS * | EMPTY? * * SPECIFIERS -> TYPE_OR_CLASS * | SPECIFIERS TYPE_OR_CLASS * * * TYPE_OR_CLASS -> TYPE_SPECIFIER * | CLASS * * TYPE_SPECIFIER -> TYPE * * NEW_NAME -> NAME * * NAME_NT -> NAME * * VAR_DECL -> | NEW_NAME * * | START VAR_DECL * */
在語法推導式初始化的過程一共要構建三個數據結構
private HashMap<Integer, ArrayList<Production>> productionMap = new HashMap<>(); private HashMap<Integer, Symbols> symbolMap = new HashMap<>(); private ArrayList<Symbols> symbolArray = new ArrayList<>();
Symbol相似Production,也是用來表示產生式的,可是稍有點不一樣,也還包括終結符,在後面也會有不一樣的做用,
//Symbols public int value; public ArrayList<int[]> productions; public ArrayList<Integer> firstSet = new ArrayList<>(); public boolean isNullable;
若是一個非終結符,它能夠推導出空集,那麼這樣的非終結符咱們稱之爲nullable的非終結符
在上一篇裏說到驗證語法的過程就是在一堆對應語法產生式中推導出答案,Production類就是來表示一個產生式
private int dotPos = 0; private int left; private ArrayList<Integer> right; private ArrayList<Integer> lookAhead = new ArrayList<>(); private int productionNum = -1; public Production(int productionNum, int left, int dot, ArrayList<Integer> right) { this.left = left; this.right = right; this.productionNum = productionNum; lookAhead.add(Token.SEMI.ordinal()); if (dot >= right.size()) { dot = right.size(); } this.dotPos = dot; }
這一篇主要介紹了幾個數據結構,這幾個數據結構都是以後構建有限狀態自動機的基礎。原本想把狀態機的構建也寫在這一篇,可是若是加上去以後,篇幅太長,加一部分會感受不成模塊,有點分散,因此自動機的構建就寫在下一篇。
另外個人github博客:https://dejavudwh.cn/