Exemplo n.º 1
0
    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)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
 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)
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    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)
Exemplo n.º 6
0
    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