编译原理老师要求写一个java的词法分析器,想了想决定用python写一个。
目标
能识别出变量,数字,运算符,界符和关键字,用excel表打印出来。
有了目标,想想要怎么实现词法分析器。
1.先进行预处理,把注释,多余的空格,空行去掉。
2.一行一行扫描,行里逐字扫描,把界符和运算符当做分割符,遇到就先停下开始判断。
- 若是以 英文字母、$、下划线开头,则可能是变量和关键字,在判断是关键字还是变量。
- 若是数字开头,则判断下一位是不是也是数字,直到遇到非数字停止,在把数字取出来。
- 再来判断分割符是什么类型,是界符还是运算符。
在给不同词添加上识别码
在用excel表打印出来。
代码实现
1. 用列表创建一个关键字表,java关键字有50个。
1
2
3
4
5
6
7
8
9
10
11
|
#保留字 key_word = [ 'abstract' , 'assert' , 'boolean' , 'break' , 'byte' , 'case' , 'catch' , 'char' , 'class' , 'const' , 'continue' , 'default' , 'do' , 'double' , 'else' , 'enum' , 'extends' , 'final' , 'finally' , 'float' , 'for' , 'goto' , 'if' , 'implements' , 'import' , 'instanceof' , 'int' , 'interface' , 'long' , 'native' , 'new' , 'package' , 'private' , 'protected' , 'public' , 'return' , 'short' , 'static' , 'strictfp' , 'super' , 'switch' , 'synchronized' , 'this' , 'throw' , 'throws' , 'transient' , 'try' , 'void' , 'volatile' , 'while' ] |
2.用列表创建一个运算符表。
1
2
3
4
5
6
7
|
#运算符 operator = [ '+' , '-' , '*' , '/' , '%' , '++' , '--' , '+=' , '-=' , '+=' , '/=' , #算术运算符 '==' , '!=' , '>' , '<' , '>=' , '<=' , #关系运算符 '&' , '|' , '^' , '~' , '<<' , '>>' , '>>>' , #位运算符 '&&' , '||' , '!' , #逻辑运算符 '=' , '+=' , '-=' , '*=' , '/=' , '%=' , '<<=' , '>>=' , '&=' , '^=' , '|=' , #赋值运算符 '?:' ] #条件运算符 |
3. 用列表创建一个界符表。
1
2
|
#界符 delimiters = [ '{' , '}' , '[' , ']' , '(' , ')' , '.' , ',' , ':' , ';' ] |
4.预处理
用正则表达式把注释去掉,在把多余的空行去掉
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#预处理 def filterresource( file ,new_file): f2 = open (new_file, 'w+' ) txt = ' '.join(open(file,' r').readlines()) deal_txt = re.sub(r '\/\*[\s\s]*\*\/|\/\/.*' ,'',txt) for line in deal_txt.split( '\n' ): line = line.strip() line = line.replace( '\\t' ,'') line = line.replace( '\\n' ,'') if not line: continue else : f2.write(line + '\n' ) f2.close() return sys.path[ 0 ] + '\\' + new_file |
5.逐行扫描
按照刚刚的思路进行判断,把每一行的单词,添加到word_line列表中,最后在把每一行添加到token列表中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
def scan( file ): lines = open ( file , 'r' ).readlines() for line in lines: word = '' word_line = [] i = 0 while i < len (line): word + = line[i] if line[i] = = ' ' or line[i] in delimiters or line[i] in operator: if word[ 0 ].isalpha() or word[ 0 ] = = '$' or word[ 0 ] = = '_' : word = word[: - 1 ] if searchreserve(word): # 保留字 word_line.append({word[: - 1 ]:key_word.index(word)}) else : # 标识符 identifier.append({word: - 2 }) word_line.append({word: - 2 }) # 常数 elif word[: - 1 ].isdigit(): word_line.append({word: - 1 }) #else: #error_word.append(word) # 字符是界符 if line[i] in delimiters: word_line.append({line[i]: len (key_word) + delimiters.index(line[i])}) # 字符是运算符 elif line[i] in operator: s = line[i] + line[i + 1 ] if s in operator: word_line.append({s: len (key_word) + len (delimiters) + operator.index(s)}) i + = 1 else : word_line.append({line[i]: len (key_word) + len (delimiters) + operator.index(line[i])}) word = '' i + = 1 token.append(word_line) |
6.根据单词返回是什么类型
按照保留字--界符--运算符--常数的顺序来当识别码。常数识别码是-1,标识符识别码是-2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def check(number): hanzi = '' q = len (key_word) w = len (delimiters) e = len (operator) if 0 <number< = q: hanzi = '保留字' elif q<number < = q + w: hanzi = '界符' elif q + w<number < = q + w + e: hanzi = '运算符' elif number = = - 1 : hanzi = '常数' elif number = = - 2 : hanzi = '标识符' return hanzi |
7. 用thinker写一个简单的界面
导入
1
2
|
from tkinter import * from tkinter.filedialog import askdirectory,askopenfilename |
1
2
3
4
5
6
7
8
9
|
root = tk() root.title( '词法分析' ) root.resizable( 0 , 0 ) path = stringvar() label(root,text = "目标路径:" ).grid(row = 0 , column = 0 ) entry(root, textvariable = path).grid(row = 0 , column = 1 ) button(root, text = "路径选择" , command = openfiles).grid(row = 0 , column = 2 ) button(root,text = '词法分析' ,command = open_excel).grid(row = 0 ,column = 3 ) root.mainloop() |
打开文件
1
2
3
|
def openfiles(): fname = askopenfilename(title = '打开文件' , filetypes = [( 'all files' , '*' )]) path. set (fname) |
简单的界面
8.导入到excel表中
需要安装包xwings
1
|
pip install xwings |
导入
1
|
import xlwings as xw |
把token里的单词,按照 单词 ---- 识别码 ---类型 打印到excel表中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
def open_excel(): # 预处理 row,col = 0 , 0 if path.get()! = '': txt = java_analysis.filterresource(path.get(),new_file) print (txt) #扫描 java_analysis.scan(txt) app = xw.app(visible = true,add_book = false) wb = app.books. open (sys.path[ 0 ] + '\\'+' test.xlsx') sheet = wb.sheets.active sheet.clear() print (java_analysis.token) for i in range ( len (java_analysis.token)): sheet[row, 0 ].value = '第' + str (i + 1 ) + '行' row + = 1 for word in java_analysis.token[i]: for k,w in word.items(): sheet[row, 3 ].value = k sheet[row, 5 ].value = w sheet[row, 7 ].value = java_analysis.check(w) row + = 1 sheet.autofit() #整个sheet自动调整 #wb.save() |
最后就像这样
效果
代码很烂,不过也算是大致明白词法分析器了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://www.jianshu.com/p/30369358da8a