from pyparsing import * class Polyp: # BuiltinFunction = Keyword("Render") Point = Literal('.') e = CaselessLiteral('E') PlusOrMinus = Literal('+') | Literal('-') Number = Word(nums) Integer = Combine( Optional(PlusOrMinus) + Number ) Float = Combine( Integer + Optional( Point + Optional(Number) ) + Optional( e + Integer ) ) String = quotedString Comment = cppStyleComment Identifier = Forward() Identifier << (Word(alphas, alphanums + '_') + ZeroOrMore(':' + Identifier)) Variable = Word(alphas, alphanums + '_') PrimaryExpr = Forward() UnaryExpr = Forward() Expr = Forward() Expression = Forward() MathOperator = oneOf("+ - * / % ^ **") RelationOperator = oneOf("= != < > <= >= <>") UnaryOperator = oneOf("+ - ! ~") LogicalOperator = oneOf("& |") BinaryOperator = RelationOperator | MathOperator VariableList = delimitedList(Variable) ExpressionList = delimitedList(Expression) Operand = Integer | Float | Identifier | String UnaryExpr << ((UnaryOperator + UnaryExpr) | PrimaryExpr | nestedExpr(content=PrimaryExpr) ) Expr << ( UnaryExpr + ZeroOrMore(BinaryOperator + Expr) ) Expression << ( ( (Expr | nestedExpr(content=Expr) ) + ZeroOrMore( LogicalOperator + ( Expr | nestedExpr(content=Expr) ) ) ) | nestedExpr(content=Expression) ) Call = Identifier + Suppress("(") + ExpressionList + Suppress(")") ParameterList = delimitedList(Variable) Parameters = Suppress("(") + Optional(ParameterList) + Suppress(")") Function = Identifier + Parameters VariableDeclaration = Optional(Suppress(Keyword("var"))) + VariableList + Suppress(":=") + ExpressionList FunctionDeclaration = Optional(Suppress(Keyword("def"))) + Function + Suppress(":=") + ( nestedExpr(content=Expression) | Expression) Declaration = VariableDeclaration | FunctionDeclaration PrimaryExpr << (Call | Operand) Statement = Declaration | Call EndOfStatement = Suppress(";") Polyps = OneOrMore(Statement + EndOfStatement) + StringEnd() Polyps.ignore(Comment) def __init__(self): self.FunctionDeclaration.setParseAction(self.FunctionRegister) self.VariableDeclaration.setParseAction(self.VariableRegister) self.EndOfStatement.setParseAction(self.StatementEnd) self.Call.setParseAction(self.CallAction) self.VariableTable = {} # Contains bound variables (lazy evaluation) self.FunctionTable = {} # Contains defined functions (lazy evaluation :) self.StatementEnd() def StatementEnd(self, s = None, loc = None, toks = None): self.function_registration = False self.variable_registration = False def CallAction(self, s, loc, toks): print "Call to '%s'" % toks[0] def FunctionRegister(self, s, loc, toks): print "Registering Function:", toks[0] self.function_registration = True FunctionName = toks[0] FunctionTrace = toks[1:] self.FunctionTable[FunctionName] = [FunctionTrace] def VariableRegister(self, s, loc, toks): print "Registering Variable:", toks[0] self.variable_registration = True self.VariableTable[toks[0]] = None def Identifier(self, s, loc, toks): if self.function_registration or self.variable_registration: pass else: if not self.VariableTable.has_key(toks[0]): print "Unresolved variable at ", loc def Parse(self, string, given_table={}): self.VariableTable.clear() self.VariableTable.update(given_table) self.FunctionTable.clear() try: print "Parsing string '%s':" % string self.Polyps.parseString(string) except ParseException, E: print "Polyps: Parse error: ", E print string print (" " * E.loc) + "^" print E.parserElement return def ParseFile(self, file, given_table={}): self.VariableTable.clear() self.VariableTable.update(given_table) self.FunctionTable.clear() try: print "Parsing file '%s':" % file self.Polyps.parseFile(file) except ParseException, E: print "Polyps: Parse error: ", E print (" " * E.loc) + "^" # print print E.parserElement return p = Polyp() # parse("Foostring := \"Foo\";") # (x < a+s) & (x > a-s) & (y < b+s) & (y > b-s) & (z < c+s) & (z > c-s);") p.Parse("""Cube(a, b, c, s) := (x < a+s) & (x > a-s) & (y < b+s) & (y > b-s) & (z < c+s) & (z > c-s);""") # p.Parse("var MyVar := 3;") p.ParseFile("howdy.polyp")