def _parse_iden(self): ''' Handle identifier and function calls. ''' iden = self.__cur_tok.iden # eat identifier expression self._get_next_tok() if not self.__cur_tok or (not self.__cur_tok.iden == '(' and \ not self.__cur_tok.iden == '['): self.refs.append(iden) return ASTVarRef(iden) # eat '(' or '[' paren_char = self.__cur_tok.iden self._get_next_tok() # if we have a lookup... if paren_char == '[': arg = self._parse_expr() if not self.__cur_tok.iden == ']': err = 'Expected \']\' not \'%s\'' % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) self._get_next_tok() return ASTLookupRef(iden, arg) args = [] if self.__cur_tok.iden != ')': while True: arg = self._parse_expr() if not arg: return None args.append(arg) if self.__cur_tok.iden == ')': break if self.__cur_tok.iden != ',': err = 'Expected \',\' not \'%s\'' % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) self._get_next_tok() # eat the ')' self._get_next_tok() return ASTCallExpr(iden, args)
def _parse_iden(self): """ Handle identifier and function calls. """ iden = self.__cur_tok.iden # eat identifier expression self._get_next_tok() if not self.__cur_tok or (not self.__cur_tok.iden == "(" and not self.__cur_tok.iden == "["): self.refs.append(iden) return ASTVarRef(iden) # eat '(' or '[' paren_char = self.__cur_tok.iden self._get_next_tok() # if we have a lookup... if paren_char == "[": arg = self._parse_expr() if not self.__cur_tok.iden == "]": err = "Expected ']' not '%s'" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) self._get_next_tok() return ASTLookupRef(iden, arg) args = [] if self.__cur_tok.iden != ")": while True: arg = self._parse_expr() if not arg: return None args.append(arg) if self.__cur_tok.iden == ")": break if self.__cur_tok.iden != ",": err = "Expected ',' not '%s'" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) self._get_next_tok() # eat the ')' self._get_next_tok() return ASTCallExpr(iden, args)
def _parse_integ(self): """ Handle integral equations. Integrals look like this: integ ( expr, expr ) net flow---^ ^---initial value """ # eat 'integ' self._get_next_tok() if not self.__cur_tok or self.__cur_tok.iden != "(": err = "expected '(', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat '(' self._get_next_tok() net_flow = self._parse_expr() if not net_flow: return None if not self.__cur_tok or self.__cur_tok.iden != ",": err = "expected ',', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ',' self._get_next_tok() initial_val = self._parse_expr() if not initial_val: return None if not self.__cur_tok or self.__cur_tok.iden != ")": err = "expected ')', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ')' self._get_next_tok() # TODO: need to sort out assignment and intial self.valid = True self.kind = sim.STOCK self.net_flow = net_flow self.initial = ASTAssignExpr(self.__var.props.name, initial_val)
def _parse_integ(self): ''' Handle integral equations. Integrals look like this: integ ( expr, expr ) net flow---^ ^---initial value ''' # eat 'integ' self._get_next_tok() if not self.__cur_tok or self.__cur_tok.iden != '(': err = "expected '(', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat '(' self._get_next_tok() net_flow = self._parse_expr() if not net_flow: return None if not self.__cur_tok or self.__cur_tok.iden != ',': err = "expected ',', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ',' self._get_next_tok() initial_val = self._parse_expr() if not initial_val: return None if not self.__cur_tok or self.__cur_tok.iden != ')': err = "expected ')', not '%s' in integral" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ')' self._get_next_tok() # TODO: need to sort out assignment and intial self.valid = True self.kind = sim.STOCK self.net_flow = net_flow self.initial = ASTAssignExpr(self.__var.props.name, initial_val)
def _parse_primary(self): """ Handle identifiers, function calls and constants """ if self.__cur_tok.kind is lex.NUMBER: return self._parse_number() elif self.__cur_tok.kind is lex.IDENTIFIER: return self._parse_iden() else: err = "expected identifier or number, not '%s'" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok)
def _parse_primary(self): ''' Handle identifiers, function calls and constants ''' if self.__cur_tok.kind is lex.NUMBER: return self._parse_number() elif self.__cur_tok.kind is lex.IDENTIFIER: return self._parse_iden() else: err = 'expected identifier or number, not \'%s\'' % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok)
def _parse_paren(self): """ Handle parenthesis. """ # eat '(' self._get_next_tok(self) expr = self._parse_expr() if not expr: return None if self.__cur_tok.iden != ")": err = "expected ')', not '%s'" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ')' self._get_next_tok() return expr
def _parse_paren(self): ''' Handle parenthesis. ''' # eat '(' self._get_next_tok(self) expr = self._parse_expr() if not expr: return None if self.__cur_tok.iden != ')': err = 'expected \')\', not \'%s\'' % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # eat ')' self._get_next_tok() return expr
def _parse_unary(self): """ Handle unary operations. """ if self.__cur_tok.kind is not lex.OPERATOR: return self._parse_primary() elif self.__cur_tok.iden == "(": return self._parse_paren() # our only allowed binary operators are + and - if not self.__cur_tok.iden == "+" and not self.__cur_tok.iden == "-": err = "unexpected or unknown unary operator: %s" % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # get our operator then eat the token op = self.__cur_tok.iden self._get_next_tok() lval = self._parse_unary() if lval: return ASTUnaryExpr(op, lval)
def _parse_unary(self): ''' Handle unary operations. ''' if self.__cur_tok.kind is not lex.OPERATOR: return self._parse_primary() elif self.__cur_tok.iden == '(': return self._parse_paren() # our only allowed binary operators are + and - if not self.__cur_tok.iden == '+' and not self.__cur_tok.iden == '-': err = 'unexpected or unknown unary operator: %s' % self.__cur_tok.iden return report_eqn_error(err, self.__var, self.__cur_tok) # get our operator then eat the token op = self.__cur_tok.iden self._get_next_tok() lval = self._parse_unary() if lval: return ASTUnaryExpr(op, lval)
def get_tok(self): ''' Gets the next token from the scanner, or None if at end of equation ''' eqn = self.__eqn while self.__pos < self.__len: # skip whitespace if eqn[self.__pos].isspace(): self.__pos += 1 continue # check for identifiers if eqn[self.__pos].isalpha(): start = self.__pos while self.__pos < self.__len: if eqn[self.__pos].isalpha() or eqn[self.__pos].isdigit() or \ eqn[self.__pos] == '_': self.__pos += 1 else: break iden = eqn[start:self.__pos] tok = Token(start, self.__pos-start, IDENTIFIER, iden) # if this identifier is a language construct we # update the token type. self.__promote_identifier(tok) return tok # next check for numbers elif eqn[self.__pos].isdigit() or eqn[self.__pos] == '.': # keep track of how many decimals we have, SHOULD only be 1 num_decimals = 0 start = self.__pos while self.__pos < self.__len: if eqn[self.__pos].isdigit() or eqn[self.__pos] == '.': if eqn[self.__pos] == '.': num_decimals += 1 self.__pos += 1 else: break num = eqn[start:self.__pos] tok = Token(start, self.__pos-start, NUMBER, num) if num_decimals > 1: err = 'more than one decimal in number' return report_eqn_error(err, self.__var, tok) if not tok.error: tok.val = float(num) return tok else: if OPERATORS.find(eqn[self.__pos]) is -1: err = '\'%s\' (%d) is not a valid operator' % \ (eqn[self.__pos], self.__pos) return report_eqn_error(err, self.__var, tok) tok = Token(self.__pos, 1, OPERATOR, eqn[self.__pos]) self.__pos += 1 return tok
def get_tok(self): """ Gets the next token from the scanner, or None if at end of equation """ eqn = self.__eqn while self.__pos < self.__len: # skip whitespace if eqn[self.__pos].isspace(): self.__pos += 1 continue # check for identifiers if eqn[self.__pos].isalpha(): start = self.__pos while self.__pos < self.__len: if eqn[self.__pos].isalpha() or eqn[self.__pos].isdigit() or eqn[self.__pos] == "_": self.__pos += 1 else: break iden = eqn[start : self.__pos] tok = Token(start, self.__pos - start, IDENTIFIER, iden) # if this identifier is a language construct we # update the token type. self.__promote_identifier(tok) return tok # next check for numbers elif eqn[self.__pos].isdigit() or eqn[self.__pos] == ".": # keep track of how many decimals we have, SHOULD only be 1 num_decimals = 0 start = self.__pos while self.__pos < self.__len: if eqn[self.__pos].isdigit() or eqn[self.__pos] == ".": if eqn[self.__pos] == ".": num_decimals += 1 self.__pos += 1 else: break num = eqn[start : self.__pos] tok = Token(start, self.__pos - start, NUMBER, num) if num_decimals > 1: err = "more than one decimal in number" return report_eqn_error(err, self.__var, tok) if not tok.error: tok.val = float(num) return tok else: if OPERATORS.find(eqn[self.__pos]) is -1: err = "'%s' (%d) is not a valid operator" % (eqn[self.__pos], self.__pos) return report_eqn_error(err, self.__var, tok) tok = Token(self.__pos, 1, OPERATOR, eqn[self.__pos]) self.__pos += 1 return tok