日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

从零写一个编译器(三):语法分析之几个基础数据结构

發(fā)布時間:2023/12/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 从零写一个编译器(三):语法分析之几个基础数据结构 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

項目的完整代碼在 C2j-Compiler

寫在前面

這個系列算作為我自己在學習寫一個編譯器的過程的一些記錄,算法之類的都沒有記錄原理性的東西,想知道原理的在龍書里都寫得非常清楚,但是我自己一開始是不怎么看得下來,到現在都還沒有完整的看完,它像是一本給已經有基礎的人寫的書。

在parse包里一共有8個文件,就是語法分析階段寫的所有東西啦

  • Symbols.java
  • Production.java
  • SyntaxProductionInit.java
  • FirstSetBuilder.java
  • ProductionManager.java
  • ProductionsStateNode.java
  • StateNodeManager.java
  • LRStateTableParser.java

項目的完整代碼在 C2j-Compiler

SyntaxProductionInit 語法初始化

在上一篇說了,竟然要驗證句子正確與否,自然就需要語法,也就是給出相應的語法推導式

所有語法的初始化工作都在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 多個變量名稱聲明可以推導是一個變量名稱聲明或者多個變量名稱聲明 + 逗號 + 變量名稱聲明

VAR_DECL 則可以是一個標識符或者一個多重指針

即一個從葉子節(jié)點不斷的推導,讀入終結符,最后推導到開始符號,且輸入流也已經讀完

/* * 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<>();
  • ProductionMap的key就是推導式的左邊,value即對應的一個或多個產生式
  • SymbolMap類似ProductionMap,key是推導式的左邊,value是一個或者多個產生式的右邊

Symbol類似Production,也是用來表示產生式的,但是稍有點不同,也還包括終結符,在后面也會有不同的作用,

//Symbols public int value; public ArrayList<int[]> productions; public ArrayList<Integer> firstSet = new ArrayList<>(); public boolean isNullable;

如果一個非終結符,它可以推導出空集,那么這樣的非終結符我們稱之為nullable的非終結符

  • symbolArray存儲著每一個Symbols對象,在后面也會有不一樣的作用

Production 產生式類

在上一篇里說到驗證語法的過程就是在一堆對應語法產生式中推導出答案,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; }
  • left和right就是產生式的左邊和右邊,都是用之前Token的值來表示
  • lookahead向前看集合,后面用到再提
  • dos就像構造這個自動機的輔助工具,之后用到詳細說
  • productionNum是這個產生式對應編號,這個編號是在初始化語法的時候給定的
  • 小結

    這一篇主要介紹了幾個數據結構,這幾個數據結構都是之后構建有限狀態(tài)自動機的基礎。本來想把狀態(tài)機的構建也寫在這一篇,但是如果加上去之后,篇幅太長,加一部分會感覺不成模塊,有點分散,所以自動機的構建就寫在下一篇。

    另外我的github博客:https://dejavudwh.cn/

    轉載于:https://www.cnblogs.com/secoding/p/11367530.html

    總結

    以上是生活随笔為你收集整理的从零写一个编译器(三):语法分析之几个基础数据结构的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。