2

MongoDB から抽出されたデータを変換する単純な DSL に取り組んでいます。私は python と pyparsing を使用しており、提供された例から始めて、+/-* などの基本的な演算子で機能する文法の作成にかなりの距離を置いています。私は現在、自分のプログラムにフォームの関数を評価させる方法に固執していますRank[dbRef]。単純な演算子を使用して dbRefs を評価して算術演算を実行できますが、関数を評価する際の再帰で何かが機能していません。関数呼び出しで渡された dbRef 引数にアクセスする方法がわかりません。

文法と関連するものは次のsetParseActionsとおりです。

# Define parser, accounting for the fact that some fields contain whitespace
chars = Word(alphanums + "_-/")
expr = Forward()
integer = Word(nums).setParseAction(EvalConstant)
real = Combine(Word(nums) + "." + Word(nums)).setParseAction(EvalConstant)

# Handle database field references that are coming out of Mongo
dbRef = Combine(chars + OneOrMore(":") + chars)

dbRef.setParseAction(EvalDBref)

# Handle function calls
functionCall = (Keyword("Rank") | Keyword("ZS") | Keyword("Ntile")) + "[" + dbRef + "]"
functionCall.setParseAction(EvalFunction)
operand = (real | integer) | functionCall | dbRef 

signop = oneOf('+ -')
multop = oneOf('* /')
plusop = oneOf('+ -')

# Use parse actions to attach Eval constructors to sub-expressions

expr << operatorPrecedence(operand,
    [
     (signop, 1, opAssoc.RIGHT, EvalSignOp),
     (multop, 2, opAssoc.LEFT, EvalMultOp),
     (plusop, 2, opAssoc.LEFT, EvalAddOp),
    ])

formulas = ['Rank[Person:Height]']

for f in formulas:
    ret = expr.parseString(f)[0]
    print p + ": " + line + " --> " + str(ret.eval())

これが私の評価クラスに関連するコードです。クラスはパーサーによって呼び出されますが、関数に渡される引数にアクセスするにはどうすればよいですか?

# Executes functions contained in expressions
class EvalFunction(object): 
    def __init__(self, tokens): 
        self.value = tokens[0]
    def eval(self):
        func = self.value
        if func == 'Rank':
            # How to evaluate the token that is arg of Function?
            return 'Rank Found';

次の段階に進むには、正しい方向に微調整する必要があると思います..

4

1 に答える 1

1

私はこれを整理し、答えを提供したいと思いました。私の関数評価クラスは次のようになります。

# Executes functions contained in expressions
class EvalFunction(object):
  pop_ = {}
  def __init__(self, tokens):
    self.func_ = tokens.funcname
    self.field_ = tokens.arg
  def eval(self):
      # Get the name of the requested field and source db
      # Functions can only be called on dbRef so this always done
      v = self.field_.value
      fieldRef = v.split(':')
      source = fieldRef[0]
      field = fieldRef[1]

      # Evaluate the dbRef (get the value from the db)
      val = self.field_.eval()

      if self.func_ == 'Avg':
        rec = db['Stats'].find_one({'_id' : field})   
        return rec['value']['avg']
      elif self.func_ == 'Root':
          return math.sqrt(val)

私の関数の文法は次のとおりです。

functionCall = funcNames("funcname") + "[" + dbRef("arg") + "]"
functionCall.setParseAction(EvalFunction)
于 2012-12-03T19:39:55.270 に答える