編譯原理作業(第一次)-完成retinf.c(閹割版)

来源:https://www.cnblogs.com/lugf/archive/2019/03/06/10486744.html
-Advertisement-
Play Games

首先,作業要求概括如下: 根據首碼表達式文法,實現statements() 和expression() 兩個函數。 並且要求使得語義分析在完成分析首碼表達式並輸出中間代碼的同時,也能夠將首碼表達式翻譯為中綴表達式, 且要求翻譯後的中綴表達式中儘可能少用括弧。 舉例如下: 輸入"+ a * b c;" ...


首先,作業要求概括如下:

根據首碼表達式文法,實現statements() 和expression() 兩個函數。

並且要求使得語義分析在完成分析首碼表達式並輸出中間代碼的同時,也能夠將首碼表達式翻譯為中綴表達式, 且要求翻譯後的中綴表達式中儘可能少用括弧

 

1 statements -> expression SEMI
2                 |  expression SEMI statements
3    
4 expression -> PLUS expression expression
5                |  MINUS expression expression
6                |  TIMES expression expression
7                |  DIVISION expression expression
8                |  NUM_OR_ID    

 

舉例如下: 輸入"+ a * b c;"時,應輸出中綴式為" a + b * c", 而不是"a + (b * c)"或"(a) + (b * c)"等。

最後測試效果如下:

 

 

其中未實現河流命名演算法故為閹割版。為方便讀者閱讀並理解後自行更改,這裡只提供初版(low版),其代碼如下(DDL後會更新):

 

  1 //retinf.c
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <stdlib.h>
  5 #include <stdbool.h>
  6 
  7 #include "lex.h"
  8 
  9 char err_id[] = "error";
 10 char * midexp;
 11 extern char * yytext;
 12 
 13 struct YYLVAL {
 14     int last_op;  /* last operation of expression
 15          for elimination of redundant parentheses */
 16 
 17     char * val;  /* 記錄表達式中間臨時變數 */
 18     char * expr; /* 記錄表達式尾碼式 */
 19 };
 20 
 21 typedef struct YYLVAL Yylval;
 22 
 23 Yylval * expression(void);
 24 
 25 char *newname(void); /* 在name.c中定義 */
 26 
 27 extern void freename(char *name);
 28 
 29 void statements(void) {
 30     Yylval *temp;
 31     printf("Please input an infix expression and ending with \";\"\n");
 32     while (!match(EOI)) {
 33 
 34         temp = expression();
 35 
 36         printf("The Expression Is %s\n", temp->expr);
 37         freename(temp->val);
 38 
 39         free(temp->expr);
 40         free(temp);
 41         if (match(SEMI)) {
 42             printf("Please input an infix expression and ending with \";\"\n");
 43             advance();
 44 
 45         }
 46         else {
 47             fprintf(stderr, "%d: Inserting missing semicolon\n", yylineno);
 48         }
 49     }
 50 }
 51 
 52 Yylval * expression(void) {
 53     Yylval *tempToReturn;
 54     tempToReturn = (Yylval *)malloc(sizeof(Yylval));
 55 
 56     Yylval *temp0, *temp1;
 57     while (match(PLUS) || match(MINUS) || match(TIMES) || match(DIVISION)) {
 58 
 59         char op = yytext[0];
 60         advance();
 61         temp0 = expression();
 62 
 63         temp1 = expression();
 64         
 65         bool tempToReturnIsPro = op == '*' || op == '/';
 66         bool temp0IsLower = temp0->last_op == PLUS || temp0->last_op == MINUS;
 67         bool temp1IsLower = temp1->last_op == PLUS || temp1->last_op == MINUS;
 68 
 69 
 70         if (tempToReturnIsPro) {
 71             if (temp0IsLower && temp1IsLower) {
 72                 tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + 12);
 73                 sprintf(tempToReturn->expr, "( %s ) %c ( %s )", 
 74                     temp0->expr, op, temp1->expr);
 75             }
 76             else if (temp0IsLower) {
 77                 tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + 8);
 78                 sprintf(tempToReturn->expr, "( %s ) %c %s",
 79                     temp0->expr, op, temp1->expr);
 80             }
 81             else if (temp1IsLower) {
 82                 tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + 8);
 83                 sprintf(tempToReturn->expr, "%s %c ( %s )",
 84                     temp0->expr, op, temp1->expr);
 85             }
 86             else {
 87                 tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + 4);
 88                 sprintf(tempToReturn->expr,  "%s %c %s",
 89                     temp0->expr, op, temp1->expr);
 90             }
 91         }
 92         else {
 93             tempToReturn->expr = (char*)malloc(strlen(temp0->expr) + strlen(temp1->expr) + 4);
 94             sprintf(tempToReturn->expr, "%s %c %s",
 95                 temp0->expr, op, temp1->expr);
 96         }
 97         switch (op)
 98         {
 99         case '+':tempToReturn->last_op = PLUS; break;
100         case '-':tempToReturn->last_op = MINUS; break;
101         case '*':tempToReturn->last_op = TIMES; break;
102         case '/':tempToReturn->last_op = DIVISION; break;
103         default:
104             break;
105         }
106 
107         printf("    %s %c= %s\n", temp0->val, op, temp1->val);
108         freename(temp1->val);
109         tempToReturn->val = temp0->val;
110         return tempToReturn;
111 
112     }
113 
114     if (match(NUM_OR_ID)) {
115         printf("    %s = %0.*s\n", tempToReturn->val = newname(), yyleng, yytext);
116         tempToReturn->expr = (char*)malloc(yyleng + 1);
117         strncpy(tempToReturn->expr, yytext, yyleng);
118         advance();
119         tempToReturn->last_op = TIMES;
120         return tempToReturn;
121     }
122     else if (match(SEMI)){
123         printf("111");
124         return;    
125     }
126     else {
127         tempToReturn->val = newname();
128         advance();
129         fprintf(stderr, "%d: Number or identifier expected\n", yylineno);
130         return;
131     }
132 }

 

另:

 

1 /*main.c XL分析器 */
2 
3 main()
4 {
5     statements();
6 }

 

 1 /*lex.c     XL分析器 */
 2 
 3 
 4 #include "lex.h"
 5 #include <stdio.h>
 6 #include <ctype.h>
 7 
 8 char       *yytext = "";  /* 當前詞形,註意由於是直接指向
 9                    行緩衝區input_buffer,因此不是以'\0'結尾,
10                    因此使用時要小心, 設初值為0, 表示緩衝區為空,
11                    需要重新讀行 */
12 int        yyleng = 0;   /* 詞形的長度     */
13 int        yylineno = 0;   /* 輸入的行號    */
14 
15 lex()
16 {
17     static char input_buffer[128];
18     char        *current;
19 
20     current = yytext + yyleng;      /* 跳過以讀過的詞形 */
21 
22     while (1) {                  /* 讀下一個詞形     */
23         while (!*current) {
24             /* 如果當前緩衝區已讀完,重新從鍵盤讀入新的一行.
25            並且跳過空格
26             */
27 
28             current = input_buffer;
29             /* 如果讀行有誤,返回 EOI */
30             if (!fgets(input_buffer, 127, stdin)) {
31                 *current = '\0';
32                 return EOI;
33             }
34 
35             ++yylineno;
36 
37             while (isspace(*current))
38                 ++current;
39         }
40 
41         for (; *current; ++current) {
42             /* Get the next token */
43 
44             yytext = current;
45             yyleng = 1;
46 
47             /* 返回不同的辭彙代碼 */
48             switch (*current) {
49             case ';': return SEMI;
50             case '+': return PLUS;
51             case '-': return MINUS;
52             case '/': return DIVISION;
53             case '*': return TIMES;
54             case '(': return LP;
55             case ')': return RP;
56 
57             case '\n':
58             case '\t':
59             case ' ': break;
60 
61             default:
62                 if (!isalnum(*current))
63                     fprintf(stderr, "Ignoring illegal input <%c>\n", *current);
64                 else {
65                     while (isalnum(*current))
66                         ++current;
67 
68                     yyleng = current - yytext;
69                     return NUM_OR_ID;
70                 }
71 
72                 break;
73             }
74         }
75     }
76 }
77 
78 static int Lookahead = -1;      /* 向前查看的辭彙,設初值為-1
79                    表示第一次調用match函數時
80                    必須要讀取一個辭彙 */
81 
82 int match(int token)
83 {
84     /* 判斷token是否和當前向前查看的辭彙相同. */
85 
86     if (Lookahead == -1)
87         Lookahead = lex();
88 
89     return token == Lookahead;
90 }
91 
92 void advance()
93 {
94     /* 向前都一個辭彙 */
95     Lookahead = lex();
96 }

 

 1 /* lex.h      XL分析器*/
 2 #define EOI           0        /*  end of input                */
 3 #define SEMI          1        /*       ;                      */
 4 #define PLUS          2        /*       +                      */
 5 #define TIMES         3        /*       *                      */
 6 #define LP            4        /*       (                      */
 7 #define RP            5        /*       )                      */
 8 #define NUM_OR_ID     6        /* decimal number or identifier */
 9 #define MINUS         7
10 #define DIVISION      8
11 extern char *yytext;        /* in lex.c                     */
12 extern int  yyleng;
13 extern int  yylineno;

 

/*name.c XL分析器 */

#include <stdio.h>

char  *Names[] = { "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
           "t8", "t9", "t10", "t11", "t12", "t13", "t14", "t15" };

char  **Namep = Names;

extern int yylineno;

char  *newname()
{
    if (Namep >= &Names[sizeof(Names) / sizeof(*Names)]) {
        fprintf(stderr, "%d: Expression too complex\n", yylineno);
        exit(1);
    }

    return(*Namep++);
}

freename(s)
char    *s;
{
    if (Namep > Names)
        *--Namep = s;
    else
        fprintf(stderr, "%d: (Internal error) Name stack underflow\n",
            yylineno);
}

 

具體生成方法不一,使用makefile方式最好。

這裡只提供基本的gcc 方式(部分linux中沒有自帶,自行安裝)。

 

 1 gcc -c lex.c
 2 
 3 gcc -c retinf.c
 4 
 5 gcc -c name.c
 6 
 7 gcc -c main.c
 8 
 9 gcc -o namebalabala lex.o retinf.o name.o main.o
10 //gcc -o namebalabala *.o
11 
12 ./namebalabala

 

註意,如果非要在win下vs中直接運行此程式的話,你會發現:

 

 

很正常,這是因為執行的標準不一樣。為了防止溢出,微軟要求用sprintf_s()strncpy_s() 函數(其中_s代表safe)代替sprintf()strncpy()

也就多了一個目標串長度的參數,百度一下就好了。

 

但實際過程中應該還是會有一些問題的,特別是地址方面的。這個時候就自己debug吧~

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在可預見的未來, 高考仍是最重要的也最有社會影響力的人才選拔機制. 很久沒有關註, 最近得知高考自選科目中開始增加了編程一項(見 "如何評價2017浙江高考七選三科目中包含技術?" ). 雖然個人對編程是否應該進入高考仍有保留看法, 但至少全民(都應該可以)編程這一趨勢已經很明顯了. 這應該是中文編 ...
  • 筆者環境 centos7 python3 pytesseract只是tesseract-ocr的一種實現介面。所以要先安裝tesseract-ocr(大名鼎鼎的開源的OCR識別引擎)。 依賴安裝 安裝依賴的leptonica庫 安裝tesseract-ocr 安裝語言包: 安裝pytesseract ...
  • Maven 有一個生命周期,當你運行 mvn install 的時候被調用。這條命令告訴 Maven 執行一系列的有序的步驟,直到到達你指定的生命周期。遍歷生命周期旅途中的一個影響就是,Maven 運行了許多預設的插件目標,這些目標完成了像編譯和創建一個 JAR 文件這樣的工作。 一個jar包,會有 ...
  • 為什麼要談這個topic? 實踐中,質量保障體系的建設,主要針對兩個目標: 一是不斷提高目標業務測試覆蓋率,保障面向客戶的產品質量;二就是儘可能的提高人效,增強迭代效率。而構建全鏈路質量卡點就是整個體系建設的核心手段。筆者用下圖來描述這整個鏈路: 可以看到,雖然保障業務迭代的方向性正確排在最前面,但 ...
  • 真的是忙頭暈了,學業、ACM打題、班級活動、自學新東西,哇這充實的大學~ L1-007 念數字 輸入一個整數,輸出每個數字對應的拼音。當整數為負數時,先輸出fu字。十個數字對應的拼音如下: 0: ling 1: yi 2: er 3: san 4: si 5: wu 6: liu 7: qi 8: ...
  • 首先創建一個test類: 在main方法里寫上如下代碼: 在工程目錄下新建一個generator.xml文件: 最後的table標簽是自己資料庫中表的名字;資料庫的連接信息需要自己修改 執行test類就會自動生成自己以上設置table標簽中數據中表的對應的實體類,dao層介面以及對應的mapper映 ...
  • 可變對象與不可變對象 要理解深拷貝和淺拷貝,首先要理解可變對象和不可變對象。 不可變對象:該對象所指向的記憶體中的值不能被改變,修改對象的值時,由於其指向的值不能被改變,因此實際上是在記憶體中重新開闢一個地址用來存儲新的值,然後將對象指向這個新值。本質上是兩個對象,賦值前後對象id發生了變化。pytho ...
  • 這篇博客記錄@InitBinder怎麼起作用、起什麼作用? 首先,該註解被解析的時機,是該匹配Controller的請求執行映射的方法之前; 同時 @InitBinder標註的方法執行是多次的,一次請求來就執行一次。 當某個Controller上的第一次請求由SpringMvc前端控制器匹配到該Co ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...