from parcon import number, Forward, InfixExpr import operator expr = Forward() term = number[float] | "(" + expr + ")" term = InfixExpr(term, [("*", operator.mul), ("/", operator.truediv)]) term = InfixExpr(term, [("+", operator.add), ("-", operator.sub)]) expr << term(name="expr") print expr.parse_string("1+2") # prints 3 print expr.parse_string("1+2+3") # prints 6 print expr.parse_string("1+2+3+4") # prints 10 print expr.parse_string("3*4") # prints 12 print expr.parse_string("5+3*4") # prints 17 print expr.parse_string("(5+3)*4") # prints 32 print expr.parse_string("10/4") # prints 2.5
m_keywords = m_and | m_or | m_not m_identifier = W(alphanum_chars + alphas8bit + '_', init_chars=alpha_chars + alphas8bit + '_') - m_keywords m_identifier = m_identifier(name='NAME') test('m_identifier', ''' a abc _abc abc1 ''') m_expression = Forward() m_infix_operator = m_logical_operator(name='⧽X⧼') m_prefix_operator = m_not m_subexpression = '(' + m_expression + ')' m_term = m_literal | (m_identifier) | (m_subexpression) m_expression_tail = Forward() m_infix_expression = m_term + m_expression_tail m_expression_tail << ((m_infix_operator + m_expression + m_expression_tail) | (Return(None))) """ m_infix_expression = ( | (m_term + m_infix_operator + m_expression) | (m_expression + m_infix_operator + m_term) )
return None @rule(identifier[1]) def anyIdentifier(_): """Matches any identifier.""" return None @rule(sp(1) + ':' + sp(1) + className + (',' + sp(1) + className)[...]) def baseClasses(value): """List of base classes.""" return justErrors(value) filePart = Forward() # Breaking naming scheme to match functions. # pylint: disable=C0103 @rule(Literal('@end')) def end(_): """End of an interface, protocol, or implementation.""" return None @rule(First('long', 'short') + ' ' + xsp) def cTypeSizeModifier(value): """A type size modifier.""" return justErrors(value) @rule(Regex(r'((signed|unsigned)\s+)?((long|short)\s+){0,2}(long|int|double|float|short)\b'))
return expressions.ApplyExpression("plus", [left, right]) def make_minus_expression(left, right): """simple post-parsing creation method for subtract expressions""" return expressions.ApplyExpression("minus", [left, right]) def make_times_expression(left, right): """simple post-parsing creation method for multiply expressions""" return expressions.ApplyExpression("times", [left, right]) def make_divide_expression(left, right): """simple post-parsing creation method for divide expressions""" return expressions.ApplyExpression("divide", [left, right]) def make_power_expression(left, right): """simple post-parsing creation method for power expressions""" return expressions.ApplyExpression("power", [left, right]) expr = Forward() argument_list = Optional(create_separated_by(expr, ",")) # This way seems to work, provided in 'term' we have apply_expr # before name_expr. We could also try something like: # apply_expr = parcon.alpha_word + Optional("(" + argument_list + ")) # provided we can then interpret the result correctly, in particular # we must make sure that "h()" is different from "h", the former being # an application of the function h to no arguments and the latter being # just a name expression referencing the 'h' variable. # # Note also that parcon.alphanum_word may be incorrect here, it should # be alphchar followed by alphanum_word, or something like that. variable_name = parcon.Word(parcon.alphanum_chars + "_",
if not value[0].islower(): return Error('BadParameterName', 'Parameter names must not be capitalized', position, LINES) return None @rule(sp(1) + ':' + sp(1) + className + (',' + sp(1) + className)[...]) def baseClasses(value): """List of base classes.""" return justErrors(value) @rule('(' + -anyIdentifier + ')') def category(value): return justErrors(value) filePart = Forward() # Breaking naming scheme to match functions. # pylint: disable=C0103 @rule(Literal('@end')) def end(_): """End of an interface, protocol, or implementation.""" return None @rule(First('long', 'short') + ' ' + xsp) def cTypeSizeModifier(value): """A type size modifier.""" return justErrors(value) @rule(Regex(r'((signed|unsigned)\s+)?((long|short)\s+){0,2}(long|int|double|float|short)\b'))
def parse_newick(text): import operator from parcon import Alpha, Digit, ZeroOrMore, Optional, Forward, OneOrMore, Longest, flatten, InfixExpr, CharIn labels = {} class ZNode(object): def __init__(self, label=None, length=None): self.label = label self.length = length self.children = [] self.parent = None def add_child(self, node): node.parent = self self.children.append(node) def ancestors(self): pairs = [(self, 0)] node = self while node.parent: pairs.append((node.parent, pairs[-1][1] + 1)) node = node.parent return pairs def __str__(self): return "{}[{}]:{}".format(self.label, ''.join(map(str, self.children)), self.length) def __repr__(self): s = "<%s" % (self.label or "?", ) if self.children: s += " " + ", ".join(map(repr, self.children)) s += ">" return s def make_leaf(ast): # print "leaf ast", ast label = ast node = ZNode(label=label) if label: labels[label] = node return node def make_internal(ast): # print "internal ast", ast if isinstance(ast[0], ZNode): node = ZNode() children = ast else: label = ast[-1] node = ZNode(label=label) if label: labels[label] = node children = ast[-2] for n in children: node.add_child(n) return node def test(args): # print "matched:", args return args Name = ZeroOrMore(Alpha() | CharIn("_"))[''.join] Leaf = Name Node = Forward() Internal = ("(" + InfixExpr(Node[lambda x: [x]], [(",", operator.add)]) + ")") + Optional(Name) Node << (Internal[make_internal] | Leaf[make_leaf]) Tree = Node + ";" return Tree.parse_string(text), labels
VALUE_CHAR_REGEX = u"[\u0020\u0021\u0023-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\u10000-\u10FFFF]+" compare_op = (SL(">=") | SL("<=") | SL(">") | SL("<") | SL("eq"))(name="compare_op") attr_name = Word(string.letters + string.digits + "_" + "-" + ".")(desc="attribute") value = Expected(Regex(VALUE_CHAR_REGEX), "value")(desc="value") bare_value = UntilRegex(u"\s*(?:\sor\s|\sand\s|[)(])", flags=re.IGNORECASE | re.UNICODE) | value # may end with or | and | ( | ) maybe_quoted = (L('"') + value + L('"')) | bare_value attr_match = (attr_name + "=" + maybe_quoted)(name="attr_match")[AttributeMatch.tup] full_match = (L("full") + "=" + maybe_quoted)(name="full_match")[FullMatch] schema_match = (L("schema") + "=" + maybe_quoted)(name="schema_match")[SchemaMatch] type_match = (L("objtype") + "=" + maybe_quoted)(name="type_match")[TypeMatch] fulltext_match = (L("fulltext") + "=" + maybe_quoted)(name="fulltext_match")[FulltextMatch] attr_compare = (attr_name + compare_op + maybe_quoted)(name="attr_compare")[AttributeCompare.tup] atom = (schema_match | type_match | fulltext_match | full_match | attr_match | attr_compare)(name="atom") expr = Forward() t = atom | "(" + expr + ")" t = InfixExpr(t, [(AC("and"), And)]) t = InfixExpr(t, [(AC("or"), Or)]) negated = (AC("not") + t)[Not] t = negated | t expr << t(name="search_expr") # expr is used for parsing the search language, name it `parser` to make it clearer ;) parser = expr