国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > Python > 正文

使用70行Python代碼實現一個遞歸下降解析器的教程

2020-02-23 00:47:41
字體:
來源:轉載
供稿:網友

 第一步:標記化

處理表達式的第一步就是將其轉化為包含一個個獨立符號的列表。這一步很簡單,且不是本文的重點,因此在此處我省略了很多。
首先,我定義了一些標記(數字不在此中,它們是默認的標記)和一個標記類型:
 

token_map = {'+':'ADD', '-':'ADD',       '*':'MUL', '/':'MUL',       '(':'LPAR', ')':'RPAR'} Token = namedtuple('Token', ['name', 'value'])

下面就是我用來標記 `expr` 表達式的代碼:
 

split_expr = re.findall('[/d.]+|[%s]' % ''.join(token_map), expr)tokens = [Token(token_map.get(x, 'NUM'), x) for x in split_expr]

第一行是將表達式分割為基本標記的技巧,因此
 

'1.2 / ( 11+3)' --> ['1.2', '/', '(', '11', '+', '3', ')']

下一行命名標記,這樣分析器就能通過分類識別它們:
 

['1.2', '/', '(', '11', '+', '3', ')']->[Token(name='NUM', value='1.2'), Token(name='MUL', value='/'), Token(name='LPAR', value='('), Token(name='NUM', value='11'), Token(name='ADD', value='+'), Token(name='NUM', value='3'), Token(name='RPAR', value=')')]

任何不在 token_map 中的標記被假定為數字。我們的分詞器缺少稱為驗證的屬性,以防止非數字被接受,但幸運的是,運算器將在以后處理它。
就是這樣
第二步: 語法定義

我選擇的解析器實現自一個本地垂直解析器,其來源于LL解析器的一個簡單版本。它是一個最簡單的解析器實現,事實上,只有僅僅14行代碼。它是一種自上而下的解析器,這意味著解析器從最上層規則開始解析(like:expression),然后以遞歸方式嘗試按照其子規則方式解析,直至符合最下層的規則(like:number)。換句話解釋,當自底向上解析器(LR)逐步地收縮標記,使規則被包含在其它規則中,直到最后僅剩下一個規則,而自頂向下解析器(LL)逐步展開規則并進入到少數的抽象規則,直到它能夠完全匹配輸入的標記。
在深入到實際的解析器實現之前,我們可對語法進行討論。在我之前發表的文章中,我使用過LR解析器,我可以像如下方式定義計算器語法(標記使用大寫字母表示):
 

add: add ADD mul | mul;mul: mul MUL atom | atom;atom: NUM | '(' add ')' | neg;neg: '-' atom;


(如果您還不理解上述語法,請閱讀我之前發表的文章)

現在我使用LL解析器,以如下方式定義計算器的語法:
 

rule_map = {  'add' : ['mul ADD add', 'mul'],  'mul' : ['atom MUL mul', 'atom'],  'atom': ['NUM', 'LPAR add RPAR', 'neg'],  'neg' : ['ADD atom'],}

大家可以看到,這里有一個微妙的變化。有關"add and mul"的遞歸定義被反轉了。這是個非常重要的細節,我會向大家詳細說明這一點。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 鄂温| 鄂伦春自治旗| 吉首市| 双江| 辛集市| 栾川县| 蓬莱市| 和田市| 博白县| 泊头市| 印江| 嘉定区| 禹州市| 许昌县| 新宁县| 东兰县| 加查县| 郸城县| 苏尼特右旗| 资中县| 临澧县| 沧州市| 长岭县| 台江县| 临海市| 新宾| 科技| 舞钢市| 南汇区| 体育| 左云县| 涡阳县| 安化县| 涟水县| 临清市| 苏州市| 盱眙县| 淮阳县| 河东区| 伊金霍洛旗| 江城|