def rpn_parse(text: str) -> List[expr.Expr]: """Parse text in reverse Polish notation into a list of expressions (exactly one if the expression is balanced). Example: rpn_parse("5 3 + 4 * 7") => [ Times(Plus(IntConst(5), IntConst(3)), IntConst(4)))), IntConst(7) ] May raise: IndexError (imbalanced expression), lex.LexicalError. """ tokens = lex.TokenStream(io.StringIO(text)) stack = [] while tokens.has_more(): tok = tokens.take() if tok.kind == lex.TokenCat.INT: stack.append(expr.IntConst(int(tok.value))) elif tok.kind in BINOPS: binop_class = BINOPS[tok.kind] right = stack.pop() left = stack.pop() stack.append(binop_class(left, right)) elif tok.kind in UNOPS: unop_class = UNOPS[tok.kind] left = stack.pop() stack.append(unop_class(left)) elif tok.kind == lex.TokenCat.ASSIGN: right = stack.pop() left = stack.pop() # Reverse left and right stack.append(expr.Assign(right, left)) elif tok.kind == lex.TokenCat.VAR: stack.append(expr.Var(tok.value)) else: print('oops') return stack
def _stmt(stream: TokenStream) -> expr.Expr: """ # stmt ::= assign | loop | ifstmt | printstmt assignment ::= IDENT '=' expression ';' """ if stream.peek().kind is TokenCat.WHILE: return _while(stream) if stream.peek().kind is TokenCat.IF: return _if(stream) if stream.peek().kind is TokenCat.PRINT: return _print(stream) if stream.peek().kind is not TokenCat.VAR: raise InputError( f"Expecting identifier at beginning of assignment, got {stream.peek()}" ) target = expr.Var(stream.take().value) if stream.peek().kind is not TokenCat.ASSIGN: raise InputError(f"Expecting assignment symbol, got {stream.peek()}") stream.take() # Discard token value = _expr(stream) if stream.peek().kind is not TokenCat.SEMI: raise InputError( f"Expecting semicolon after assignment, got {stream.peek()}") stream.take() # Discard token return expr.Assign(target, value)
def _assignment(self) -> ex.Expr: expr = self._ternary() if self._match(TokenType.EQUAL): equals = self._previous value = self._assignment() if isinstance(expr, ex.Variable): name = expr.name return ex.Assign(name, value) if isinstance(expr, ex.Get): return ex.Set(expr.object, expr.name, value) self._error(equals, 'Invalid assignment target.') return expr
def _stmt(stream: TokenStream) -> expr.Expr: """ stmt ::= exp ['=' exp] """ left = _expr(stream) if stream.peek().kind is TokenCat.ASSIGN: if not isinstance(left, expr.Var): raise InputError("Can only assign to a variable") stream.take() right = _expr(stream) return expr.Assign(left, right) else: return left
def rpn_parse(text: str) -> List[expr.Expr]: """Parse text in reverse Polish notation into a list of expressions (exactly one if the expression is balanced). Example: rpn_parse("5 3 + 4 * 7") => [ Times(Plus(IntConst(5), IntConst(3)), IntConst(4)))), IntConst(7) ] May raise: IndexError (imbalanced expression), lex.LexicalError. """ BINOPS = { lex.TokenCat.PLUS: expr.Plus, lex.TokenCat.TIMES: expr.Times, lex.TokenCat.DIV: expr.Div, lex.TokenCat.MINUS: expr.Minus } UNOPS = {lex.TokenCat.NEG: expr.Neg, lex.TokenCat.ABS: expr.Abs} tokens = lex.TokenStream(io.StringIO(text)) # print (tokens) stack = [] while tokens.has_more(): tok = tokens.take() if tok.kind == lex.TokenCat.INT: stack.append(expr.IntConst(int(tok.value))) print("int", stack) elif tok.kind in BINOPS: binop_class = BINOPS[tok.kind] right = stack.pop() left = stack.pop() stack.append(binop_class(left, right)) print("binop", stack) elif tok.kind in UNOPS: unop_class = UNOPS[tok.kind] left = stack.pop() stack.append(unop_class(left)) print("unop", stack) elif tok.kind == lex.TokenCat.VAR: stack.append(expr.Var(str(tok.value))) print("var", stack) elif tok.kind == lex.TokenCat.ASSIGN: right = stack.pop() print("right", right) left = stack.pop() print("left", left) # Reverse left and right stack.append(expr.Assign(right, left)) print(stack) return stack
def assignment(self): expr = self._or() if self.match(TokenType.EQUAL): equals = self.previous() value = self.assignment() if isinstance(expr, Expr.Variable): name = expr.name return Expr.Assign(name, value) self.error(equals, "Invalid assignment target.") return expr
def assignment(self) -> e.Expr: expr: e.Expr = self._or() if self.match(TokenType.EQUAL): equals: Token = self.previous() value: e.Expr = self.assignment() if isinstance(expr, e.Variable): name: Token = expr.name return e.Assign(name, value) elif isinstance(expr, e.Get): get: e.Get = expr return e.Set(get.object, get.name, value) self.error(equals, "Invalid assignment target.") return expr