Python 3, 1322 bytes
Golfed:
import re,sys;sys.setrecursionlimit(2000);F,L=filter,list
class P:
N,O,F=0,{},{}
def __init__(S,c):
S.B,S.E={"p":S.P,"i":S.I,"d":S.D,"a":S.L},dict(enumerate(F(None,[i.split('#')[0].rstrip()for i in c.splitlines()])))
while S.N in S.E:S.X(S.E[S.N])
def V(S, v, y, z=0):
if re.match("[\w_][\d\w_]*",v):
if not v in y:
if z is not None:y[v]=z
else:return False
return True
return False
def A(S):S.N+=1
def P(S,v):
if S.V(v,S.O):print("{0} = {1}".format(v, S.O[v]));return True
return False
def I(S,v):
if S.V(v, S.O):S.O[v]+=1;return True
return False
def D(S,v):
if S.V(v,S.O)and S.O[v]>0:S.O[v]-=1;return True
return False
def L(S,v):
e=[]
if S.V(v,S.F,e):
for i in range(3):S.A();e.append(S.E[S.N].lstrip())
return True
return False
def C(S,c,v):
def R(Z,v):
for i in re.findall("\s(\d+)", Z):Z=Z.replace(" %s"%i," %s"%v[int(i)-1])
return Z
Q,m,f=map(lambda l:R(l,v),S.F[c])
if S.X(Q,False):return S.X(m,False)
return S.X(f,False)
def X(S,Z,C=True):
u=re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?",Z)
if u:
c,v=map(lambda i:''if i is None else i,u.groups());v=L(F(None,v.split(' ')))
if S.V(c,S.F,None):
T=S.C(c, v)
if C:S.A()
elif S.V(c,S.B,None):
T=S.B[c](*v)
if C:S.A()
else:return False
return T
return False
Ungolfed:
import re
class Prindeal:
iline = 0
local = {}
udef = {}
content = {}
def __init__(self, c):
self.built = {
"p": self.print,
"i": self.increment,
"d": self.decrement,
"a": self.alias,
}
self.content = dict(enumerate(filter(None, [i.split('#')[0].rstrip()for i in c.splitlines()])))
while self.iline in self.content:
self.execute_line(self.content[self.iline])
def validate_name(self, varname, stack, default=0):
if re.match("[\w_][\d\w_]*", varname):
if not varname in stack:
if default is not None:
stack[varname] = default
else:
return False
return True
return False
def advance_stack(self):
self.iline += 1
def print(self, varname):
if self.validate_name(varname, self.local):
print("{0} = {1}".format(varname, self.local[varname]))
return True
return False
def increment(self, varname):
if self.validate_name(varname, self.local):
self.local[varname] += 1
return True
return False
def decrement(self, varname):
if self.validate_name(varname, self.local) and self.local[varname] > 0:
self.local[varname] -= 1
return True
return False
def alias(self, aliasname):
indexed_lines = []
if self.validate_name(aliasname, self.udef, indexed_lines):
for i in range(3):
self.advance_stack()
indexed_lines.append(self.content[self.iline].lstrip())
return True
return False
def execute_alias(self, cmd, variables):
def parse_args(line, variables):
for i in re.findall("\s(\d+)", line):
line = line.replace(" %s" % i, " %s" % variables[int(i) - 1])
return line
init, success, failure = map(lambda l: parse_args(l, variables), self.udef[cmd])
if self.execute_line(init, False):
return self.execute_line(success, False)
return self.execute_line(failure, False)
def execute_line(self, line, cont=True):
valid_execution = re.match("\s?([\w_][\d\w_]*)\s?([\w_][\d\w ]*)?", line)
if valid_execution:
cmd, variables = map(lambda i: '' if i is None else i, valid_execution.groups())
variables = list(filter(None, variables.split(' ')))
if self.validate_name(cmd, self.udef, None):
temp = self.execute_alias(cmd, variables)
if cont:
self.advance_stack()
elif self.validate_name(cmd, self.built, None):
temp = self.built[cmd](*variables)
if cont:
self.advance_stack()
else:
return False
return temp
return False
Usage:
P(c)
Where c is the text content.
Examples:
Single-line strings are accepted:
P("p cat")P("p dog\ni dog\np dog")
Multi-lined strings are also accepted:
P("""
p dog
i dog
p dog
""")
Or:
P("""p dog
i dog
p dog""")
Etc.
Notes:
This works correctly for all test cases, but reaches the recursion limit on:
pow C A B #C = A ^ B = 9 ^ 3 = 729
Hence the sys.setrecursionlimit(2000).
Zach Gates
- 6.7k
- 31
- 75