@TOC
前言
本文只作为笔记记录。
TinText开源地址:https://github.com/Smart-Space/TinText
语法解析器
从前文可以看到,新的Tin标记语言非常简单,即便是加入嵌套关系,也只是标签级别做个标记就行了。(在写这篇文章的时候,新版Tin语法解析器还没有重写到能够解析嵌套标签的程度,但是很简单,就像下文所说)
比如:
<pass>#pass-content1
...
<pass>#pass-content2
...
<pass>#pass-content2
...
</pass>#pass-content1
好了,话不多说,虽然接下来也没有多少话。
正则匹配
class TinParser():
"""
tin标记解析模块
"""
ver='V-4'
def __init__(self):
#<tag>, -, |, |-, [空]
self.tin_re=re.compile('[ ]{0,}(<.*?>|-|\\|-|\\||)(.*)')
self.tag_start_attrs_tuple=('|','-')
#特殊标记|,-,;
我们创建了一个名为TinParser的语法解析器,并且预编译了语法正则匹配self.tin_re
。
接下来的流程思路大致如下:
具体实现:
def parse(self,tin):
#分析
TAGATTR=False#标签参数注入,用于多行表达
line_count=0#行数
for line in tin.split('\n'):
line_count+=1
if line=='':
continue
if line.startswith('|-'):
#注释
continue
unit=self.tin_re.match(line)
if unit==None:#无法匹配
err=f"无法匹配的tin标记[{line_count}]:\n{line}"
yield TagNoMatch(err)
break
unit=unit.groups()
if unit[1].endswith(';'):#开启多行表达
if TAGATTR:
err=f"重复使用多行表达标记[{line_count}]:\n{line}\n上方标签的多行表达未结束"
yield AlreadyStartLine(err)
TAGATTR=True
tagattrs=list()
tagattrs.append(line_count)
tagattrs.append(unit[0])
tagattrs.append(unit[1][:-1])
continue
if TAGATTR and (unit[0] not in self.tag_start_attrs_tuple):
#多行表达标签没有正确的后续标记
err=f"多行表达错误[{line_count}]:\n{line}\n多行表达缺少结束标记,或者更改上方标签为单行表达\n多行表达开始于[{tagattrs[0]}]"
yield NoLinesMark(err)
break
if unit[0] in self.tag_start_attrs_tuple:#多行表达
if not TAGATTR:
#TAGATTR:False时,提出警告
err=f"标记未使用多行表达,但出现了多行表达的参数[{line_count}]:\n{line}\n请检查上方标记参数末尾是否有\";\""
yield NoLinesMode(err)
break
if unit[1].endswith('|'):#多行表达结束
TAGATTR=False
tagattrs.append(unit[1][:-1])
yield tuple(tagattrs)
del tagattrs
continue
tagattrs.append(unit[1])
continue
attrs=unit[1].split('|')
rattrs=list()#result attrs
for i in attrs:
#对已经获得的参数值进行特殊标记文本转义,这可能降低效率,目前没有好的方法
rattrs.append(i.replace('%VEB%','|'))
yield line_count,unit[0],*rattrs
这里使用了yield
输出,就是为了能够即时解析,同时加快与渲染器的解释与渲染效率,因为接下来的渲染器的解释与渲染是通过for循环实现的。