用python手工編寫一個詞法分析器

用python手工編寫一個詞法分析器

@author:x1Nge.

  • 編譯原理基礎實驗

實驗目的

通過設計編制調試一個具體的詞法分析程序,加深對詞法分析原理的理解,這裏我使用python作爲開發語言。

過程分析

爲了簡化設計,降低難度,這裏設計的詞法分析器識別以下內容:

類別 舉例 輸出舉例(種別編碼,自身值)
保留字 if 、int、while (1,“int”)
標識符 a、b、c (2,“a”)
整常數 6、16、36 (3,“0110”)
運算符 +、-、*、/、**、>= (4,"+")
分隔符 ;、{、} (5,";")

基本流程圖如下:

Created with Raphaël 2.2.0開始初始化讀入字符忽略空格字母_$?讀入字符字母數字_$?指針回退查詢保留字表結束數字?讀入字符數字?指針回退運算符?分隔符?yesnoyesnoyesnoyesnoyesnoyes

內容一:編寫子功能函數

1.讀入下一個字符

# 把下一個字符讀入到new_ch中
def get_char():
    global p
    temp_ch = res_lst[p]
    p += 1
    return temp_ch

注意:實際工作中並不常用在函數內部用global來使用全局變量

2.跳過空白符直至ch讀入一個非空白符

# 跳過空白符直至ch讀入一個非空白符
def get_blank_ch(temp_ch_1):
    if temp_ch_1 == ' ':
        temp_ch_2 = get_char()
        return temp_ch_2
    return temp_ch_1

3.把ch中的字符連接到str_get之後

# 把ch中的字符連接到str_get之後
def ch_append():
    #直接調用python函數
    return

有話說:剛開始考慮寫詞法分析器並未考慮具體語言,於是有一些函數在這裏並不需要實現

3.查找保留字表中是否有str_get,若存在則返回1,否則返回0

# 查找保留字表中是否有str_get,若存在則返回1,否則返回0
def is_reserved_word( str_result ):
    check_client = pymongo.MongoClient("mongodb://localhost:27017/")
    check_db = check_client["PrincipleOfCompiler"]
    check_col = check_db["ReservedWord"]
    check_query = {"content" : str_result}
    for get_text in check_col.find(check_query):
        # 判斷匹配到的get_text是否爲空,若不爲空則要匹配的字符串在保留字表中找到
        if any(get_text):
            check_client.close()
            return 1
    check_client.close()
    return 0

有話說:這裏我把保留字表放在了數據庫裏,使用的是mongodb,當然也可以用My SQL或者其他數據庫,python使用的時候需要導入包,mongodb是pymongo

pip install pymongo
import pymongo

4.將搜索指針回調一個字符位置

# 將搜索指針回調一個字符位置
def retract_pointer():
    global p
    p -= 1
    return

5.若識別爲標識符,將str_result中的標識符插入符號表並返回符號表指針

# 若識別爲標識符,將str_result中的標識符插入符號表並返回符號表指針
def insert_identifier( str_result ):
    return str_result

6.若識別爲常數,將str_result中的常數插入常數表並返回參數表指針

# 若識別爲常數,將str_result中的常數插入常數表並返回參數表指針
def insert_constant( str_result ):
    return str(bin(int(str_result)))

有話說:爲了簡化這裏我直接返回了其自身值(整常數返回二進制數)

內容二:編寫主功能函數

接下來分析主功能函數的編寫,我們按照流程圖的框架進行分析:

注意:主功能我都寫在一個函數裏了,以下部分均爲函數內代碼,作分析之用,全部源碼見下文

初始化

 # 初始化
    result = []
    str_get = []
    ch = get_char()
    new_ch = get_blank_ch(ch)

識別標識符

# 識別標識符
    if  new_ch.isalpha() or new_ch == '_' or new_ch == '$':
        str_get.append(new_ch)
        new_ch = get_char()
        while new_ch.isalpha() or new_ch.isdigit() or new_ch == '_' or new_ch == '$':
            str_get.append(new_ch)
            new_ch = get_char()
        retract_pointer()
        str_result = ''.join(str_get)
        code = is_reserved_word(str_result)
        if code == 0 :
            value = insert_identifier(str_result)
            result.append('2') # 這裏使用2作爲非保留字的標識符的種別編碼
            result.append(value)
            return result
        else:
            result.append('1') # 這裏使用1作爲保留字的種別編碼
            result.append(str_result) # 實驗例子中value值爲保留字本身
            """
            result.append('-') # 保留字無自身值
            """
            return result

識別整常數

 # 識別整常數
    elif new_ch.isdigit():
        str_get.append(new_ch)
        new_ch = get_char()
        while new_ch.isdigit():
            str_get.append(new_ch)
            new_ch = get_char()
        retract_pointer()
        str_result = ''.join(str_get)
        value = insert_constant(str_result)
        result.append('3') # 這裏使用3作爲整常數的種別編碼
        result.append(value)
        return result

識別運算符

#識別運算符
    elif new_ch == '=' or new_ch == '+' or new_ch == '-' or new_ch == '*' or new_ch == '/' or new_ch == '>'\
        or new_ch == '<' or new_ch == '!' or new_ch == '%':
        if new_ch == '>' or new_ch == '<' or new_ch == '!':
            str_get.append(new_ch)
            value = ''.join(new_ch)
            new_ch = get_char()
            if new_ch == '=':
                str_get.append(new_ch)
                str_result = ''.join(str_get)
                result.append('4') # 這裏使用4作爲運算符的種別編碼
                result.append(str_result)
                return result
            else:
                retract_pointer()
                result.append('4')
                result.append(value)
                return result
        elif new_ch == '*':
            str_get.append(new_ch)
            value = ''.join(new_ch)
            new_ch = get_char()
            if new_ch == '*':
                str_get.append(new_ch)
                str_result = ''.join(str_get)
                result.append('4')
                result.append(str_result)
                return result
            else:
                retract_pointer()
                result.append('4')
                result.append(value)
                return result
        else:
            value = ''.join(new_ch)
            result.append('4')
            result.append(value)
            return  result

識別分隔符

# 識別分隔符
    elif new_ch == ',' or new_ch == ';' or new_ch == '{' or new_ch == '}' or new_ch == '(' or new_ch == ')':
        value = ''.join(new_ch)
        result.append('5') # 這裏使用5作爲分隔符的種別編碼
        result.append(value)
        return result

其他

    else:
        result.append("Error.")
        return result

注意:這裏我只是檢查了幾個主要的分隔符、運算符,若要全部檢查,則查詢一張完整的表即可

內容三:其他功能代碼

文件讀入及預處理。這裏我 主要將換行和\t去掉,並把兩個空格替換爲一個空格,如果要去掉全部空格,則記得保留諸如int a這種代碼間的空格

f = open('codeTest.txt','r')
res = f.read().replace('\n','').replace('\t','').replace('  ',' ')
res_lst = list(res)
print(res)
p = 0 # 初始化位置指針

運行

while p in range(len(res_lst)):
    print(check_code())
f.close()

運行截圖及源碼

  • 個人能力有限,程序有許多考慮不周的地方,歡迎提出修改意見
  • 同步更新至CSDN,僅作實驗記錄之用。

例:

main()
{
	int  a,b;
	a = 10;
  	b = a + 20;
}

運行:
p1
源碼:

import pymongo

"""
code,value 暫不進行初始化
"""

f = open('codeTest.txt','r')
res = f.read().replace('\n','').replace('\t','').replace('  ',' ')
res_lst = list(res)
print(res)
p = 0 # 初始化位置指針

def check_code():
    # 初始化
    result = []
    str_get = []
    ch = get_char()
    new_ch = get_blank_ch(ch)
    # 識別標識符
    if  new_ch.isalpha() or new_ch == '_' or new_ch == '$':
        str_get.append(new_ch)
        new_ch = get_char()
        while new_ch.isalpha() or new_ch.isdigit() or new_ch == '_' or new_ch == '$':
            str_get.append(new_ch)
            new_ch = get_char()
        retract_pointer()
        str_result = ''.join(str_get)
        code = is_reserved_word(str_result)
        if code == 0 :
            value = insert_identifier(str_result)
            result.append('2') # 這裏使用2作爲非保留字的標識符的種別編碼
            result.append(value)
            return result
        else:
            result.append('1') # 這裏使用1作爲保留字的種別編碼
            result.append(str_result) # 實驗例子中value值爲保留字本身
            """
            result.append('-') # 保留字無自身值
            """
            return result
    # 識別整常數
    elif new_ch.isdigit():
        str_get.append(new_ch)
        new_ch = get_char()
        while new_ch.isdigit():
            str_get.append(new_ch)
            new_ch = get_char()
        retract_pointer()
        str_result = ''.join(str_get)
        value = insert_constant(str_result)
        result.append('3') # 這裏使用3作爲整常數的種別編碼
        result.append(value)
        return result
    #識別運算符
    elif new_ch == '=' or new_ch == '+' or new_ch == '-' or new_ch == '*' or new_ch == '/' or new_ch == '>'\
        or new_ch == '<' or new_ch == '!' or new_ch == '%':
        if new_ch == '>' or new_ch == '<' or new_ch == '!':
            str_get.append(new_ch)
            value = ''.join(new_ch)
            new_ch = get_char()
            if new_ch == '=':
                str_get.append(new_ch)
                str_result = ''.join(str_get)
                result.append('4') # 這裏使用4作爲運算符的種別編碼
                result.append(str_result)
                return result
            else:
                retract_pointer()
                result.append('4')
                result.append(value)
                return result
        elif new_ch == '*':
            str_get.append(new_ch)
            value = ''.join(new_ch)
            new_ch = get_char()
            if new_ch == '*':
                str_get.append(new_ch)
                str_result = ''.join(str_get)
                result.append('4')
                result.append(str_result)
                return result
            else:
                retract_pointer()
                result.append('4')
                result.append(value)
                return result
        else:
            value = ''.join(new_ch)
            result.append('4')
            result.append(value)
            return  result
    # 識別分隔符
    elif new_ch == ',' or new_ch == ';' or new_ch == '{' or new_ch == '}' or new_ch == '(' or new_ch == ')':
        value = ''.join(new_ch)
        result.append('5') # 這裏使用5作爲分隔符的種別編碼
        result.append(value)
        return result
    else:
        result.append("Error.")
        return result

# 把下一個字符讀入到new_ch中
def get_char():
    global p
    temp_ch = res_lst[p]
    p += 1
    return temp_ch

# 跳過空白符直至ch讀入一個非空白符
def get_blank_ch(temp_ch_1):
    if temp_ch_1 == ' ':
        temp_ch_2 = get_char()
        return temp_ch_2
    return temp_ch_1

# 把ch中的字符連接到str_get之後
def ch_append():
    #直接調用python函數
    return

# 查找保留字表中是否有str_get,若存在則返回1,否則返回0
def is_reserved_word( str_result ):
    check_client = pymongo.MongoClient("mongodb://localhost:27017/")
    check_db = check_client["PrincipleOfCompiler"]
    check_col = check_db["ReservedWord"]
    check_query = {"content" : str_result}
    for get_text in check_col.find(check_query):
        # 判斷匹配到的get_text是否爲空,若不爲空則要匹配的字符串在保留字表中找到
        if any(get_text):
            check_client.close()
            return 1
    """
    check_doc = check_col.find(check_query)
    print(check_doc)
    for res in check_doc:
        print(res)
    """
    check_client.close()
    return 0

# 將搜索指針回調一個字符位置
def retract_pointer():
    global p
    p -= 1
    return

# 若識別爲標識符,將str_result中的標識符插入符號表並返回符號表指針
def insert_identifier( str_result ):
    return str_result

# 若識別爲常數,將str_result中的常數插入常數表並返回參數表指針
def insert_constant( str_result ):
    return str(bin(int(str_result)))

while p in range(len(res_lst)):
    print(check_code())
f.close()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章