Первый шаг - написать BNF.Вы уже начали думать об этом, когда вы написали: Мне нужно взять ключ словаря в качестве первичного ключа, а затем я могу иметь одно или несколько значений в качестве столбцов, сначала у меня всегда есть имя переменной, а затемтип переменной.
Преобразуйте это во что-то более формальное:
class_definition :: '@Class' identifier class_body
class_body :: class_dict // can add other types here as necessary
class_dict :: 'dict' '<' '<' identifier ':' value_type '>' ','
column_decl [',' column_decl]... '>'
column_decl :: identifier ':' value_type
value_type :: 'int' | 'str' | 'atomicint'
Хммм, identifier : value_type
в нескольких местах, назовем это var_decl
и перепишем.Кроме того, я думаю, что вы можете иметь составные первичные ключи, определяя разделенный запятыми список внутри <>
s, и мы используем этот вид списка в нескольких местах.Перезапись:
class_definition :: '@Class' identifier class_body
class_body :: class_dict // can add other types here as necessary
class_dict :: 'dict' '<' '<' vars_decl '>' ',' vars_decl '>'
vars_decl :: var_decl [',' var_decl]...
var_decl :: identifier ':' value_type
value_type :: 'int' | 'str' | 'atomicint'
Затем работайте снизу вверх, чтобы определить их в терминах переноса:
import pyparsing as pp
S = pp.Suppress
identifier = pp.pyparsing_common.identifier
value_type = pp.oneOf("int str atomicint")
var_decl = pp.Group(identifier + S(":") + value_type)
vars_decl = pp.Group(pp.delimitedList(var_decl))
dict_decl = pp.Group(S("dict") + S("<")
+ S("<") + vars_decl + S(">") + S(",")
+ vars_decl
+ S(">"))
class_decl = pp.Group('@Class' + identifier + dict_decl)
И, наконец, добавьте имена результатов, чтобы можно было выбирать разные фрагменты.после разбора легче:
import pyparsing as pp
S = pp.Suppress
identifier = pp.pyparsing_common.identifier
value_type = pp.oneOf("int str atomicint")
var_decl = pp.Group(identifier("name") + S(":") + value_type("type"))
vars_decl = pp.Group(pp.delimitedList(var_decl))
dict_decl = pp.Group(S("dict") + S("<")
+ S("<") + vars_decl("primary_key") + S(">") + S(",")
+ vars_decl("columns")
+ S(">"))
class_decl = pp.Group('@Class'
+ identifier("class_name")
+ dict_decl("class_body"))
Затем проанализируйте ваш текст, используя:
class_definitions = pp.OneOrMore(class_decl).parseString(comment)
И распечатайте то, что вы получили:
print(class_definitions.dump())
Или даже лучше:
class_decl.runTests(comment)
Это совершенно не проверено, может быть, там нет единого мнения, но это общая идея.Но даже если вы в конечном итоге используете что-то кроме pyparsing, начните с BNF .Это действительно поможет прояснить ваше мышление и общую концепцию проблемы.