push (lame)
This commit is contained in:
commit
d1cf1ea5a9
117
main.py
Normal file
117
main.py
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
import dataclasses
|
||||
import enum
|
||||
import logging
|
||||
import string
|
||||
|
||||
from rich.logging import RichHandler
|
||||
|
||||
logging.basicConfig(
|
||||
level="INFO", format="%(message)s", datefmt="[%X]", handlers=[RichHandler()]
|
||||
)
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TokenType(enum.Enum):
|
||||
DIGIT = enum.auto()
|
||||
OPERATOR = enum.auto()
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class Token:
|
||||
token_type: TokenType
|
||||
literal: str
|
||||
precedence: int
|
||||
line: int
|
||||
column: int
|
||||
|
||||
@classmethod
|
||||
def from_char(cls, char: str, line: int, column: int) -> "Token | None":
|
||||
if char.isdigit():
|
||||
token_type = TokenType.DIGIT
|
||||
elif char in "*/+-":
|
||||
token_type = TokenType.OPERATOR
|
||||
else:
|
||||
return None
|
||||
|
||||
return cls(
|
||||
token_type=token_type,
|
||||
literal=char,
|
||||
precedence=get_precedence(char),
|
||||
line=line,
|
||||
column=column,
|
||||
)
|
||||
|
||||
|
||||
def get_precedence(char: str):
|
||||
match char:
|
||||
case "*" | "/":
|
||||
return 2
|
||||
case "+" | "-":
|
||||
return 1
|
||||
case _:
|
||||
return 0
|
||||
|
||||
|
||||
def get_expr() -> str:
|
||||
return "1 + 2\n * 6 / 2 * oarsetaortsn6 / 2"
|
||||
|
||||
|
||||
def goto_address(line, col) -> str:
|
||||
return f"({line}:{col})"
|
||||
|
||||
|
||||
def tokenize_expr(expr: str) -> list[Token]:
|
||||
stack = list()
|
||||
line = 1
|
||||
col = 0
|
||||
|
||||
for c in expr:
|
||||
col += 1
|
||||
|
||||
if c in string.whitespace:
|
||||
if c == "\n":
|
||||
line += 1
|
||||
col = 0
|
||||
continue
|
||||
|
||||
current_token = Token.from_char(c, line, col)
|
||||
if not current_token:
|
||||
log.warning("Unexpected char %s: %s", goto_address(line, col), repr(c))
|
||||
log.info("Ignoring char %s: %s", goto_address(line, col), repr(c))
|
||||
continue
|
||||
|
||||
stack.append(current_token)
|
||||
|
||||
return stack
|
||||
|
||||
|
||||
def main() -> int:
|
||||
expr = get_expr()
|
||||
log.info(f"{expr=}")
|
||||
|
||||
expr_tokenized = tokenize_expr(expr)
|
||||
log.info(f"{expr_tokenized=}")
|
||||
|
||||
rpn: list[Token] = []
|
||||
stack: list[Token] = []
|
||||
|
||||
for token in expr_tokenized:
|
||||
log.info(
|
||||
f"{goto_address(token.line, token.column)} {token.literal=} {token.precedence=}"
|
||||
)
|
||||
if token.literal.isdigit():
|
||||
rpn.append(token)
|
||||
elif token.literal in "*/-+":
|
||||
while stack and stack[-1].precedence >= token.precedence:
|
||||
rpn.append(stack.pop())
|
||||
stack.append(token)
|
||||
while stack:
|
||||
rpn.append(stack.pop())
|
||||
|
||||
log.info("RPN: %s", [c.literal for c in rpn])
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
Loading…
Reference in a new issue