1. 程式人生 > >Python 實現的 C 語言 詞法分析器

Python 實現的 C 語言 詞法分析器

這個學期上了編譯原理課,真的是超難。。。
這門課難到,全院老師只有我們老師他一個人會教編譯原理,哈哈哈哈

這門課這個學期有兩個實驗,一個是寫詞法分析器,一個是寫語法分析器

這裡的詞法分析器是用 Python 寫。Python 是剛自學的,所以使用上應該有很多的問題,但不得不說這真的是一門很先進的語言,使用起來相當的輕鬆,更符合人類的自然語言和思維習慣。

C語言編譯程式的詞法分析部分實現。從左到右掃描每行該語言源程式的符號,拼成單詞,換成統一的內部表示(token)送給語法分析程式。為了簡化程式的編寫,要求如下:
1. 數字僅整數或浮點數。
2. 空白符僅僅是空格、回車符\n、製表符\t。
3. 程式碼是自由格式。
4. 註釋應放在花括號或者/* */或者 // 之內,並且不允許巢狀
5. 可識別常用關鍵字

詞法分析建議:
1) 記號的二元式形式中種類採用列舉方法定義;其中保留字和特殊字元是每個都一個種類,標示符自己是一類,數字是一類;單詞的屬性值就是表示的字串值。
2) 詞法分析的具體功能實現是一個函式GetToken(),每次呼叫都對剩餘的字串分析得到一個單詞或記號識別其種類,收集該記號的符號串屬性,當識別一個單詞完畢,採用返回值的形式返回符號的種類,同時採用程式變數的形式提供當前識別出記號的屬性值。
3)標示符和保留字的詞法構成相同,為了更好的實現,把語言的保留字建立一個表格儲存,這樣可以把保留字的識別放在標示符之後,用識別出的標示符對比該表格,如果在該表格中則是保留字,否則是一般標示符。

詞法分析的過程可如下描述:

測試
測試該設計詞法分析器。
輸入與輸出形式:
例如讀取下述程式碼構成的C源程式檔案。

#include <studio.h>
int main(int argc, char const *argv[])
{
    char *str = "String123";
    /**
    printf("NULL\n");
    */  

    int floatnum = 123.4.56;
    // If是語法錯誤,不做詞法錯誤處理
    If(6.4ab <= 3E-1){   
        printf("Yes\n "
);} return 0; }

輸出結果到一個檔案中,結果類似如下:

line:1 <#,SEP>
line:1 <include,ID>
line:1 <<,OP>
line:1 <studio,ID>
line:1 <.,OP>
line:1 <h,ID>
line:1 <>,OP>
line:2 <int,KEY>
line:2 <main,ID>
line:2 <(,SEP>
line:2 <int,KEY>
line:2 <argc,ID>
line:2 <,,SEP>
line:2 <char,KEY>
line:2 <const,KEY>
line:2 <*,OP>
line:2 <argv,ID>
... 

大致上是把這個詞法分析器完成了,但其實知道里面或多或少還有一些問題,但實在懶得改進了,有需要的自己再研究吧。

放核心程式碼:

def main():
    global ws
    cflag = 0  # 控制多行註釋
    oflag = 0
    op_first = ''
    line = read_file('/Users/Desktop/test.c')
    # 行號
    line_num = 0
    # 多行註釋起始行號
    line_comment_start = 0
    comment_start1 = '//'
    comment_start2 = '/*'
    comment_end = '*/'

    for i in line:
        # 去除空白行
        if len(i) < 1:
            line_num = line_num + 1
            continue
        else:
            #  處理註釋行
            if cflag == 0:
                if i.startswith(comment_start1):  # 如果是以 // 開頭
                    line_num = line_num + 1
                    continue
                elif i.startswith(comment_start2):  # 如果是以 /* 開頭
                    line_comment_start = line_num
                    cflag = 1
                    line_num = line_num + 1
                    continue
            elif cflag == 1:
                if i.endswith(comment_end):  # 如果是以 */ 結尾
                    for m in range(line_comment_start, line_num + 1):
                        cflag = 0
                    line_num = line_num + 1
                    continue
                else:
                    line_num = line_num + 1
                    continue

            line_num = line_num + 1

        # 存放字元的列表
        each = []
        # 分解每個字元
        for m in i:
            each.append(m)  # 將每個字元新增到列表 each 中

        word = ''

        for e in each:
            # 是操作符
            if oflag == 1:
                if e in ['=', '<', '>', '+', '-', '*', '/', '%', '|', '&']:
                    OP_List.append(op_first + e)
                    print_List.append('Line:' + str(line_num) + ' ' + op_first + e + ', OP')
                    content_List.append(op_first + e)
                elif re.match(r'[a-zA-Z\_]', e):
                    word = word + e
                    OP_List.append(op_first)
                    print_List.append('Line:' + str(line_num) + ' ' + op_first + ', OP')
                    content_List.append(op_first)
                oflag = 0
                continue
            # 是常數 NUM
            elif oflag == 2:
                if e == ' ':
                    NUM_List.append(word)
                    print_List.append('Line:' + str(line_num) + ' ' + word + ', NUM')
                    content_List.append(word)
                    word = ''
                    oflag = 0
                elif e in SEPARATOR:
                    NUM_List.append(word)
                    print_List.append('Line:' + str(line_num) + ' ' + word + ', NUM')
                    content_List.append(word)
                    SEPARATOR_list.append(e)
                    print_List.append('Line:' + str(line_num) + ' ' + e + ', SEPARATOR')
                    content_List.append(e)
                    word = ''
                    oflag = 0
                else:
                    word = word + e
                continue
            # 是關鍵字或變數名
            elif oflag == 3:
                if e == ' ':
                    if word in key_ws:
                        KEY_List.append(word)
                        print_List.append('Line:' + str(line_num) + ' ' + word + ', KEY')
                        content_List.append(word)
                    elif re.match(ID, word):
                        ID_List.append(word)
                        print_List.append('Line:' + str(line_num) + ' ' + word + ', ID')
                        content_List.append(word)
                    word = ''
                    oflag = 0
                elif e in SEPARATOR:
                    if word in key_ws:
                        KEY_List.append(word)
                        print_List.append('Line:' + str(line_num) + ' ' + word + ', KEY')
                        content_List.append(word)
                    elif re.match(ID, word):
                        ID_List.append(word)
                        print_List.append('Line:' + str(line_num) + ' ' + word + ', ID')
                        content_List.append(word)
                    SEPARATOR_list.append(e)
                    print_List.append('Line:' + str(line_num) + ' ' + e + ', SEPARATOR')
                    content_List.append(e)
                    word = ''
                    oflag = 0
                else:
                    word = word + e
                continue
            # 是字串 STRING
            elif oflag == 4:
                if e != '"':
                    word = word + e
                elif e == '"':
                    word = word + e
                    STRING_List.append(word)
                    print_List.append('Line:' + str(line_num) + ' ' + word + ', STRING')
                    content_List.append(word)
                    word = ''
                    oflag = 0
                continue

            # 判斷是否是操作符(OP)
            if e in OP:
                oflag = 1
                op_first = e
                continue
            # 判斷是否是分隔符(SEPARATOR)
            if e in SEPARATOR:
                SEPARATOR_list.append(e)
                print_List.append('Line:' + str(line_num) + ' ' + e + ', SEPARATOR')
                content_List.append(e)
                continue
            # 判斷是否是常數 NUM
            if re.match(r'[0-9\.]', e):
                oflag = 2
                word = word + e
                continue
            # 判斷是否是關鍵字或變數名
            if re.match(r'[a-zA-Z\_]', e):
                oflag = 3
                word = word + e
                continue
            # 判斷是否是字串
            if e == '"':
                oflag = 4
                word = word + e
                continue

最後的輸出結果如下:

Line:1 #, SEPARATOR
Line:1 include, ID
Line:1 <, OP
Line:1 studio.h, ID
Line:1 >, SEPARATOR
Line:2 int, KEY
Line:2 main, ID
Line:2 (, SEPARATOR
Line:2 int, KEY
Line:2 argc, ID
Line:2 ,, SEPARATOR
Line:2 char, KEY
Line:2 const, KEY
Line:2 *, OP
Line:2 argv, ID
Line:2 [, SEPARATOR
Line:2 ], SEPARATOR
Line:2 ), SEPARATOR
Line:3 {, SEPARATOR
Line:4 char, KEY
Line:4 *, OP
Line:4 str, ID
Line:4 "String123", STRING
Line:4 ;, SEPARATOR
Line:10 int, KEY
Line:10 floatnum, ID
Line:10 123.4.56, NUM
Line:10 ;, SEPARATOR
Line:12 If, ID
Line:12 (, SEPARATOR
Line:12 6.4, NUM
Line:12 <=, OP
Line:12 3E-1, NUM
Line:12 ), SEPARATOR
Line:12 {, SEPARATOR
Line:13 printf, ID
Line:13 (, SEPARATOR
Line:13 "Yes\n", STRING
Line:13 ), SEPARATOR
Line:13 ;, SEPARATOR
Line:13 }, SEPARATOR
Line:14 return, KEY
Line:14 0, NUM
Line:14 ;, SEPARATOR
Line:15 }, SEPARATOR

看結果很明顯有幾個判斷錯誤,還有源程式錯誤沒有挑出來。不過我是個很懶的人,差不多就行了,有需要的就自己再改進了。這裡只是提供一個思路或借鑑。

相關推薦

LEX & FLEX 實現C語言詞法分析器

最近在學習《編譯原理》,學完詞法分析之後,做了一個C語言的詞法分析器。 詞法分析簡述: 詞法分析是編譯過程的第一步,主要實現高階語言程式中詞法規範的檢查。詞法分析程式的主要任務是按語言的詞法規則從源程式中逐個識別單詞,把字串形式的源程式轉行成單詞串的形式,並把每個單詞轉換

Python 實現C 語言 詞法分析器

這個學期上了編譯原理課,真的是超難。。。 這門課難到,全院老師只有我們老師他一個人會教編譯原理,哈哈哈哈 這門課這個學期有兩個實驗,一個是寫詞法分析器,一個是寫語法分析器 這裡的詞法分析器是用 Python 寫。Python 是剛自學的,所以使用上應該

【編譯原理】利用Flex工具生成C語言詞法分析器

Flex構造C語言詞法分析器 可以識別大部分的C語言關鍵字和識別符號,可以去除註釋(多行單行都可以),可以識別整數和浮點數,可以識別錯誤的浮點數。 lex檔案結構: [第一部分:定義段] /* *按照C語言語法,宣告檔案包含,巨集定義,常數定義,全域性

編譯原理:C語言詞法分析器

編譯原理的實驗:完成對C語言的詞法分析 先說一下整體框架: 基類:Base  封裝了一些基礎的字元判斷函式,如下: int charkind(char c);//判斷字元型別 int spaces(char c); //當前空格是否可以消除 int characte

【編譯原理】類C語言詞法分析器的設計

1.實驗要求輸入為一個以類C語言編寫的源程式輸出為一組二元組序列構成的文字檔案,一行為一個二元組,二元組中間以逗號隔開實驗報告上要求附上DFA 2.語言說明:保留字:unsigned、break、return、void、case、float、char、for、while、co

編譯原理之手工構造C語言詞法分析器

編寫一個(C語言)詞法分析器:需求是:1對原來的資料進行預處理,刪掉註釋;(為了展示方便,就不刪掉換行,製表符了,本來應該是要刪掉這些的)2將詞法正確的token分解出來,一共應該有5類,識別符號,關鍵字,常數,界符,運算子,對於原來的原始碼,將token之間都加上空格;3對

C語言實現簡單的詞法分析器

詞法分析器又稱掃描器。詞法分析是指將我們編寫的文字程式碼流解析為一個一個的記號,分析得到的記號以供後續語法分析使用。詞法分析器的工作是低級別的分析:將字元或者字元序列轉化成記號.。 要實現的詞法分析器單詞符號及種別碼對照表: 單詞符號 # begin if then wh

pythonC語言樣的函式引數引用實現..

python中有傳參需求,好像也沒有像C一樣傳參(引用)設計,可以採用一種變形方式,函式返回值來實現。 def test(): t1 = "123123" t2 = "test" t3 = 122 t

java實現C語言子集的語法分析器

如題,只是做一個演算法的演示,所以並不能識別C語言全部的關鍵字,像int 等關鍵字會被識別為識別符號。可以按照自己需求自行擴充保留字表。 程式功能: 詞法分析器從input檔案中讀入一小段C語言源程式,以二元式形式按順序輸出所有單詞。輸出結果在顯示器上顯示,同時存入outp

CCF認證歷年試題解(python版本 + c語言版+c++版本)

試題編號 試題名稱 最高得分 試題連結 備註 201803-1 跳一跳 100 python  C語言   201

python嵌入C語言

編寫C語言檔案,add.c #include <stdio.h> int add_int(int, int); float add_float(float, float); int add_int(int num1, int num2){ return num1 +

巨集開關管理模組的實現 C語言

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

k-mean實現 C語言(轉載)

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include <time.h>   #define N 12

資料結構-佇列-順序表實現-C語言

佇列定義 對於一個存取的n個內容,最先進入的最先出去(First In,First Out:FIFO),即稱為佇列. 比如,食堂排隊,最先去的,最先得到飯菜; 關鍵步驟:入隊出隊 程式碼實現 //迴圈佇列 順序表實現 #include <stdio

資料結構-陣列排序-二路歸併-迴圈實現-C語言

/* * * 歸併排序-迴圈實現 * * */ #include <stdio.h> #include <stdlib.h> void Merge(int Element[],int TmpA[],int L,int R,int RightEnd){

資料結構-二路歸併-遞迴實現-C語言

/* * * 二路歸併 遞迴實現 * * * */ #include <stdio.h> #include <stdlib.h> //對一個元素或者多個有序元素進行合併 void Merge(int Element[],int TmpA[],int

基於C++的詞法分析器

實驗目的 通過設計編制除錯一個具體的詞法分析程式,加深對詞法分析原理的理解。並掌握在對程式設計語言源程式進行掃描過程中將其分解為各類單詞的詞法分析方法。 編制一個讀單詞過程,從輸入的源程式中,識別出各個具有獨立意義的單詞(token),即基本保留字、識別符號、常量、運算子、分隔符五大類,並依

C語言--詞法分析程式

小C語言文法  1. <程式>→(){<宣告序列><語句序列>} 2. <宣告序列>→<宣告序列><宣告語句>|<宣告語句>|<空> 3. <宣告語句>→<識別符

資料結構之順序表的實現(C語言)

實現程式碼: #ifndef __LINEARLIST_H__ #define __LINEARLIST_H__ #include <malloc.h> #include <stdi

【資料結構】靜態順序表各種功能實現(C語言)

順序表的儲存方式 定義一個順序表 #define MAX_SIZE (100) typedef int DataType; typedef struct SeqList { DataType data[MAX_SIZE]; int siz