0

So I have a problem I'm trying to solve in which I have two fundamental classes CMIX and C, whereby CMIX contains a list of instances of C: [C1, C2, .... Cn] which will be manipulated by a custom grammar (string values operators - "+", "-", "", "(", ")", but in the sense that there is the ability to embed extra logic into operations. For example, a [C1 + C2 + ... + Cn] composition would call C.foo() for each C1,C2,...Cn, and then add those results. Similarly, a composition of grammar terms with the object set, e.g.: [C1 "" "(" C1 "+" C2 "*" "("C2"+"C2")"")"] would call C1.foo(), C2.foo(), and then combine those results according to normal mathematical evaluation. Initially, I just want to deal with basic math operations like * + ( ) but would like to be able to extend it later for custom (non math) terms .

A basic representative sketch of the class functionality is as follows (this is mainly conceptual; especially the CMIX, as I'm unsure of the best way to go about the parsing syntax logic)

class CMIX():
   self.C_list = []  # List of instances of type C
   self.grammar = []
   def my_val(self, val):
      ## call every .foo(val=val) in self.C_list, and apply the grammar rules accordingly.

class C():
   def __init__(self, location):
      self.location= location
   def my_val(self, val):
      return val * 2 
   def check_location(self):
      if self.location == "antarctica":
         return "cold"
      elif self.location == "moon":
         return "bouncy"
      else:
         return "lost"

for example, say we have defined the global grammar operator

+ means if C.check_location() == "lost" then return -100*C.my_val(val) otherwise just return C.m

the grammar said C1 + C2, and C1.location="lost", C2.location="antarctica", then CMIX.my_val(20) would evaluate like: -100*C1.my_val(20) + C2.my_val(20)

Is there an existing easy way to do this in python? Or perhaps a lightweight library that allows one to create such evaluation rules. I have found for instance https://github.com/pydata/numexpr however this applies directly onto datatypes, whereas it should apply onto the object layer, apply custom logic, and then execute the standard math grammar order of operations.

Any direction for trying to do this is greatly appreciated! regards

undercurrent
  • 285
  • 1
  • 2
  • 12
  • 1
    It's not really clear what you're asking although perhaps what you're looking for is operator overloading. – pvg Jun 04 '17 at 01:45
  • Where is this "grammar" coming from, and why do you call it a grammar? It doesn't seem to have much to do with parsing or grammars. It sounds like you could just have the "grammar" be a function. – user2357112 Jun 04 '17 at 01:47
  • @user2357112 A grammar in the sense that one has a defined set of operations, each of which performs the same task on the same item type. Is this not what a grammar is - a set of rules that determine how certain things compose with one another. In this case that thing is a class, and the structured rule set is mathematical operations on top of another layer of (consistent) logic. A function is merely part of a grammar. Mathematical evaluation has its own grammar. I'm wondering is there an existing solution so I don't re-invent the wheel. Perhaps https://fdik.org/pyPEG/ – undercurrent Jun 04 '17 at 03:05
  • @pvg This is an option, and I may have to use it for now however would prefer something that is not necessarily limited to existing operators – undercurrent Jun 04 '17 at 03:07
  • Well. I sounds like you want some sort of expression parser but it's not really clear exactly what you have in mind. You might want to update your question with more specifics and examples. @user2357112 is right that your use of 'grammar' is somewhat confusing and unorthodox. – pvg Jun 04 '17 at 03:09
  • "A grammar in the sense that one has a defined set of operations, each of which performs the same task on the same item type" - nope, that's not what a grammar is at all. – user2357112 Jun 04 '17 at 03:23
  • @user2357112 Well, then please enlighten us with some wisdom which you clearly have. It would be great if you could put this wisdom in the context of https://en.wikipedia.org/wiki/Formal_grammar , https://en.wikipedia.org/wiki/Principle_of_compositionality , https://en.wikipedia.org/wiki/Formal_language – undercurrent Jun 04 '17 at 03:33
  • @pvg yep, i think you're correct this is what I want. I'm not sure if I have termed everything properly, however, but the wiki links above are where i'm coming from. Perhaps "object composition" makes more intuitive sense. Although I thought the example I gave above is reasonably clear? basically I want to extend common mathematical operations with some higher level logic (i.e. the object.foo() should be evaluated in accordance to mathematical order of operations parentheses first, multiply, sum etc – undercurrent Jun 04 '17 at 03:40
  • Well, to directly quote the intro of the Wikipedia article on formal grammars, "In formal language theory, a grammar (when the context is not given, often called a formal grammar for clarity) is a set of production rules for strings in a formal language. The rules describe how to form strings from the language's alphabet that are valid according to the language's syntax." That has pretty much nothing to do with what you're doing. If you received the string "C1 * (C1 + C2 * (C2+C2))" and you had to figure out what it meant, that would be a task for a grammar and a parser generator, but... – user2357112 Jun 04 '17 at 03:41
  • you haven't said anything about receiving strings, and you haven't said anything that would indicate that you need to receive strings. – user2357112 Jun 04 '17 at 03:43
  • @user2357112 "That has pretty much nothing to do with what you're doing. If you received the string "C1 * (C1 + C2 * (C2+C2))" " that's exactly what I want to do! Noted I definitely should have mentioned it would be to interpret strings (for the operators). Apologies – undercurrent Jun 04 '17 at 03:47
  • It still sounds like you're getting confused about which thing "grammar" refers to in this situation, and it's still not clear whether a string representation, a parser, or a grammar need to be involved at any point. More context would be useful. – user2357112 Jun 04 '17 at 04:03
  • Also, your operator examples don't seem to compose. For example, your `+` operator takes two C instances and produces what appears to be a number. You can't nest that, because the result would have to be a C instance instead of a number for that to work. – user2357112 Jun 04 '17 at 04:07
  • @user2357112 The + operator takes two C instances, but contained in CMIX class, and evaluated only when CMIX.my_val() is called. Since CMIX and C share the same function name that does the evaluation, at least in the pseudocode, to me it seems like they would nest ok? The most barebones analogy i can give is instead of y = x1 + x2 where x1=2, x1=4 giving y = 2 + 4 = 6, one would have y = x1 + x2 where x1 and x2 are type C, y is type CMIX. y.my_val(10) would then evaluate x.my_val(10), y.my_val(10), and then the results are added following normal math logic: x.my_val(10) + y.my_val(10) – undercurrent Jun 04 '17 at 04:20
  • 1
    Have you looked at [ply](http://www.dabeaz.com/ply/ply.html#ply_nn24)? – rici Jun 04 '17 at 05:44

1 Answers1

1

Pyparsing makes it pretty easy to define infix notation parsers, and can wrap operators and operands in classes to do standard or customized behavior. See this question and its pyparsing-based solution: pyparsing nestedExpr and nested parentheses

PaulMcG
  • 62,419
  • 16
  • 94
  • 130