search.nv
· 164 B · Text
Исходник
Playground
+
0 b
1 a 1 b 1 c
1 d 1 e 1 f
1 e 1 d 1 c
1 a
.
? 0 $a 1 $a
- 0
+ 2 $a
.
? 0 $a 1 $b
- 1
+ 3 $b
.
? 0 $a
- 0
+ 4 $a
.
| 1 | + |
| 2 | 0 b |
| 3 | 1 a 1 b 1 c |
| 4 | 1 d 1 e 1 f |
| 5 | 1 e 1 d 1 c |
| 6 | 1 a |
| 7 | . |
| 8 | |
| 9 | ? 0 $a 1 $a |
| 10 | - 0 |
| 11 | + 2 $a |
| 12 | . |
| 13 | |
| 14 | ? 0 $a 1 $b |
| 15 | - 1 |
| 16 | + 3 $b |
| 17 | . |
| 18 | |
| 19 | ? 0 $a |
| 20 | - 0 |
| 21 | + 4 $a |
| 22 | . |
simplest-nova.py
· 4.7 KiB · Python
Исходник
Playground
#!/usr/bin/env python3
import sys
from enum import Enum
class State(Enum):
# States
INSERT = 0
MATCH = 1
REMOVE = 2
# Substates
FETCH = 3
LITERAL = 4
VARIABLE = 5
class Machine:
def __init__(self, code, hooks=[]):
self.code = code
self.literals = "0123456789abcdefABCDEF"
self.length = len(code)
self.cursor = 0
self.stack = 0
self.state = State.INSERT
self.substate = State.FETCH
self.stacks = [[] for _ in range(0x10)]
self.offsets = [0] * 0x10
self.variables = {}
self.hooks = hooks
for hook in hooks:
hook(self)
def seek(self, instruction):
while self.cursor < self.length and self.code[self.cursor] != instruction:
self.cursor += 1
def branch(self):
self.clear()
self.seek('.')
def transition(new):
def instruction(self):
self.state = new
self.substate = State.FETCH
self.cursor += 1
return self.cursor >= self.length
return instruction
def variable(self):
if self.substate is State.LITERAL:
self.substate = State.VARIABLE
self.cursor += 1
return self.cursor >= self.length
def clear(self):
self.variables.clear()
for stack in range(0x10):
self.offsets[stack] = 0
def reset(self):
self.clear()
self.cursor = 0
self.state = State.INSERT
self.substate = State.FETCH
self.seek('?')
for hook in self.hooks:
hook(self)
def number(self, instruction):
try:
return int(instruction, 16)
except:
return None
def insert(self, instruction):
if self.substate is State.LITERAL:
self.stacks[self.stack].append(instruction)
else:
if instruction in self.variables:
self.stacks[self.stack].append(self.variables[instruction])
else:
self.stacks[self.stack].append(0)
self.substate = State.FETCH
self.cursor += 1
return self.cursor >= self.length
def match(self, instruction):
depth = len(self.stacks[self.stack])
offset = self.offsets[self.stack]
if depth == 0 or offset >= depth:
self.branch()
else:
if self.substate is State.LITERAL:
if self.stacks[stack][-1 - offset] != instruction:
self.branch()
elif self.substate is State.VARIABLE:
if instruction in self.variables:
if self.variables[instruction] != self.stacks[self.stack][-1 - offset]:
self.branch()
else:
self.variables[instruction] = self.stacks[self.stack][-1 - offset]
self.substate = State.FETCH
self.cursor += 1
return self.cursor >= self.length
def literal(self, instruction):
if self.substate is State.FETCH:
if self.state is State.REMOVE:
self.stacks[instruction].pop()
else:
self.stack = instruction
self.substate = State.LITERAL
self.cursor += 1
return self.cursor >= self.length
if self.state is State.INSERT:
return self.insert(instruction)
return self.match(instruction)
def step(self):
instructions = {
'+': Machine.transition(State.INSERT),
'?': Machine.transition(State.MATCH),
'-': Machine.transition(State.REMOVE),
'$': Machine.variable,
'.': Machine.reset
}
if self.cursor >= self.length:
return True
instruction = self.code[self.cursor]
if instruction in instructions:
return instructions[instruction](self)
elif instruction in self.literals:
return self.literal(self.number(instruction))
self.cursor += 1
return False
def run(self):
halt = False
while not halt:
halt = self.step()
return self
def print(self):
for index, stack in enumerate(self.stacks):
if len(stack) != 0:
print(str(index) + ':', " ".join([str(element) for element in stack]))
def main(name, arguments):
code = ""
if len(arguments) == 0:
print("usage:", name, "<files...>")
return
for argument in arguments:
if argument == '-':
code += input()
continue
with open(argument) as file:
code += file.read()
Machine(code).run().print()
if __name__ == "__main__":
main(sys.argv[0], sys.argv[1:])
| 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import sys |
| 4 | from enum import Enum |
| 5 | |
| 6 | class State(Enum): |
| 7 | # States |
| 8 | INSERT = 0 |
| 9 | MATCH = 1 |
| 10 | REMOVE = 2 |
| 11 | |
| 12 | # Substates |
| 13 | FETCH = 3 |
| 14 | LITERAL = 4 |
| 15 | VARIABLE = 5 |
| 16 | |
| 17 | class Machine: |
| 18 | def __init__(self, code, hooks=[]): |
| 19 | self.code = code |
| 20 | self.literals = "0123456789abcdefABCDEF" |
| 21 | self.length = len(code) |
| 22 | self.cursor = 0 |
| 23 | self.stack = 0 |
| 24 | self.state = State.INSERT |
| 25 | self.substate = State.FETCH |
| 26 | self.stacks = [[] for _ in range(0x10)] |
| 27 | self.offsets = [0] * 0x10 |
| 28 | self.variables = {} |
| 29 | self.hooks = hooks |
| 30 | for hook in hooks: |
| 31 | hook(self) |
| 32 | def seek(self, instruction): |
| 33 | while self.cursor < self.length and self.code[self.cursor] != instruction: |
| 34 | self.cursor += 1 |
| 35 | def branch(self): |
| 36 | self.clear() |
| 37 | self.seek('.') |
| 38 | def transition(new): |
| 39 | def instruction(self): |
| 40 | self.state = new |
| 41 | self.substate = State.FETCH |
| 42 | self.cursor += 1 |
| 43 | return self.cursor >= self.length |
| 44 | return instruction |
| 45 | def variable(self): |
| 46 | if self.substate is State.LITERAL: |
| 47 | self.substate = State.VARIABLE |
| 48 | self.cursor += 1 |
| 49 | return self.cursor >= self.length |
| 50 | def clear(self): |
| 51 | self.variables.clear() |
| 52 | for stack in range(0x10): |
| 53 | self.offsets[stack] = 0 |
| 54 | def reset(self): |
| 55 | self.clear() |
| 56 | self.cursor = 0 |
| 57 | self.state = State.INSERT |
| 58 | self.substate = State.FETCH |
| 59 | self.seek('?') |
| 60 | for hook in self.hooks: |
| 61 | hook(self) |
| 62 | def number(self, instruction): |
| 63 | try: |
| 64 | return int(instruction, 16) |
| 65 | except: |
| 66 | return None |
| 67 | def insert(self, instruction): |
| 68 | if self.substate is State.LITERAL: |
| 69 | self.stacks[self.stack].append(instruction) |
| 70 | else: |
| 71 | if instruction in self.variables: |
| 72 | self.stacks[self.stack].append(self.variables[instruction]) |
| 73 | else: |
| 74 | self.stacks[self.stack].append(0) |
| 75 | self.substate = State.FETCH |
| 76 | self.cursor += 1 |
| 77 | return self.cursor >= self.length |
| 78 | def match(self, instruction): |
| 79 | depth = len(self.stacks[self.stack]) |
| 80 | offset = self.offsets[self.stack] |
| 81 | if depth == 0 or offset >= depth: |
| 82 | self.branch() |
| 83 | else: |
| 84 | if self.substate is State.LITERAL: |
| 85 | if self.stacks[stack][-1 - offset] != instruction: |
| 86 | self.branch() |
| 87 | elif self.substate is State.VARIABLE: |
| 88 | if instruction in self.variables: |
| 89 | if self.variables[instruction] != self.stacks[self.stack][-1 - offset]: |
| 90 | self.branch() |
| 91 | else: |
| 92 | self.variables[instruction] = self.stacks[self.stack][-1 - offset] |
| 93 | self.substate = State.FETCH |
| 94 | self.cursor += 1 |
| 95 | return self.cursor >= self.length |
| 96 | def literal(self, instruction): |
| 97 | if self.substate is State.FETCH: |
| 98 | if self.state is State.REMOVE: |
| 99 | self.stacks[instruction].pop() |
| 100 | else: |
| 101 | self.stack = instruction |
| 102 | self.substate = State.LITERAL |
| 103 | self.cursor += 1 |
| 104 | return self.cursor >= self.length |
| 105 | if self.state is State.INSERT: |
| 106 | return self.insert(instruction) |
| 107 | return self.match(instruction) |
| 108 | def step(self): |
| 109 | instructions = { |
| 110 | '+': Machine.transition(State.INSERT), |
| 111 | '?': Machine.transition(State.MATCH), |
| 112 | '-': Machine.transition(State.REMOVE), |
| 113 | '$': Machine.variable, |
| 114 | '.': Machine.reset |
| 115 | } |
| 116 | if self.cursor >= self.length: |
| 117 | return True |
| 118 | instruction = self.code[self.cursor] |
| 119 | if instruction in instructions: |
| 120 | return instructions[instruction](self) |
| 121 | elif instruction in self.literals: |
| 122 | return self.literal(self.number(instruction)) |
| 123 | self.cursor += 1 |
| 124 | return False |
| 125 | def run(self): |
| 126 | halt = False |
| 127 | while not halt: |
| 128 | halt = self.step() |
| 129 | return self |
| 130 | def print(self): |
| 131 | for index, stack in enumerate(self.stacks): |
| 132 | if len(stack) != 0: |
| 133 | print(str(index) + ':', " ".join([str(element) for element in stack])) |
| 134 | |
| 135 | def main(name, arguments): |
| 136 | code = "" |
| 137 | if len(arguments) == 0: |
| 138 | print("usage:", name, "<files...>") |
| 139 | return |
| 140 | for argument in arguments: |
| 141 | if argument == '-': |
| 142 | code += input() |
| 143 | continue |
| 144 | with open(argument) as file: |
| 145 | code += file.read() |
| 146 | Machine(code).run().print() |
| 147 | |
| 148 | if __name__ == "__main__": |
| 149 | main(sys.argv[0], sys.argv[1:]) |