Son aktivite 2 days ago

The simplest Nova implementation I've got (so far).

Revizyon e6a1b63b8b7c4e63169abd31c2ef2d4529268e45

simplest-nova.py Ham Playground
1#!/usr/bin/env python3
2
3import sys
4from enum import Enum
5
6class State(Enum):
7 # States
8 INSERT = 0
9 MATCH = 1
10 REMOVE = 2
11
12 # Substates
13 FETCH = 3
14 LABEL = 4
15 VARIABLE = 5
16
17def number(instruction):
18 try:
19 return int(instruction, 16)
20 except:
21 return None
22
23def seek(cursor, code, instruction):
24 while cursor < len(code) and code[cursor] != instruction:
25 cursor += 1
26 return cursor
27
28def step(machine, code):
29 state, substate, cursor, label, stacks, offsets, variables = machine
30 if cursor >= len(code):
31 return (False, machine)
32 instruction = code[cursor]
33 if instruction == '+':
34 state = State.INSERT
35 substate = State.FETCH
36 cursor += 1
37 elif instruction == '?':
38 state = State.MATCH
39 substate = State.FETCH
40 cursor += 1
41 elif instruction == '-':
42 state = State.REMOVE
43 substate = State.FETCH
44 cursor += 1
45 elif instruction == '.':
46 state = State.INSERT
47 substate = State.FETCH
48 variables.clear()
49 for offset in range(0xF):
50 offsets[offset] = 0
51 cursor = seek(0, code, '?')
52 elif instruction == '$':
53 if substate is State.LABEL:
54 substate = State.VARIABLE
55 cursor += 1
56 else:
57 # Gremlins live here.
58 data = number(instruction)
59 if data is not None:
60 if substate is State.FETCH:
61 if state is State.REMOVE:
62 stacks[data].pop()
63 else:
64 label = data
65 substate = State.LABEL
66 elif substate is State.LABEL:
67 if state is State.INSERT:
68 stacks[label].append(data)
69 elif state is State.MATCH:
70 if len(stacks[label]) == 0 or offsets[label] >= len(stacks[label]) or stacks[label][-1 - offsets[label]] != data:
71 cursor = seek(cursor, code, '.')
72 variables.clear()
73 for offset in range(0xF):
74 offsets[offset] = 0
75 else:
76 offsets[label] += 1
77 substate = State.FETCH
78 elif substate is State.VARIABLE:
79 if state is State.INSERT:
80 if data in variables:
81 stacks[label].append(variables[data])
82 else:
83 stacks[label].append(0)
84 elif state is State.MATCH:
85 if len(stacks[label]) == 0 or offsets[label] > len(stacks[label]):
86 cursor = seek(cursor, code, '.')
87 variables.clear()
88 for offset in range(0xF):
89 offsets[offset] = 0
90 else:
91 if data in variables:
92 if stacks[label][-1 - offsets[label]] != variables[data]:
93 cursor = seek(cursor, code, '.')
94 variables.clear()
95 for offset in range(0xF):
96 offsets[offset] = 0
97 else:
98 offsets[label] += 1
99 else:
100 variables[data] = stacks[label][-1 - offsets[label]]
101 offsets[label] += 1
102 substate = State.FETCH
103 cursor += 1
104 return (cursor >= len(code), (state, substate, cursor, label, stacks, offsets, variables))
105
106def run(code, machine=None):
107 if not machine:
108 stacks = [[] for _ in range(0x10)]
109 offsets = [0] * 0x10
110 machine = (State.INSERT, State.FETCH, 0, 0, stacks, offsets, {})
111 halt = False
112 while not halt:
113 halt, machine = step(machine, code)
114 return machine
115
116def pretty(machine):
117 state, substate, cursor, label, stacks, offsets, variables = machine
118 for index, stack in enumerate(stacks):
119 if len(stack) == 0:
120 continue
121 print(str(index) + ':', " ".join(reversed([str(element) for element in stack])))
122
123def main(name, arguments):
124 rules = ""
125 if len(arguments) == 0:
126 print("usage:", name, + "<files>...")
127 return
128 for argument in arguments:
129 with open(argument) as file:
130 rules += file.read()
131 pretty(run(rules))
132
133if __name__ == "__main__":
134 main(sys.argv[0], sys.argv[1:])
135