自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

使用 Python 開發(fā)一個(gè) Python 解釋器

開發(fā) 后端
在本文中,我們將設(shè)計(jì)一個(gè)可以執(zhí)行算術(shù)運(yùn)算的解釋器。一起來看看吧。

 

計(jì)算機(jī)只能理解機(jī)器碼。歸根結(jié)底,編程語言只是一串文字,目的是為了讓人類更容易編寫他們想讓計(jì)算機(jī)做的事情。真正的魔法是由編譯器和解釋器完成,它們彌合了兩者之間的差距。解釋器逐行讀取代碼并將其轉(zhuǎn)換為機(jī)器碼。

在本文中,我們將設(shè)計(jì)一個(gè)可以執(zhí)行算術(shù)運(yùn)算的解釋器。

我們不會(huì)重新造輪子。文章將使用由 David M. Beazley 開發(fā)的詞法解析器 —— PLY(Python Lex-Yacc(https://github.com/dabeaz/ply))。

PLY 可以通過以下方式下載:

  1. $ pip install ply 

我們將粗略地瀏覽一下創(chuàng)建解釋器所需的基礎(chǔ)知識(shí)。欲了解更多,請(qǐng)參閱這個(gè) GitHub 倉(cāng)庫(https://github.com/dabeaz/ply)。

標(biāo)記(Token)

標(biāo)記是為解釋器提供有意義信息的最小字符單位。標(biāo)記包含一對(duì)名稱和屬性值。

讓我們從創(chuàng)建標(biāo)記名稱列表開始。這是一個(gè)必要的步驟。 

  1. tokens = (  
  2.     # 數(shù)據(jù)類型  
  3.     "NUM",  
  4.     "FLOAT",  
  5.     # 算術(shù)運(yùn)算  
  6.     "PLUS",  
  7.     "MINUS",  
  8.     "MUL",  
  9.     "DIV",  
  10.     # 括號(hào)  
  11.     "LPAREN",  
  12.     "RPAREN",  

詞法分析器(Lexer)

將語句轉(zhuǎn)換為標(biāo)記的過程稱為標(biāo)記化或詞法分析。執(zhí)行詞法分析的程序是詞法分析器。 

  1. # 標(biāo)記的正則表達(dá)  
  2. t_PLUS   = r"\+"  
  3. t_MINUS  = r"\-"  
  4. t_MUL    = r"\*"  
  5. t_DIV    = r"/"  
  6. t_LPAREN = r"\("  
  7. t_RPAREN = r"\)"  
  8. t_POW    = r"\^"  
  9. # 忽略空格和制表符  
  10. t_ignore = " \t"  
  11. # 為每個(gè)規(guī)則添加動(dòng)作  
  12. def t_FLOAT(t):  
  13.     r"""\d+\.\d+"""  
  14.     t.value = float(t.value)  
  15.     return t  
  16. def t_NUM(t):  
  17.     r"""\d+"""  
  18.     t.value = int(t.value)  
  19.     return t  
  20. # 未定義規(guī)則字符的錯(cuò)誤處理  
  21. def t_error(t):  
  22.     # 此處的 t.value 包含未標(biāo)記的其余輸入  
  23.     print(f"keyword not found: {t.value[0]}\nline {t.lineno}")  
  24.     t.lexer.skip(1)  
  25. # 如果遇到 \n 則將其設(shè)為新的一行  
  26. def t_newline(t):  
  27.     r"""\n+"""  
  28.     t.lexer.lineno += t.value.count("\n") 

為導(dǎo)入詞法分析器,我們將使用:

import ply.lex as lex

t_ 是一個(gè)特殊的前綴,表示定義標(biāo)記的規(guī)則。每條詞法規(guī)則都是用正則表達(dá)式制作的,與 Python 中的 re 模塊兼容。正則表達(dá)式能夠根據(jù)規(guī)則掃描輸入并搜索符合的符號(hào)串。正則表達(dá)式定義的文法稱為正則文法。正則文法定義的語言則稱為正則語言。

定義好了規(guī)則,我們將構(gòu)建詞法分析器。 

  1. data = 'a = 2 +(10 -8)/1.0'  
  2. lexlexer = lex.lex()  
  3. lexer.input(data)  
  4. while tok :lexer.token():  
  5.     print(tok) 

為了傳遞輸入字符串,我們使用 lexer.input(data)。lexer.token() 將返回下一個(gè) LexToken 實(shí)例,最后返回 None。根據(jù)上述規(guī)則,代碼 2 + ( 10 -8)/1.0 的標(biāo)記將是:

紫色字符代表的是標(biāo)記的名稱,其后是標(biāo)記的具體內(nèi)容。

巴科斯-諾爾范式(Backus-Naur Form,BNF)

大多數(shù)編程語言都可以用上下文無關(guān)文法來編寫。它比常規(guī)語言更復(fù)雜。對(duì)于上下文無關(guān)文法,我們用上下文無關(guān)語法,它是描述語言中所有可能語法的規(guī)則集。BNF 是一種定義語法的方式,它描述了編程語言的語法。讓我們看看例子:

symbol : alternative1 | alternative2 …

根據(jù)產(chǎn)生式,: 的左側(cè)被替換為右側(cè)的其中一個(gè)值替換。右側(cè)的值由 | 分隔(可理解為 symbol 定義為 alternative1 或 alternative2或…… 等等)。對(duì)于我們的這個(gè)算術(shù)解釋器,語法規(guī)格如下: 

  1. expression : expression '+' expression  
  2.            | expression '-' expression  
  3.            | expression '/' expression  
  4.            | expression '*' expression  
  5.            | expression '^' expression  
  6.            | +expression  
  7.            | -expression  
  8.            | ( expression )  
  9.            | NUM  
  10.            | FLOAT 

輸入的標(biāo)記是諸如 NUM、FLOAT、+、-、*、/ 之類的符號(hào),稱作終端(無法繼續(xù)分解或產(chǎn)生其他符號(hào)的字符)。一個(gè)表達(dá)式由終端和規(guī)則集組成,例如 expression 則稱為非終端。

解析器(Parser)

我們將使用 YACC(Yet Another Compiler Compiler) 作為解析器生成器。導(dǎo)入模塊:import ply.yacc as yacc。 

  1. from operator import (add, sub, mul, truediv, pow)  
  2. # 我們的解釋器支持的運(yùn)算符列表  
  3. ops = {  
  4.     "+": add,  
  5.     "-": sub,  
  6.     "*": mul,  
  7.     "/": truediv,  
  8.     "^": pow,  
  9. def p_expression(p):  
  10.     """expression : expression PLUS expression  
  11.                   | expression MINUS expression  
  12.                   | expression DIV expression  
  13.                   | expression MUL expression  
  14.                   | expression POW expression"""  
  15.     if (p[2], p[3]) == ("/", 0):  
  16.         # 如果除以 0,則將“INF”(無限)作為值  
  17.         p[0] = float("INF")  
  18.     else:  
  19.         p[0] = ops[p[2]](p[1], p[3])  
  20. def p_expression_uplus_or_expr(p):  
  21.     """expression : PLUS expression %prec UPLUS  
  22.                   | LPAREN expression RPAREN"""  
  23.     p[0] = p[2]  
  24. def p_expression_uminus(p):  
  25.     """expression : MINUS expression %prec UMINUS"""  
  26.     p[0] = -p[2]  
  27. def p_expression_num(p):  
  28.     """expression : NUM  
  29.                   | FLOAT"""  
  30.     p[0] = p[1]  
  31. # 語法錯(cuò)誤時(shí)的規(guī)則  
  32. def p_error(p):  
  33.     print(f"Syntax error in {p.value}") 

在文檔字符串中,我們將添加適當(dāng)?shù)恼Z法規(guī)范。p 列表中的的元素與語法符號(hào)一一對(duì)應(yīng),如下所示: 

  1. expression : expression PLUS expression  
  2. p[0]         p[1]       p[2] p[3] 

在上文中,%prec UPLUS 和 %prec UMINUS 是用來表示自定義運(yùn)算的。%prec 即是 precedence 的縮寫。在符號(hào)中本來沒有 UPLUS 和 UMINUS 這個(gè)說法(在本文中這兩個(gè)自定義運(yùn)算表示一元正號(hào)和符號(hào),其實(shí) UPLUS 和 UMINUS 只是個(gè)名字,想取什么就取什么)。之后,我們可以添加基于表達(dá)式的規(guī)則。YACC 允許為每個(gè)令牌分配優(yōu)先級(jí)。我們可以使用以下方法設(shè)置它: 

  1. precedence = (  
  2.     ("left", "PLUS", "MINUS"),  
  3.     ("left", "MUL", "DIV"),  
  4.     ("left", "POW"),  
  5.     ("right", "UPLUS", "UMINUS")  

在優(yōu)先級(jí)聲明中,標(biāo)記按優(yōu)先級(jí)從低到高的順序排列。PLUS 和 MINUS 優(yōu)先級(jí)相同并且具有左結(jié)合性(運(yùn)算從左至右執(zhí)行)。MUL 和 DIV 的優(yōu)先級(jí)高于 PLUS 和 MINUS,也具有左結(jié)合性。POW 亦是如此,不過優(yōu)先級(jí)更高。UPLUS 和 UMINUS 則是具有右結(jié)合性(運(yùn)算從右至左執(zhí)行)。

要解析輸入我們將使用: 

  1. parser = yacc.yacc()  
  2. result = parser.parse(data)  
  3. print(result) 

完整代碼如下: 

  1. #####################################  
  2. # 引入模塊                           #  
  3. #####################################  
  4. from logging import (basicConfig, INFO, getLogger)  
  5. from operator import (add, sub, mul, truediv, pow)  
  6. import ply.lex as lex  
  7. import ply.yacc as yacc  
  8. # 我們的解釋器支持的運(yùn)算符列表  
  9. ops = {  
  10.     "+": add,  
  11.     "-": sub,  
  12.     "*": mul,  
  13.     "/": truediv,  
  14.     "^": pow,  
  15.  
  16. #####################################  
  17. # 標(biāo)記集                             #  
  18. #####################################  
  19. tokens = (  
  20.     # 數(shù)據(jù)類型  
  21.     "NUM",  
  22.     "FLOAT",  
  23.     # 算術(shù)運(yùn)算  
  24.     "PLUS",  
  25.     "MINUS",  
  26.     "MUL",  
  27.     "DIV",  
  28.     "POW",  
  29.     # 括號(hào)  
  30.     "LPAREN",  
  31.     "RPAREN",  
  32.  
  33. #####################################  
  34. # 標(biāo)記的正則表達(dá)式                    #  
  35. #####################################  
  36. t_PLUS   = r"\+"  
  37. t_MINUS  = r"\-"  
  38. t_MUL    = r"\*"  
  39. t_DIV    = r"/"  
  40. t_LPAREN = r"\("  
  41. t_RPAREN = r"\)"  
  42. t_POW    = r"\^"  
  43. # 忽略空格和制表符  
  44. t_ignore = " \t"  
  45. # 為每個(gè)規(guī)則添加動(dòng)作  
  46. def t_FLOAT(t):  
  47.     r"""\d+\.\d+"""  
  48.     t.value = float(t.value)  
  49.     return t  
  50. def t_NUM(t):  
  51.     r"""\d+"""  
  52.     t.value = int(t.value)  
  53.     return t  
  54. # 未定義規(guī)則字符的錯(cuò)誤處理  
  55. def t_error(t):  
  56.     # 此處的 t.value 包含未標(biāo)記的其余輸入  
  57.     print(f"keyword not found: {t.value[0]}\nline {t.lineno}")  
  58.     t.lexer.skip(1)  
  59. # 如果看到 \n 則將其設(shè)為新的一行 
  60.  def t_newline(t):  
  61.     r"""\n+"""  
  62.     t.lexer.lineno += t.value.count("\n")  
  63. #####################################  
  64. # 設(shè)置符號(hào)優(yōu)先級(jí)                      #  
  65. #####################################  
  66. precedence = (  
  67.     ("left", "PLUS", "MINUS"),  
  68.     ("left", "MUL", "DIV"),  
  69.     ("left", "POW"),  
  70.     ("right", "UPLUS", "UMINUS")  
  71.  
  72. #####################################  
  73. # 書寫 BNF 規(guī)則                      #  
  74. #####################################  
  75. def p_expression(p):  
  76.     """expression : expression PLUS expression  
  77.                   | expression MINUS expression  
  78.                   | expression DIV expression  
  79.                   | expression MUL expression  
  80.                   | expression POW expression"""  
  81.     if (p[2], p[3]) == ("/", 0):  
  82.         # 如果除以 0,則將“INF”(無限)作為值  
  83.         p[0] = float("INF")  
  84.     else:  
  85.         p[0] = ops[p[2]](p[1], p[3])  
  86. def p_expression_uplus_or_expr(p):  
  87.     """expression : PLUS expression %prec UPLUS  
  88.                   | LPAREN expression RPAREN"""  
  89.     p[0] = p[2]  
  90. def p_expression_uminus(p):  
  91.     """expression : MINUS expression %prec UMINUS"""  
  92.     p[0] = -p[2]  
  93. def p_expression_num(p):  
  94.     """expression : NUM  
  95.                   | FLOAT"""  
  96.     p[0] = p[1]  
  97. # 語法錯(cuò)誤時(shí)的規(guī)則  
  98. def p_error(p):  
  99.     print(f"Syntax error in {p.value}") 
  100.  #####################################  
  101. # 主程式                             #  
  102. #####################################  
  103. if __name__ == "__main__":  
  104.     basicConfig(level=INFOfilename="logs.txt"
  105.     lexlexer = lex.lex()  
  106.     parser = yacc.yacc()  
  107.     while True:  
  108.         try:  
  109.             result = parser.parse(  
  110.                 input(">>>"),  
  111.                 debug=getLogger())  
  112.             print(result)  
  113.         except AttributeError:  
  114.             print("invalid syntax") 

結(jié)論

由于這個(gè)話題的體積龐大,這篇文章并不能將事物完全的解釋清楚,但我希望你能很好地理解文中涵蓋的表層知識(shí)。 

 

責(zé)任編輯:龐桂玉 來源: 馬哥Linux運(yùn)維
相關(guān)推薦

2024-01-31 08:16:38

IPythonPython解釋器

2024-05-15 10:07:11

Agents人工智能CSV

2022-11-02 21:00:21

Python解釋器智能手機(jī)

2010-02-01 13:55:12

Python 解釋器

2023-03-10 13:38:00

Python文檔掃描器

2012-08-14 10:44:52

解釋器編程

2024-01-25 11:41:00

Python開發(fā)前端

2016-09-12 14:05:27

PythonPython解釋器Web

2014-04-18 09:31:04

PystonDropboxPython

2022-06-29 09:02:31

go腳本解釋器

2019-07-24 13:42:34

Python編程語言代碼

2020-01-10 18:04:01

Python編程語言Windows

2018-08-26 05:38:44

路由器調(diào)制解調(diào)器網(wǎng)絡(luò)設(shè)備

2020-10-16 16:28:54

Python開發(fā)技術(shù)

2010-02-23 15:52:14

Python編輯器

2021-12-01 07:02:55

Python 記錄器按鍵

2023-09-05 09:00:00

工具Python抄襲檢測(cè)系統(tǒng)

2023-10-18 10:48:44

Python解釋器

2010-02-24 15:41:53

Python解釋器

2021-09-03 12:33:36

語言并發(fā)下載器
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)