本文適用于 Rail 0.1 版本.
工作:輸入Rial文件的路徑,識別詞元,輸出實例列表.
是一邊寫代碼一邊寫文章的,所以有時候改了原本的代碼不一定會說.以思路為中心.
Rail
是一種信息分布與細節構成的表示語言。詳見參考文檔.
關于本文的分析對象,參考邏輯行的類型.
從源文件到詞元
這個Python腳本實現了文件的讀取和詞元拆分.以及縮進個數的識別.
def split_mul_ind(inp):word = ""line = [] result = []indent = 0indent_list = []ind_in = Truefor char in inp:if char =="\n":if word:line.append(word)word = ""if line:result.append(line)indent_list.append(indent)line = []indent = 0ind_in = Trueelif char == " ":if ind_in:indent += 1elif word:line.append(word)word = ""else:ind_in = Falseword += charif word: line.append(word)if line:result.append(line)indent_list.append(indent)return (result, indent_list)with (open("test.txt", 'r') as f):result, indent_list = split_mul_ind(f.read())def check(result, indent_list, n):print(f"[{n+1}] {result[n]}: {indent_list[n]}")
測試文件 test.txt
如下.包含了Rail語言的20種語義.
:
: *
*
* = *
< *
< * = *
< * = * ? *
* < *
* < * ! *
+ *
+ * = *
+ * < *
+ * < * ! *
> *
> * = *
> * < *
> * < * ! *
* >
# *
測試方法如下.
for i in range(19):check(result, indent_list, i)
運行結果如下.
[1] [':']: 0
[2] [':', '*']: 0
[3] ['*']: 0
[4] ['*', '=', '*']: 0
[5] ['<', '*']: 0
[6] ['<', '*', '=', '*']: 0
[7] ['<', '*', '=', '*', '?', '*']: 0
[8] ['*', '<', '*']: 0
[9] ['*', '<', '*', '!', '*']: 0
[10] ['+', '*']: 0
[11] ['+', '*', '=', '*']: 0
[12] ['+', '*', '<', '*']: 0
[13] ['+', '*', '<', '*', '!', '*']: 0
[14] ['>', '*']: 0
[15] ['>', '*', '=', '*']: 0
[16] ['>', '*', '<', '*']: 0
[17] ['>', '*', '<', '*', '!', '*']: 0
[18] ['*', '>']: 0
[19] ['#', '*']: 0
語句結構
除了空格會被直接忽略,可以為每種語句結構實現一個類,即實現19個類.
class PlaceHoder:def __init__(line):line.content = ""class Comment:def __init__(line, p1):line.content = (p1)class Element:def __init__(line, p1):line.content = (p1)class Rail:def __init__(line, p1, p2):line.content = (p1, p2)class ReferenceDefination1:def __init__(line, p1):line.content = (p1)class ReferenceDefination2:def __init__(line, p1, p2):line.content = (p1, p2)class ReferenceDefination3:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class ReferenceImpletement1:def __init__(line, p1, p2):line.content = (p1)class ReferenceImpletement2:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class Category1:def __init__(line, p1):line.content = (p1)class Category2:def __init__(line, p1, p2):line.content = (p1, p2)class Category3:def __init__(line, p1, p2):line.content = (p1, p2)class Category4:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class AggregateDefination1:def __init__(line, p1):line.content = (p1)class AggregateDefination2:def __init__(line, p1, p2):line.content = (p1, p2)class AggregateDefination3:def __init__(line, p1, p2):line.content = (p1, p2)class AggregateDefination4:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class AggregateImpletement1:def __init__(line, p1, p2):line.content = (p1)class Import:def __init__(line, p1):line.content = (p1)
然后呢,要給這些行創建實例.
我看這個長度是固定的,能到6,所以做個分支結構敷衍了事,要改以后該.
先做個骨架.
def get_ins(line_list):lenth = len(line_list)if lenth == 1:...elif lenth == 2:...elif lenth == 3:...elif lenth == 4:...elif lenth == 5:...elif lenth == 6:...
然后照著參考文檔一個一個匹配至實例.
def get_ins(line_list):ins = []for line in line_list:lenth = len(line)if lenth == 1:if line[0] == ':':ins.append(PlaceHoder())else:ins.append(Element(line[0]))elif lenth == 2:if line[0] == ':':ins.append(Comment(line[1]))elif line[0] == '<':ins.append(ReferenceDefination1(line[1]))elif line[0] == '>':ins.append(AggregateDefination1(line[1]))elif line[0] == '+':ins.append(Category1(line[1]))elif line[0] == '#':ins.append(Import(line[1]))else:ins.append(AggregateImpletement(line[0]))elif lenth == 3:if line[1] == "=":ins.append(Rail(line[0], line[2]))else:ins.append(ReferenceImpletement1(line[0], line[2]))elif lenth == 4:if line[0] == '+':if line[2] == '=':ins.append(Category2(line[1], line[3]))else:ins.append(Category3(line[1], line[3]))elif line[0] == '>':if line[2] == '=':ins.append(AggregateDefination2(line[1], line[3]))else:ins.append(AggregateDefination3(line[1], line[3]))else:ins.append(ReferenceDefination2(line[1], line[3]))elif lenth == 5:ins.append(ReferenceImpletement2(line[0], line[2], line[4]))elif lenth == 6:if line[0] == '<':ins.append(ReferenceDefination3(line[1], line[3], line[5]))elif line[0] == '+':ins.append(Category4(line[1], line[3], line[5]))else:ins.append(AggregateDefination4(line[1], line[3], line[5]))return ins
測試
使用之前構造的詞元列表進行檢查.
INS = get_ins(result)
for line in INS:print(line)
測試結果與預期一致.
本文的最終代碼如下.
def split_mul_ind(inp):word = ""line = [] result = []indent = 0indent_list = []ind_in = Truefor char in inp:if char =="\n":if word:line.append(word)word = ""if line:result.append(line)indent_list.append(indent)line = []indent = 0ind_in = Trueelif char == " ":if ind_in:indent += 1elif word:line.append(word)word = ""else:ind_in = Falseword += charif word: line.append(word)if line:result.append(line)indent_list.append(indent)return (result, indent_list)with (open("test.txt", 'r') as f):result, indent_list = split_mul_ind(f.read())def check(result, indent_list, n):print(f"{n+1} | {result[n]}: {indent_list[n]}")for i in range(19):check(result, indent_list, i)def __init__(line):line.content = ""class PlaceHoder:def __init__(line):passclass Comment:def __init__(line, p1):line.content = (p1)class Element:def __init__(line, p1):line.content = (p1)class Rail:def __init__(line, p1, p2):line.content = (p1, p2)class ReferenceDefination1:def __init__(line, p1):line.content = (p1)class ReferenceDefination2:def __init__(line, p1, p2):line.content = (p1, p2)class ReferenceDefination3:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class ReferenceImpletement1:def __init__(line, p1, p2):line.content = (p1, p2)class ReferenceImpletement2:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class Category1:def __init__(line, p1):line.content = (p1)class Category2:def __init__(line, p1, p2):line.content = (p1, p2)class Category3:def __init__(line, p1, p2):line.content = (p1, p2)class Category4:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class AggregateDefination1:def __init__(line, p1):line.content = (p1)class AggregateDefination2:def __init__(line, p1, p2):line.content = (p1, p2)class AggregateDefination3:def __init__(line, p1, p2):line.content = (p1, p2)class AggregateDefination4:def __init__(line, p1, p2, p3):line.content = (p1, p2, p3)class AggregateImpletement:def __init__(line, p1):line.content = (p1)class Import:def __init__(line, p1):line.content = (p1)def get_ins(line_list):ins = []for line in line_list:lenth = len(line)if lenth == 1:if line[0] == ':':ins.append(PlaceHoder())else:ins.append(Element(line[0]))elif lenth == 2:if line[0] == ':':ins.append(Comment(line[1]))elif line[0] == '<':ins.append(ReferenceDefination1(line[1]))elif line[0] == '>':ins.append(AggregateDefination1(line[1]))elif line[0] == '+':ins.append(Category1(line[1]))elif line[0] == '#':ins.append(Import(line[1]))else:ins.append(AggregateImpletement(line[0]))elif lenth == 3:if line[1] == "=":ins.append(Rail(line[0], line[2]))else:ins.append(ReferenceImpletement1(line[0], line[2]))elif lenth == 4:if line[0] == '+':if line[2] == '=':ins.append(Category2(line[1], line[3]))else:ins.append(Category3(line[1], line[3]))elif line[0] == '>':if line[2] == '=':ins.append(AggregateDefination2(line[1], line[3]))else:ins.append(AggregateDefination3(line[1], line[3]))else:ins.append(ReferenceDefination2(line[1], line[3]))elif lenth == 5:ins.append(ReferenceImpletement2(line[0], line[2], line[4]))elif lenth == 6:if line[0] == '<':ins.append(ReferenceDefination3(line[1], line[3], line[5]))elif line[0] == '+':ins.append(Category4(line[1], line[3], line[5]))else:ins.append(AggregateDefination4(line[1], line[3], line[5]))return insINS = get_ins(result)
for line in INS:print(line)