git.fiddlerwoaroof.com
Browse code

initial

fiddlerwoaroof authored on 20/07/2014 06:34:23
Showing 3 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,517 @@
1
+from __future__ import print_function
2
+import sys
3
+import inspect
4
+SPACE = None
5
+class _RUN: pass
6
+
7
+def read_word(fil):
8
+    char = ' '
9
+    buffer = []
10
+    delim  = SPACE
11
+    spaces = {' ', '\n', '\t'}
12
+    while char != '':
13
+        char = fil.read(1)
14
+        if char == '':
15
+            yield ''.join(buffer).strip()
16
+            break
17
+        buffer.append(char)
18
+        if delim != SPACE and buffer[-len(delim):] == delim:
19
+            delim = yield ''.join(buffer[:-len(delim)])
20
+            buffer = []
21
+        elif char in spaces:
22
+            delim = yield ''.join(buffer[:-1]).strip()
23
+            if char == '\n':
24
+                yield _RUN
25
+            buffer = []
26
+
27
+def skip_run(reader):
28
+    skipped = False
29
+    r = reader.next()
30
+    while r == _RUN:
31
+        skipped = skipped or r == _RUN
32
+        #print(r, end=':')
33
+        r = reader.next()
34
+        #print(r, end=' ')
35
+    #print('out')
36
+    return r, skipped
37
+
38
+import collections
39
+import traceback
40
+class SymbolDict(collections.MutableMapping):
41
+    def __init__(self, *args, **kwargs):
42
+        self.ctr = 0
43
+        self.items_ = set()
44
+        self.dct = dict(*args, **kwargs)
45
+
46
+    def __getitem__(self, key):
47
+        if self.dct[key] != []:
48
+            return self.dct[key][-1][1]
49
+        else:
50
+            raise KeyError("No such key '%s'" % key)
51
+    def __setitem__(self, key, value):
52
+        self.ctr += 1
53
+        self.items_.add(key)
54
+        self.dct.setdefault(key, []).append((self.ctr, value))
55
+    def __delitem__(self, key):
56
+        state = self.dct[key][-1][0]
57
+        for a in self.dct.keys():
58
+            while self.dct[a] and self.dct[a][-1][0] >= state:
59
+                self.dct[a].pop()
60
+            if self.dct[a] == []: self.dct.pop(a)
61
+    forget = __delitem__
62
+    def __iter__(self):
63
+        return (x for x in self.dct.keys())
64
+    def __len__(self):
65
+        return len(self.dct)
66
+
67
+import random
68
+
69
+class Reader(object):
70
+    symbols = SymbolDict()
71
+
72
+    def rev_pctr(self, stack, rstack):
73
+        num = stack.pop()
74
+        self.program_ctr -= num
75
+
76
+    def adv_pctr(self, stack, rstack):
77
+        num = stack.pop()
78
+        self.program_ctr += num
79
+
80
+    def adv_pctr0(self, stack, rstack):
81
+        #print('adv0 -->', stack, rstack)
82
+        num = stack.pop()
83
+        cond = stack.pop()
84
+        if cond == 0:
85
+            stack.append(num)
86
+            self.adv_pctr(stack, rstack)
87
+
88
+    def save_program_ctr(self):
89
+        self.pcs.append(self.program_ctr)
90
+    def restore_program_ctr(self):
91
+        self.program_ctr = self.pcs.pop()
92
+    def rollback_program(self):
93
+        self.restore_program_ctr()
94
+        del self.program[self.program_ctr:]
95
+    def splice_program(self, words):
96
+        begin = self.peek_saved_program_ctr()
97
+        end = self.program_ctr + 1
98
+        self.program[begin:end] = words
99
+    def peek_saved_program_ctr(self):
100
+        return self.pcs[-1]
101
+    def drop_saved_program_ctr(self):
102
+        return self.pcs.pop()
103
+
104
+    def if_(self, stack, rstack=None):
105
+        def if_reader(gen):
106
+            counter = 0
107
+            if_clause = []
108
+            else_clause = []
109
+            cur_clause = if_clause
110
+            for word in gen:
111
+                if word == 'if':
112
+                    cur_clause.extend(if_reader(gen))
113
+                    continue
114
+                elif word == 'else':
115
+                    cur_clause = else_clause
116
+                    continue
117
+                elif word == 'then':
118
+                    else_clause.extend(['nop'])
119
+                    break
120
+                cur_clause.extend(self.expand_word(word))
121
+            if_clause.extend(['%d' % len(else_clause), 'adv'])
122
+            if_clause.insert(0, '%d' % len(if_clause))
123
+            if_clause.insert(1, 'adv0')
124
+            result = if_clause + else_clause
125
+            return result
126
+
127
+        ## Below we replace the if statement with a call to lower-level primitives
128
+        ## i.e. if is implemented as a kind of macro.
129
+        self.save_program_ctr()
130
+        self.program_ctr += 1 # since the program counter doesn't update until after the yield
131
+        gen = self.read_word()
132
+        self.splice_program(if_reader(gen))
133
+        self.restore_program_ctr()
134
+        self.program_ctr -= 1 # in order to pick up the beginning of the if statement
135
+
136
+    def words(self, stack, rstack=None):
137
+        words = sorted(self.symbols.keys())
138
+        mlen = max(len(x) for x in words)
139
+        c = 80 // (mlen + 2)
140
+        while words:
141
+            head, words = words[:c], words[c:]
142
+            print(' '.join(x.center(mlen) for x in head))
143
+
144
+    def forget(self, stack, rstack=None):
145
+        self.program_ctr += 1 # since the program counter doesn't update until after the yield
146
+        name, skipped = skip_run(self.read_word())
147
+        self.symbols.forget(name)
148
+        if skipped: self.inp.append([_RUN])
149
+
150
+    def colon(self, stack, rstack=None):
151
+        self.program_ctr += 1 # since the program counter doesn't update until after the yield
152
+        gen = self.read_word()
153
+        name = gen.next()
154
+        word = ' '
155
+        conts = []
156
+        while word != ';':
157
+            word = gen.next()
158
+            if word == _RUN: continue
159
+            conts.append(word)
160
+        conts.pop() # pop off the semicolon
161
+
162
+        self.compile(name, filter(None,conts))
163
+        #print(' >name', name, ' >symbols["%s"]' % name, self.symbols[name.lower()])
164
+
165
+    def expand_word(self, word):
166
+        if word in self.sym_words:
167
+            outp = [self.expand_word(w) for w in self.sym_words[word][:]]
168
+            return sum(outp, [])
169
+        else:
170
+            return [word]
171
+
172
+    def compile(self, name, words):
173
+        if hasattr(words, 'split'): words = words.split()
174
+        self.sym_words[name] = words[:]
175
+        @self.add_symbol(name)
176
+        def newfun(stack, rstack=None):
177
+            self.save_program_ctr()
178
+            self.splice_program(words[:])
179
+            self.program_ctr -= 1
180
+        newfun.__name__ = '_forth_%s' % name
181
+    def prog_print(self, stack, rstack=None):
182
+        print('<%d>' % len(self.program), end=' ')
183
+        for n in self.program:
184
+            print(n, end=' ')
185
+        print()
186
+
187
+    def set_pctr(self, v):
188
+        self.program_ctr = v
189
+    def begin_until(self, stack, rstack):
190
+        self.program_ctr += 1 # since the program counter doesn't update until after the yield
191
+        mark = self.program_ctr
192
+        word = ' '
193
+        loop_count = 0
194
+        words = []
195
+        while True:
196
+            word = self.read_word()
197
+            if word == 'begin': loop_count += 1
198
+            elif word == 'until':
199
+                if loop_count == 0: break
200
+                else: loop_count -= 1
201
+            words.append(word)
202
+
203
+    def mark_r(self, stack, rstack):
204
+        self.jmpr.append(self.program_ctr-1)
205
+        #print('markr', self.jmpr)
206
+    def jmp_r(self, stack, rstack):
207
+        dst = self.jmpr.pop()
208
+        self.set_pctr(dst)
209
+        #print('jmpr', dst, self.jmpr)
210
+    def jmp_clr(self, stack, rstack):
211
+        self.jmpr.pop()
212
+        #print('clrjmp', self.jmpr)
213
+
214
+    def mark(self, stack, rstack):
215
+        self.stack.append(self.program_ctr-1)
216
+    def jmp(self, stack, rstack):
217
+        dst = stack.pop()
218
+        self.set_pctr(dst)
219
+
220
+    def __init__(self):
221
+        self.sym_words = SymbolDict()
222
+        self.stack = []
223
+        self.rstack = []
224
+        self.program = []
225
+        self.jmpr = []
226
+        self.pcs = []
227
+        self.mode = 0; # 0 - Normal; 1 - string reading
228
+        self.program_ctr = 0
229
+        self.add_symbol('words')(self.words)
230
+        self.add_symbol('.p')(self.prog_print)
231
+        self.add_symbol(':')(self.colon)
232
+        self.add_symbol('forget')(self.forget)
233
+        self.add_symbol('if')(self.if_)
234
+        self.add_symbol('jmp')(self.jmp)
235
+        self.add_symbol('rev')(self.rev_pctr)
236
+        self.add_symbol('adv')(self.adv_pctr)
237
+        self.add_symbol('adv0')(self.adv_pctr0)
238
+        self.add_symbol('mark')(self.mark)
239
+        self.add_symbol('markr')(self.mark_r)
240
+        self.add_symbol('jmpr')(self.jmp_r)
241
+        self.add_symbol('clrjmp')(self.jmp_clr)
242
+
243
+    def __getword(self):
244
+        while self.inp[-1] == []: self.inp.pop()
245
+        if hasattr(self.inp[-1], 'read'):
246
+            self.inp[-1] = read_word(self.inp[-1])
247
+        if hasattr(self.inp[-1], 'next'):
248
+            result = self.inp[-1].next()
249
+        else:
250
+            result = self.inp[-1].pop(0)
251
+        self.program.append(result)
252
+
253
+    def read_word(self):
254
+        while True:
255
+            while self.program_ctr >= len(self.program):
256
+                self.__getword()
257
+            yield self.program[self.program_ctr]
258
+            self.program_ctr += 1
259
+
260
+    def read(self, inp, silent=False):
261
+        self.inp = [inp]
262
+        delim = SPACE
263
+        if not silent: print(self.program_ctr, end='? ')
264
+        for word in self.read_word():
265
+            #print('<%s>' % word, end=' ')
266
+            if word == _RUN:
267
+                if not silent:
268
+                    print(' ok')
269
+                    print(self.program_ctr, end='? ')
270
+                continue
271
+            elif word == '."':
272
+                out = []
273
+                word = self.__getword()
274
+                while word != '"':
275
+                    out.append(self.__getword)
276
+                    word = self.__getword()
277
+                print(' '.join(out))
278
+                continue
279
+            elif word == '': continue
280
+            self.stack.append(word)
281
+            self.lookup()
282
+    def lookup(self, sym=None):
283
+        if sym is None:
284
+            sym = self.stack.pop()
285
+        result = None
286
+        if sym.lower() in self.symbols:
287
+            result = self.symbols[sym.lower()](self.stack, self.rstack)
288
+        else:
289
+            result = self.numberp(sym)
290
+            if result is None: raise ValueError("Symbol %r not found" % sym)
291
+            else:
292
+                self.stack.append(result)
293
+        return result
294
+    def numberp(self, sym):
295
+        is_valid = -1 # -1 = undecided, 0 = False, 1 = True
296
+        typ = int
297
+        dot_acceptable = False
298
+        if sym == '': is_valid = 0
299
+        elif not (sym.startswith('-') or sym[0].isdigit()): is_valid = 0
300
+        if is_valid == 0: return None
301
+        else:
302
+            for char in sym[1:]:
303
+                if char.isdigit(): dot_acceptable = True
304
+                elif dot_acceptable and char == '.': typ = float
305
+                elif dot_acceptable and char == 'e': typ = float
306
+                else:
307
+                    return None
308
+            else:
309
+                return typ(sym)
310
+    @classmethod
311
+    def add_symbol(cls, name):
312
+        def _i1(func):
313
+            cls.symbols[name.lower()] = func
314
+            return func
315
+        return _i1
316
+
317
+@Reader.add_symbol('J')
318
+def J(stack, rstack):
319
+    stack.append(rstack[-3])
320
+
321
+@Reader.add_symbol('R@')
322
+def rAt(stack, rstack):
323
+    stack.append(rstack[-1])
324
+
325
+@Reader.add_symbol('I')
326
+def I(stack, rstack):
327
+    stack.append(rstack[-1])
328
+
329
+@Reader.add_symbol('R>')
330
+def movP(stack, rstack):
331
+    stack.append(rstack.pop())
332
+
333
+@Reader.add_symbol('>R')
334
+def movR(stack, rstack):
335
+    rstack.append(stack.pop())
336
+
337
+@Reader.add_symbol('2over')
338
+def _2over(stack, rstack=None):
339
+    d, c, b, a = [stack.pop() for _ in range(4)]
340
+    stack.append(a)
341
+    stack.append(b)
342
+    stack.append(c)
343
+    stack.append(d)
344
+    stack.append(a)
345
+    stack.append(b)
346
+
347
+@Reader.add_symbol('2dup')
348
+def _2dup(stack, rstack=None):
349
+    b, a = [stack.pop() for _ in range(2)]
350
+    stack.append(a)
351
+    stack.append(b)
352
+    stack.append(a)
353
+    stack.append(b)
354
+
355
+@Reader.add_symbol('2swap')
356
+def _2swap(stack, rstack=None):
357
+    d, c, b, a = [stack.pop() for _ in range(4)]
358
+    stack.append(c)
359
+    stack.append(d)
360
+    stack.append(a)
361
+    stack.append(b)
362
+
363
+@Reader.add_symbol('.r')
364
+def stack_print(stack, rstack=None):
365
+    print('<%d>' % len(rstack), end=' ')
366
+    for n in rstack:
367
+        print(n, end=' ')
368
+    print()
369
+
370
+@Reader.add_symbol('.s')
371
+def stack_print(stack, rstack=None):
372
+    print('<%d>' % len(stack), end=' ')
373
+    for n in stack:
374
+        print(n, end=' ')
375
+    print()
376
+
377
+@Reader.add_symbol('drop')
378
+def drop(stack, rstack=None):
379
+    stack.pop()
380
+
381
+@Reader.add_symbol('rot')
382
+def rot(stack, rstack=None):
383
+    n1, n2, n3 = stack.pop(), stack.pop(), stack.pop()
384
+    #a,  b,  c
385
+    stack.extend([n2, n1, n3])
386
+
387
+@Reader.add_symbol('dup')
388
+def dup(stack, rstack=None):
389
+    a = stack.pop()
390
+    stack.append(a)
391
+    stack.append(a)
392
+
393
+@Reader.add_symbol('over')
394
+def over(stack, rstack=None):
395
+    b, a = stack.pop(), stack.pop()
396
+    stack.append(a)
397
+    stack.append(b)
398
+    stack.append(a)
399
+
400
+@Reader.add_symbol('swap')
401
+def swap(stack, rstack=None):
402
+    b, a = stack.pop(), stack.pop()
403
+    stack.append(b)
404
+    stack.append(a)
405
+
406
+@Reader.add_symbol('%')
407
+def mod(stack, rstack=None):
408
+    b, a = stack.pop(), stack.pop()
409
+    stack.append(a % b)
410
+
411
+@Reader.add_symbol('/')
412
+def div(stack, rstack=None):
413
+    b, a = stack.pop(), stack.pop()
414
+    stack.append(a / b)
415
+
416
+@Reader.add_symbol('*')
417
+def mul(stack, rstack=None):
418
+    b, a = stack.pop(), stack.pop()
419
+    stack.append(a * b)
420
+
421
+@Reader.add_symbol('-')
422
+def min_(stack, rstack=None):
423
+    b, a = stack.pop(), stack.pop()
424
+    stack.append(a - b)
425
+
426
+@Reader.add_symbol('+')
427
+def add(stack, rstack=None):
428
+    b, a = stack.pop(), stack.pop()
429
+    stack.append(a + b)
430
+
431
+@Reader.add_symbol('and')
432
+def and_(stack, rstack=None):
433
+    b, a = stack.pop(), stack.pop()
434
+    stack.append(a and b)
435
+
436
+@Reader.add_symbol('or')
437
+def or_(stack, rstack=None):
438
+    b, a = stack.pop(), stack.pop()
439
+    stack.append(a or b)
440
+
441
+@Reader.add_symbol('.')
442
+def period(stack, rstack=None):
443
+    print(stack.pop(), end=' ')
444
+
445
+@Reader.add_symbol('emit')
446
+def emit(stack, rstack=None):
447
+    print(chr(stack.pop()), end='')
448
+
449
+@Reader.add_symbol('=')
450
+def eql(stack, rstack=None):
451
+    b, a = stack.pop(), stack.pop()
452
+    stack.append(int(a == b))
453
+
454
+@Reader.add_symbol('<')
455
+def lt(stack, rstack=None):
456
+    b, a = stack.pop(), stack.pop()
457
+    stack.append(int(a < b))
458
+
459
+@Reader.add_symbol('>')
460
+def gt(stack, rstack=None):
461
+    b, a = stack.pop(), stack.pop()
462
+    stack.append(int(a > b))
463
+
464
+@Reader.add_symbol('nop')
465
+def nop(*_):
466
+    pass
467
+
468
+@Reader.add_symbol('clear')
469
+def clear(stack, rstack):
470
+    del stack[:]
471
+    del rstack[:]
472
+
473
+if __name__ == '__main__':
474
+    import sys
475
+    reader = Reader()
476
+    reader.compile(*'0= 0 ='.split(None,1))
477
+    reader.compile(*'0> 0 >'.split(None,1))
478
+    reader.compile(*'0< 0 <'.split(None,1))
479
+    reader.compile('cr', ['10', 'emit'])
480
+    reader.compile('2drop', ['drop', 'drop'])
481
+    reader.compile('false', ['0'])
482
+    reader.compile('true', ['-1'])
483
+    reader.compile('invert', ['0=', 'if', 'true', 'else', 'false', 'then'])
484
+    reader.compile('?dup', 'dup if dup then'.split())
485
+    reader.compile('1+', '1 +'.split())
486
+    reader.compile('1-', '1 -'.split())
487
+    reader.compile('2+', '2 +'.split())
488
+    reader.compile('2-', '2 -'.split())
489
+    reader.compile('2*', '2 *'.split())
490
+    reader.compile('2/', '2 /'.split())
491
+    reader.compile('abs', 'dup 0< if -1 * then'.split())
492
+    reader.compile('negate', '-1 *'.split())
493
+    reader.compile('min', '2dup - 0> if swap then drop')
494
+    reader.compile('max', '2dup - 0< if swap then drop')
495
+    reader.compile('*/', 'rot rot * swap /')
496
+    reader.compile('*/mod', 'rot rot * swap /mod')
497
+    reader.compile('/mod1', '2dup % dup 2swap / rot drop')
498
+    reader.compile('mark>r', 'mark >r')
499
+    reader.compile('arrow', '45 emit 45 emit 62 emit')
500
+    reader.compile('loop0', '0= arrow .s if  98 emit cr else 97 emit cr .s r> .s jmp then')
501
+    reader.compile(*'spaces 0 do 32 emit loop'.split(None, 1))
502
+    reader.compile(*'do swap >r >r begin'.split(None, 1))
503
+    reader.compile('rdrop', 'r> drop')
504
+    reader.compile(*'loop r> 1+ r> 2dup >r >r < invert until rdrop rdrop'.split(None, 1))
505
+    reader.compile('begin', 'markr')
506
+    reader.compile('until', 'invert if jmpr else clrjmp then')
507
+
508
+    import argparse
509
+    parser = argparse.ArgumentParser()
510
+    parser.add_argument('file', nargs='?')
511
+    args = parser.parse_args()
512
+    if args.file == '-' or args.file == None:
513
+        fil = sys.stdin
514
+        reader.read(sys.stdin)
515
+    else:
516
+        with open(args.file) as f:
517
+            reader.read(f, silent=True)
0 518
new file mode 100644
... ...
@@ -0,0 +1,5 @@
1
+: truep dup * ;
2
+0 0= truep .
3
+1 0= truep .
4
+
5
+
0 6
new file mode 100644
... ...
@@ -0,0 +1,9 @@
1
+0 if 0 else 1 then . cr
2
+1 if 1 else 0 then . cr
3
+
4
+0 0 if 0 else if 0 else 1 then then . cr
5
+0 1 if if 0 else 1 then else 0 then . cr
6
+
7
+1 0 if 0 else if 1 else 0 then then . cr
8
+1 1 if if 1 else 0 then else 0 then . cr
9
+