Created
January 23, 2021 03:25
-
-
Save darius/e2a068dbd7c17b5985c88f1c508d3ce8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| """ | |
| derived from Kragen Sitaker's http://canonical.org/~kragen/sw/dev3/caronte.py | |
| """ | |
| from __future__ import division, print_function | |
| import itertools | |
| import grammars | |
| from semantics import ast_semantics, ComboSemantics, DictSemantics | |
| grammar_text = r""" | |
| start : _ expr. | |
| expr : e10 ++ (';'_ [:drop]). | |
| e10 : lvalue ( ':='_ e10 [:put] | |
| | '='_ e10 [:init] ) | |
| | e40. | |
| lvalue : id ([:fetch] '['_ expr ']'_)*. | |
| e40 : lvalue '<-'_ e60 '|'_ [:mklabel] >AGAIN [:mklabel] >LOOP | |
| [@LOOP :each] | |
| @AGAIN | |
| e40 | |
| @LOOP [@AGAIN :loop] | |
| | e60. | |
| e60 : e65 ( '?'_ [:mklabel] >ELSE [:mklabel] >THEN | |
| [@ELSE :unless] | |
| e65 | |
| ':'_ [@THEN :jump] | |
| @ELSE | |
| e60 | |
| @THEN | |
| )?. | |
| e65 : e70 ('=='_ e70 [:eq])?. | |
| e70 : e110 ('+'_ e110 [:add])*. | |
| e110 : e120 ( '['_ expr ']'_ [:fetch] | |
| | '('_ actuals ')'_ [:call] | |
| )*. | |
| e120 : '('_ expr ')'_ | |
| | id [:fetch] | |
| | string :con | |
| | integer :con | |
| | '{'_ '}'_ [:newdict]. | |
| actuals : (e40 [:arg]) ** (','_). | |
| id : { /[A-Za-z_]/ /\w/* } _ :id. | |
| string : '"' { (/[^\\"]/ | '\\' /./)* } '"' _. | |
| integer : { /\d/+ } _ :int. | |
| _ : /\s/*. | |
| """ | |
| def Caronte(make_parsing): | |
| def caronte(s, rule=None): | |
| return caronte.grammar.parse(s, rule).interpret(caronte_actions) | |
| caronte.grammar = grammars.Grammar(grammar_text, make_parsing) | |
| return caronte | |
| gensym_counter = itertools.count() | |
| def mklabel(): return '_%d' % next(gensym_counter) | |
| caronte_actions = ComboSemantics(ast_semantics, DictSemantics(dict(int=int, mklabel=mklabel))) | |
| ## from nonincremental import Parsing | |
| ## parse = Caronte(Parsing) | |
| ## parse("a", rule='id') | |
| #. (('id', 'a'),) | |
| ## parse("a[42] := b") | |
| #. (('id', 'a'), ('fetch',), ('con', 42), ('id', 'b'), ('fetch',), ('put',)) | |
| def run(prog): | |
| insns = [] | |
| # Assembler pass 1 | |
| labels = {} | |
| for line in prog: | |
| if isinstance(line, str): # label | |
| assert line not in labels | |
| labels[line] = len(insns) | |
| else: | |
| insns.append(line) | |
| # Assembler pass 2 | |
| for i, line in enumerate(insns): | |
| if line[0] in ('each', 'loop', 'unless', 'jump'): | |
| insns[i] = (line[0], labels[line[1]]) | |
| pc = 0 | |
| ram = {'iota': lambda n: list(range(n)), 'say': lambda v: print(*v, end='')} | |
| stack = [] | |
| args = [] | |
| loops = [] | |
| # Now run it | |
| ninsns = len(insns) | |
| while pc < ninsns: | |
| insn = insns[pc] | |
| c = insn[0] | |
| if c == 'newdict': | |
| stack.append({}) | |
| elif c == 'drop': | |
| stack.pop() | |
| elif c == 'con': | |
| stack.append(insn[1]) | |
| elif c == 'add': | |
| x = stack.pop() | |
| stack.append(stack.pop() + x) | |
| elif c == 'eq': | |
| x = stack.pop() | |
| stack.append('true' if stack.pop() == x else 'false') | |
| elif c == 'arg': | |
| args.append(stack.pop()) | |
| elif c == 'call': | |
| f = stack.pop() | |
| stack.append(f(*args)) | |
| args = [] | |
| elif c == 'id': | |
| stack.append(ram) | |
| stack.append(insn[1]) | |
| elif c == 'fetch': | |
| idx = stack.pop() | |
| loc = stack.pop() | |
| stack.append(loc[idx]) | |
| elif c in ('init', 'put'): | |
| val = stack.pop() | |
| idx = stack.pop() | |
| loc = stack.pop() | |
| loc[idx] = val | |
| stack.append(val) | |
| elif c == 'each': | |
| seq = stack.pop() | |
| idx = stack.pop() | |
| loc = stack.pop() | |
| loops.append([loc, idx, seq, 0]) | |
| pc = insn[1] | |
| continue | |
| elif c == 'loop': | |
| loc, off, seq, idx = loops[-1] | |
| if idx >= len(seq): | |
| loops.pop() | |
| pc += 1 | |
| stack.append(seq) # was missing from Kragen's; I think it's the desired semantics? | |
| continue | |
| loc[off] = seq[idx] | |
| loops[-1][-1] += 1 | |
| pc = insn[1] | |
| continue | |
| elif c == 'unless': | |
| x = stack.pop() | |
| assert x in ('true', 'false') | |
| if x == 'false': | |
| pc = insn[1] | |
| continue | |
| elif c == 'jump': | |
| pc = insn[1] | |
| continue | |
| else: | |
| assert 0, "bad insn %r at %d" % (c, pc) | |
| pc += 1 | |
| # Smoke test | |
| sier = """ | |
| c = {}; | |
| x <- iota(128) | (c[x] = 0); | |
| c[0] := 1; | |
| y <- iota(128) | ( | |
| x <- iota(127) | (c[x+1] := (c[x] + c[x+1] == 1) ? 1 : 0); | |
| x <- iota(128) | say((c[x] == 0) ? " " : "#"); | |
| say("\n") | |
| ) | |
| """ | |
| def testme(): | |
| from nonincremental import Parsing | |
| parser = Caronte(Parsing) | |
| prog = parser(sier) | |
| for line in prog: print(line) | |
| print() | |
| run(prog) | |
| if __name__ == '__main__': | |
| testme() | |
| ## testme() | |
| #. ('id', 'c') | |
| #. ('newdict',) | |
| #. ('init',) | |
| #. ('drop',) | |
| #. ('id', 'x') | |
| #. ('id', 'iota') | |
| #. ('fetch',) | |
| #. ('con', 128) | |
| #. ('arg',) | |
| #. ('call',) | |
| #. ('each', '_1') | |
| #. _0 | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('id', 'x') | |
| #. ('fetch',) | |
| #. ('con', 0) | |
| #. ('init',) | |
| #. _1 | |
| #. ('loop', '_0') | |
| #. ('drop',) | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('con', 0) | |
| #. ('con', 1) | |
| #. ('put',) | |
| #. ('drop',) | |
| #. ('id', 'y') | |
| #. ('id', 'iota') | |
| #. ('fetch',) | |
| #. ('con', 128) | |
| #. ('arg',) | |
| #. ('call',) | |
| #. ('each', '_3') | |
| #. _2 | |
| #. ('id', 'x') | |
| #. ('id', 'iota') | |
| #. ('fetch',) | |
| #. ('con', 127) | |
| #. ('arg',) | |
| #. ('call',) | |
| #. ('each', '_5') | |
| #. _4 | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('id', 'x') | |
| #. ('fetch',) | |
| #. ('con', 1) | |
| #. ('add',) | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('id', 'x') | |
| #. ('fetch',) | |
| #. ('fetch',) | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('id', 'x') | |
| #. ('fetch',) | |
| #. ('con', 1) | |
| #. ('add',) | |
| #. ('fetch',) | |
| #. ('add',) | |
| #. ('con', 1) | |
| #. ('eq',) | |
| #. ('unless', '_6') | |
| #. ('con', 1) | |
| #. ('jump', '_7') | |
| #. _6 | |
| #. ('con', 0) | |
| #. _7 | |
| #. ('put',) | |
| #. _5 | |
| #. ('loop', '_4') | |
| #. ('drop',) | |
| #. ('id', 'x') | |
| #. ('id', 'iota') | |
| #. ('fetch',) | |
| #. ('con', 128) | |
| #. ('arg',) | |
| #. ('call',) | |
| #. ('each', '_9') | |
| #. _8 | |
| #. ('id', 'say') | |
| #. ('fetch',) | |
| #. ('id', 'c') | |
| #. ('fetch',) | |
| #. ('id', 'x') | |
| #. ('fetch',) | |
| #. ('fetch',) | |
| #. ('con', 0) | |
| #. ('eq',) | |
| #. ('unless', '_10') | |
| #. ('con', ' ') | |
| #. ('jump', '_11') | |
| #. _10 | |
| #. ('con', '#') | |
| #. _11 | |
| #. ('arg',) | |
| #. ('call',) | |
| #. _9 | |
| #. ('loop', '_8') | |
| #. ('drop',) | |
| #. ('id', 'say') | |
| #. ('fetch',) | |
| #. ('con', '\n') | |
| #. ('arg',) | |
| #. ('call',) | |
| #. _3 | |
| #. ('loop', '_2') | |
| #. | |
| #. ################################################################################################################################ | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### #### | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # | |
| #. ######## ######## ######## ######## ######## ######## ######## ######## | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # | |
| #. #### #### #### #### #### #### #### #### | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. ################ ################ ################ ################ | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # | |
| #. #### #### #### #### #### #### #### #### | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. ######## ######## ######## ######## | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ################################ ################################ | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # | |
| #. #### #### #### #### #### #### #### #### | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. ######## ######## ######## ######## | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ################ ################ | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ######## ######## | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. #### #### | |
| #. # # # # | |
| #. ## ## | |
| #. # # | |
| #. ################################################################ | |
| #. # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # # # # # # # # # | |
| #. #### #### #### #### #### #### #### #### | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. ######## ######## ######## ######## | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ################ ################ | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ######## ######## | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. #### #### | |
| #. # # # # | |
| #. ## ## | |
| #. # # | |
| #. ################################ | |
| #. # # # # # # # # # # # # # # # # | |
| #. ## ## ## ## ## ## ## ## | |
| #. # # # # # # # # | |
| #. #### #### #### #### | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. ######## ######## | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. #### #### | |
| #. # # # # | |
| #. ## ## | |
| #. # # | |
| #. ################ | |
| #. # # # # # # # # | |
| #. ## ## ## ## | |
| #. # # # # | |
| #. #### #### | |
| #. # # # # | |
| #. ## ## | |
| #. # # | |
| #. ######## | |
| #. # # # # | |
| #. ## ## | |
| #. # # | |
| #. #### | |
| #. # # | |
| #. ## | |
| #. # |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment