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.

90 lines
3.6 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):
self.operations = {"=": self.Define.assign,
"+=": self.Define.append,
"-=": self.Define.remove}
lbrack = Literal("[")
rbrack = Literal("]")
# comma = Literal(",").suppress()
comment_symbol = Literal(';') | Literal('#')
# Define = self.Define
value_operation = (Literal("=") | Combine(Literal("+") + Literal("="))
| Combine(Literal("-") + Literal("=")))
comment = comment_symbol + Optional(restOfLine)
section_name = Word(printables+'\t', excludeChars='[]')
value_name = Word(printables+'\t', excludeChars='=-+')
# non_comma = Word(printables+'\t', excludeChars=',')
clear_section = lbrack.suppress() + Group(empty) + rbrack.suppress()
section_start = Group(OneOrMore(lbrack.suppress() + section_name
+ rbrack.suppress())
+ (clear_section | ~lbrack())
+ LineEnd().suppress())
# Если содержимое ini-файла не предваряется заголовком секции,
# значит эта строка ошибочна.
unexpected = Group(~section_start + SkipTo(LineEnd(),
include=True))("error")
unexpected.setParseAction(self._unexpected_token)
key_value = (~lbrack + value_name
+ value_operation + empty
+ restOfLine + LineEnd().suppress())
def strip_key_value(tokens):
tokens[0] = tokens[0].strip()
tokens[1] = tokens[1].strip()
key_value.setParseAction(strip_key_value)
self.ini_section_parser = (section_start
+ Group(ZeroOrMore(
Group(key_value | unexpected)))
| unexpected)
self.ini_section_parser.ignore(comment)
def _unexpected_token(self, string, location, tokens):
'''Метод вызываемый парсером, если обнаружена некорректная строка,
предназначен для получения некорректной строки и ее дальнейшего
разбора.'''
error_line = line(location, string).strip()
if error_line:
return (error_line, lineno(location, string),
col(location, string))
def parse(self, data):
for tokens, start, end in self.ini_section_parser.scanString(data):
if tokens.getName() == "error":
print('error tokens: {}'.format(tokens))
yield {'error': tokens}
section, defkeys = tokens
section_list = section.asList()
if section_list[-1] == []:
self.clear_section(section_list[:-1])
yield {'clear_section': (section_list[:-1], )}
self.start_section(section.asList())
for defkey in defkeys:
yield {'define_key': (section.asList(), defkey[0], defkey[2],
self.operations[defkey[1]])}