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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

【HUST】网安|编译原理实验|实验四攻略

發布時間:2025/5/22 编程问答 16 如意码农
生活随笔 收集整理的這篇文章主要介紹了 【HUST】网安|编译原理实验|实验四攻略 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【實驗代碼及報告地址:Gitee傳送門】(已關閉傳送大門,原因是抄襲過多,如需參考,請直接看博客,雖然下一屆內容會變了)

不擅長寫報告昂,很多地方能省全省了。
助力來年編譯原理加大難度!(hhh)

MiniC語法分析及中間代碼生成

我根據我的實驗報告重置了攻略。

貼個完成時間。

文章目錄

  • MiniC語法分析及中間代碼生成
    • 實驗內容
    • 實驗過程
      • LLVM IR初識
      • LLVM IR API
      • 語義分析與中間代碼生成(一)
        • 難點
        • 調試技巧
        • Quick Start
        • 正式開始
          • 1. astnode.cpp需要修改的函數
          • 2. astnode.h需要修改的函數
          • 3. 一個分析過程
          • 4. 舉幾個典型的例子
            • 4.1. 各種List
            • 4.2 錯誤判斷
      • 語義分析與中間代碼生成(二)
        • 1. astnode.cpp需要修改的函數
        • 2. 難點
          • 2.1 一些函數
          • 2.2 NArgs如何解析
        • 3. 錯誤判斷
      • 語義分析與中間代碼生成(三)
        • 1. astnode.cpp需要修改的函數
        • 2. astnode.h需要修改的函數
        • 3. 分析思路
          • 3.1 if-else結構
          • 3.2 變量的作用域問題
          • 3.3 或運算||的解析

實驗內容

將Mini-C源程序,手工翻譯或用LLVM API翻譯成LLVM IR(一種中間語言),并完成語法檢查。

實驗過程

LLVM IR初識

結合給出的例子,認識并熟悉LLVM IR的語法。
主要涉及了align/alloca/store/load/call/icmp/br等。【可以自行結合代碼展開說說】
主要是根據Mini-C語言翻譯,有兩個地方對我造成了困擾:【相信每個人困擾的點不一樣,自圓其說即可】

  1. task2中我一開始將putchar寫進了判斷體中,導致狀態不夠用,不得不移出。
  2. task2中涉及標號label。不像asm,llvm的標號上面不能沒有跳轉語句直接順序執行,它必須添加br label %8跳轉。

LLVM IR API

熟悉并使用LLVM IR API,主要涉及了llvm::IRBuilderBase類的API,還有一些Constant、BasicBlock、Type類的API。【可以自行結合代碼展開說說】
難點:【相信每個人的難點不一樣,自圓其說即可】

  1. getchar是無參數函數,而builder->CreateCall需要接受1到3個參數,直接傳遞空vector行不通。
    正解:builder->CreateCall(callgetfunc);
  2. task2中if-then-else涉及3個基本塊,樣例中是if-then,只涉及兩個模塊。而且并不好理解。
    正解:根據官網的IF-THEN-ELSE寫,它的解釋很好。MyFirstLanguageFrontend/LangImpl05.html#code-generation-for-if-then-else。
  3. 一些個人遇到的問題:在進入第三個基本塊我沒有f->getBasicBlockList().push_back(MergeBB);,因為我以為到結尾了可以直接順序執行下去,犯了和關卡1相似的錯誤。沒有寫這一句時,報錯會一直提示then:錯誤,導致我一直沒定位到真正的錯誤位置。

語義分析與中間代碼生成(一)

【因為實在很長,所以實驗報告里我沒有寫過程,只寫了難點。不建議大家這樣做,因為每個人的難點都是不一樣的
【如果沒話寫,可以著重寫一下“錯誤判斷”部分】

難點
  1. 咋聲明變量?(答:抄NExtDefFunDec::codegen的arg聲明)
  2. 我怎么知道一個函數里需要解析哪些參數、哪些參數是需要被特殊處理的?(答:看上面的分析,對照parser.y和astnode.h)
  3. 咋把分析結果存到變量里面?(答:實驗二里做過,不記得的話,函數聲明如是:builder->CreateStore(Value, alloca);)
  4. 咋分析加?(答:實驗二有提示。不記得的話,函數聲明如是:builder->CreateAdd(left, right, "add");)
  5. abort怎么炸了,返回之后就提示我core dump
    答:請檢查是不是把nullptr輸入到一個函數中了,舉個簡單的例子(摘自NAssignment::codegen函數):
    再檢查是否未初始化指針就直接用了,舉個retValue沒初始化就返回的例子:
    Value* retValue; if(false) retValue=nullptr; return retValue;
  6. module找不到,它什么意思?(答:字面意思,找不到就找不到。執行fundec成功了就能找到main)
  7. 為了實現功能,我參考函數定義的部分,即ExtDefFunc::codegen,添加了一個繼承屬性type,如函數NDef
調試技巧
  1. std::cout調試,定位出錯的位置。
  2. cat tokens.txt調試,通過閱讀生成的中間代碼,判斷語義分析的哪一步出了問題,或者根本沒解析出來。
  3. vim ./task1case/1.in修改樣例調試。當你覺得是某個邏輯寫得很有問題,但是樣例太長了,中間代碼眼花繚亂,就直接修改樣例
  4. p->parser();輸出語法樹。將main.cpp中的p->parser();注釋掉,再編譯運行樣例,能看到每個樣例完整的語法樹。建議順著語法樹的解析順序,逐個填充codegen,每填充完一個,就去編譯運行試試
Quick Start

使用頭歌命令行調試

打開頭歌,打開命令行,進入對應的代碼倉庫。

cd /data/workspace/myshixun/llvmexp3

檢查一下當前目錄下的文件。

ls

應該能看到judge_taskx.sh文件,以第三關為例,看一下judge_task1.sh的內容。
具體內容就不貼了,總之是這樣用的:

  1. 先編譯(make)成./minic文件,它是一個可執行的文件,用來生成中間代碼LLVM IR
make

中間代碼LLVM IR:類似于br i1 %shandian7, label %then8, label %ifcont10這種東西。

  1. 在代碼倉庫下有測試樣例,以第3關為例,對應task1case
  2. 用minic編譯一個樣例,并將中間代碼(或報錯)存儲至tokens.txt
./minic ./task1case/0.in > tokens.txt
  1. 如果生成中間代碼成功了,cat tokens.txt看一下輸出(你在cpp里寫的std::cout、輸出的報錯Error信息也會在這個txt里)。
  2. 如果這是一個正確的中間代碼,而且它需要編譯運行,并接收一定的輸入,請這樣:
echo "你要給程序輸入的值(就是stdin)" > tmp
lli tokens.txt < tmp
正式開始
1. astnode.cpp需要修改的函數

正好十個。


NIdentifier蠻麻煩的,如下:

注:寫第三題的時候可以亂來,寫第五題就得考慮作用域了。

2. astnode.h需要修改的函數

寫第五關的時候發現,VarDec::codegen返回值設為AllocaInst *才行。

3. 一個分析過程

4. 舉幾個典型的例子
4.1. 各種List

直到第五題才能發現的錯誤:注意一個特殊的,NDec::codegen,根據Dec: VarDec | VarDec ASSIGNOP Exp,它的Exp是要用來給VarDec的alloca賦值的,不要只是單純地解析它然后就不管了喔。

4.2 錯誤判斷

++ 錯誤類型 1:變量在使用時未經定義。
思路就是調用的時候找找curNamedValues里有沒有。(摘自NAssignment::codegen函數)

++ 錯誤類型 2:函數在調用時未經定義。
思路就是調用的時候找找theModule里有沒有。(摘自NMethodCall::codegen函數)

++ 錯誤類型 3:變量出現重復定義。
思路就是聲明的時候找找curNamedValues里有沒有。(摘自NExtDefFunDec::codegen函數)

語義分析與中間代碼生成(二)

有了第3關的基礎,第四關明顯簡單了許多。
【實驗報告我依舊只寫了難點,注意口語書面化】
【如果沒話寫,可以著重寫一下“錯誤判斷”部分】

1. astnode.cpp需要修改的函數

只有四個,非常快樂。

注:由于第3關的時候,我順手把NFloat::codegen之類的全部寫好了,所以這里沒有特意標注。
好像有同學找不到Float的取值函數,如下:

2. 難點
2.1 一些函數

出現了很多老師沒給樣例的函數。
CreateSubgetType()方法getReturnType()

參考classllvm_1_1IRBuilderBase.html找到CreateSub函數,
參考classllvm_1_1Function.html得知getReturnType(),
參考classllvm_1_1Value.html得知Value有自己的getType()函數。

我是如何查找的?【經驗分享】
例如,我想獲得auto *類型的變量retValue的type。

  1. 很自然地寫出了retValue.type的代碼,然后報錯,說retValue是個指針,建議用->來訪問它的成員
  2. 于是訂正為retValue->type,再次報錯,說class llvm::Value *沒有type成員
  3. 那么llvm::Value有什么呢?搜索llvm::Value,跳轉官網,找到getType()函數。
  4. 訂正為retValue->getType(),成功。
2.2 NArgs如何解析

引言:

  1. 明顯,NArgs對應多個參數,但是它的codegen()只返回一個Value*,這不合適啊!
  2. 難道參考List函數的解析方式,修改NArgs::codegen(),依次展開?不行啊,每個返回值都要用,依次展開沒辦法返回回去啊!

正解:參考NFunDec::funcodegen中對NVarList的解析即可。

std::vector<Type *> argsTypes;
std::vector<std::string> argNames;
for (NVarList *item = arguments; item; item = item->nVarList) {
auto tmp = item->nParamDec.getType();
argNames.push_back(tmp.first);
argsTypes.push_back(tmp.second);
}

注意,exp解析得到的Value*的類型,直接用getType就可以取到了,很好寫,不要想太復雜了。

3. 錯誤判斷

++ 錯誤類型 4:函數出現重復定義(即同樣的函數名被多次定義)。

這個老師寫好了。在NFunDec::funcodegen里。

++ 錯誤類型 5:賦值號兩邊的表達式類型不匹配。

++ 錯誤類型 6:賦值號左邊出現一個只有右值的表達式。

++ 錯誤類型 7:return 語句的返回類型與函數定義的返回類型不匹配。

++ 銷誤類型 8:函數調用時實參與形參的數目或類型不匹配。

沒什么好說的叭,能寫出第三題沒理由寫不出錯誤判斷。

語義分析與中間代碼生成(三)

【報告只寫了分析思路部分】

1. astnode.cpp需要修改的函數


主要是因為我前面偷懶偷得比較多,所以改動也很多。

2. astnode.h需要修改的函數


這個地方真的是,我沒太動腦,返回值設錯了一通亂解析。

3. 分析思路

首先看樣例:

這個題沒有涉及任何錯誤判斷,需要完成的是算術運算+-*/和邏輯符號||,以及三個結構:if/ifelse/while

3.1 if-else結構

其中ifelse結構直接參考實驗2的,對應的是NIfElseStmt::codegen,應該沒什么好說的吧。寫了這個之后樣例1就都過了。

樣例1:

int read(){
int a=0;
a = getchar();
return a - 48;
}
int main(){
int m,n;
int i=48;
m = read();
n = read();
if(m == n ){
putchar(i);
}else{
i = i + 1;
putchar(i);
}
i = i + 1;
putchar(i);
return 0;
}
3.2 變量的作用域問題

因為一些因素,我沒有用樣例分析,而是用了更復雜的深層結構,分析以及偽代碼如下。

3.3 或運算||的解析

提示:用基本塊。多看看生成的中間代碼和預期的區別。

貼一下報錯,這個報錯是因為while循環過多棧炸了,可能是因為條件判斷寫得有問題,心態穩住。

總結

以上是生活随笔為你收集整理的【HUST】网安|编译原理实验|实验四攻略的全部內容,希望文章能夠幫你解決所遇到的問題。

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