initial
This commit is contained in:
commit
26aaabe6a7
45
README.md
Normal file
45
README.md
Normal file
@ -0,0 +1,45 @@
|
||||
# Fifth
|
||||
|
||||
A simple stack-based language called Fifth
|
||||
|
||||
## Usage
|
||||
|
||||
```shell
|
||||
python fifth.py
|
||||
```
|
||||
|
||||
### Commands
|
||||
|
||||
- `PUSH <n>` - push integer onto stack
|
||||
- `POP` - remove top element
|
||||
- `SWAP` - swap top two elements
|
||||
- `DUP` - duplicate top element
|
||||
- `+`, `-`, `*`, `/` - arithmetic operations
|
||||
- `EXIT` - quit
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
stack is: []
|
||||
PUSH 10
|
||||
stack is: [10]
|
||||
PUSH 5
|
||||
stack is: [10, 5]
|
||||
+
|
||||
stack is: [15]
|
||||
PUSH 45
|
||||
stack is: [15, 45]
|
||||
/
|
||||
stack is: [3]
|
||||
EXIT
|
||||
```
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
python -m pytest test_stack_calculator.py
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+
|
||||
101
fifth.py
Normal file
101
fifth.py
Normal file
@ -0,0 +1,101 @@
|
||||
import operator
|
||||
import readline
|
||||
|
||||
class FifthStack:
|
||||
def __init__(self):
|
||||
self.stack = []
|
||||
self.commands = {
|
||||
'push': self.push,
|
||||
'pop': self.pop,
|
||||
'swap': self.swap,
|
||||
'dup': self.dup,
|
||||
'+': self.add,
|
||||
'-': self.sub,
|
||||
'*': self.mul,
|
||||
'/': self.div,
|
||||
}
|
||||
self.binary_ops = {
|
||||
'+': operator.add,
|
||||
'-': operator.sub,
|
||||
'*': operator.mul,
|
||||
'/': operator.floordiv,
|
||||
}
|
||||
|
||||
def _require(self, number, message):
|
||||
if len(self.stack) < number:
|
||||
print(message)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _get_binary_op(self, command):
|
||||
return self.binary_ops.get(command)
|
||||
|
||||
def _binary_op(self, operator):
|
||||
if not self._require(2, "two numbers required"):
|
||||
return
|
||||
a, b = self.stack.pop(), self.stack.pop()
|
||||
try:
|
||||
self.stack.append(operator(a, b))
|
||||
except Exception as e:
|
||||
print(f"ERROR: {e}")
|
||||
self.stack.extend([a, b])
|
||||
|
||||
def push(self, value):
|
||||
try:
|
||||
self.stack.append(int(value))
|
||||
except ValueError:
|
||||
print("ERROR: integer required")
|
||||
|
||||
def pop(self, _value):
|
||||
if not self.stack:
|
||||
print("ERROR: stack empty")
|
||||
return
|
||||
self.stack.pop()
|
||||
|
||||
def swap(self, _value):
|
||||
if not self._require(2, 'two numbers required'):
|
||||
return
|
||||
self.stack[-1], self.stack[-2] = self.stack[-2], self.stack[-1]
|
||||
|
||||
def dup(self, _value):
|
||||
if self._require(1, 'stack empty'):
|
||||
self.stack.append(self.stack[-1])
|
||||
|
||||
def add(self, _value):
|
||||
self._binary_op(self._get_binary_op('+'))
|
||||
|
||||
def sub(self, _value):
|
||||
self._binary_op(self._get_binary_op('-'))
|
||||
|
||||
def mul(self, _value):
|
||||
self._binary_op(self._get_binary_op('*'))
|
||||
|
||||
def div(self, _value):
|
||||
self._binary_op(self._get_binary_op('/'))
|
||||
|
||||
def execute(self, command):
|
||||
tokens = command.lower().strip().split()
|
||||
if not tokens:
|
||||
return
|
||||
|
||||
command, argument = tokens[0], tokens[1] if len(tokens) > 1 else None
|
||||
function = self.commands.get(command)
|
||||
|
||||
try:
|
||||
if function: function(argument)
|
||||
else: print("ERROR: unknown command")
|
||||
except:
|
||||
print("ERROR: invalid command")
|
||||
|
||||
def main():
|
||||
fifth = FifthStack()
|
||||
|
||||
while True:
|
||||
print(f'stack is: {fifth.stack}')
|
||||
command = input()
|
||||
if command.lower() == 'exit':
|
||||
break
|
||||
fifth.execute(command)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in New Issue
Block a user