You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
105 lines
3.3 KiB
105 lines
3.3 KiB
from pyparsing import (Literal, Word, ZeroOrMore, Group, Dict, Optional,
|
|
restOfLine, empty, printables, OneOrMore, oneOf, nums, lineno, line, col,
|
|
Keyword, SkipTo, LineEnd, Combine)
|
|
|
|
from enum import Enum
|
|
|
|
class CalculateIniParser:
|
|
"""
|
|
Парсер формата calculate.ini
|
|
"""
|
|
class Define(Enum):
|
|
Assign = 0
|
|
Append = 1
|
|
Remove = 2
|
|
|
|
def __init__(self):
|
|
lbrack = Literal("[").suppress()
|
|
rbrack = Literal("]").suppress()
|
|
|
|
comma = Literal(",").suppress()
|
|
commentStart = oneOf("; #")
|
|
Define = self.Define
|
|
valueOp = Literal("=") | Combine(
|
|
Literal("+") + Literal("=")) | Combine(
|
|
Literal("-") + Literal("="))
|
|
|
|
comment = commentStart + Optional( restOfLine)
|
|
|
|
nonrbrack = "".join( [c for c in printables if c != "]" ]) + " \t"
|
|
nonvalueop = "".join( [c for c in printables if c not in {"=","-","+"} ]) + " \t"
|
|
noncomma = "".join( [c for c in printables if c != "," ])
|
|
clearsection = lbrack + Group(empty) + rbrack
|
|
|
|
sectionDef = Group(OneOrMore(lbrack + Word(nonrbrack) + rbrack)
|
|
+ (clearsection | ~lbrack ) + LineEnd().suppress())
|
|
|
|
unexpected = Group(~sectionDef + SkipTo(LineEnd(), include=True))("error")
|
|
unexpected.setParseAction(self._unexpected_token)
|
|
|
|
keyDef = ~lbrack + Word(nonvalueop) + valueOp + empty + restOfLine + LineEnd().suppress()
|
|
|
|
def stripKeyValue(tokens):
|
|
tokens[0] = tokens[0].strip()
|
|
tokens[1] = tokens[1].strip()
|
|
|
|
keyDef.setParseAction(stripKeyValue)
|
|
|
|
self.inibnf = sectionDef + Group(ZeroOrMore(Group(keyDef | unexpected))) | unexpected
|
|
self.inibnf.ignore( comment )
|
|
|
|
def _unexpected_token(self, st, locn, tokString):
|
|
erline = line(locn,st).strip()
|
|
if erline:
|
|
self.parseError(erline,
|
|
lineno(locn,st),
|
|
col(locn,st))
|
|
|
|
def parse(self, data):
|
|
for tokens,start,end in self.inibnf.scanString(data):
|
|
if tokens.getName() == "error":
|
|
continue
|
|
section, defkeys = tokens
|
|
sectionList = section.asList()
|
|
if sectionList[-1] == []:
|
|
self.clearSection(sectionList[:-1])
|
|
continue
|
|
self.startSection(section.asList())
|
|
for defkey in defkeys:
|
|
if defkey.getName() == "error":
|
|
continue
|
|
mapOp = {"=": self.Define.Assign,
|
|
"+=": self.Define.Append,
|
|
"-=": self.Define.Remove }
|
|
self.defineKey(section.asList(),
|
|
defkey[0], defkey[2],
|
|
mapOp[defkey[1]])
|
|
|
|
def startSection(self, section):
|
|
"""
|
|
Начало секции
|
|
"""
|
|
|
|
def clearSection(self, section):
|
|
"""
|
|
Очистка значений секции
|
|
"""
|
|
|
|
def defineKey(self, section, defkey, defval, deftype):
|
|
"""
|
|
Определение ключа
|
|
|
|
['section','block'] 'varname', 'varval', Define.Assign
|
|
"""
|
|
pass
|
|
|
|
def parseError(self, line, lineno, col):
|
|
"""
|
|
Ошибка в формате
|
|
|
|
line - пример строки
|
|
lineno - номер строки
|
|
col - номер символа
|
|
"""
|
|
pass
|