This language has one looping structure, basic integer math, character I/O, and an accumulator (thus the name). Simple, right?
...
Again: justJust one accumulator. Thus, the name.
import re, sys
def main():
if len(sys.argv) != 2:
print("Please supply a filename on the command line.", file=sys.stderr)
return
codeFile = sys.argv[1]
with open(codeFile) as f:
code = f.readlines()
code = translate(code)
exec(code, {"inputStream": (ord(char) for char in input())})
def translate(accCode):
indent = 0
loopVars = []
pyCode = ["_ = 0"]
for lineNum, line in enumerate(accCode):
if "#" in line:
# Strip comments
line = line[:line.index("#")]
line = line.strip()
if not line:
continue
lineNum += 1
if line == "}":
if indent:
loopVar = loopVars.pop()
if loopVar is not None:
pyCode.append(" "*indent + loopVar + " += 1")
indent -= 1
else:
raise SyntaxError("Line %d: unmatched }" % lineNum)
else:
m = re.fullmatch(r"Count ([a-z]) while (.+) \{", line)
if m:
expression = validateExpression(m.group(2))
if expression:
loopVar = m.group(1)
pyCode.append(" "*indent + loopVar + " = 0")
pyCode.append(" "*indent + "while " + expression + ":")
indent += 1
loopVars.append(loopVar)
else:
raise SyntaxError("Line %d: invalid expression " % lineNum
+ m.group(2))
else:
m = re.fullmatch(r"Write (.+)", line)
if m:
expression = validateExpression(m.group(1))
if expression:
pyCode.append(" "*indent
+ "print(chr(%s), end='')" % expression)
else:
raise SyntaxError("Line %d: invalid expression "
% lineNum
+ m.group(1))
else:
expression = validateExpression(line)
if expression:
pyCode.append(" "*indent + "_ = " + expression)
else:
raise SyntaxError("Line %d: invalid statement "
% lineNum
+ line)
return "\n".join(pyCode)
def validateExpression(expr):
"Translates expr to Python expression or returns None if invalid."
expr = expr.strip()
if re.search(r"[^ 0-9a-z_N()*/%^+-]", expr):
# Expression contains invalid characters
return None
elif re.search(r"[a-zN_]\w+", expr):
# Expression contains multiple letters or underscores in a row
return None
else:
# Not going to check validity of all identifiers or nesting of parens--
# let the Python code throw an error if problems arise there
# Replace short operators with their Python versions
expr = expr.replace("^", "**")
expr = expr.replace("/", "//")
# Replace N with a call to get the next input character
expr = expr.replace("N", "inputStream.send(None)")
return expr
if __name__ == "__main__":
main()
Sample programs
Echo input to output (assumes input is null-terminated):
# Read charcode and store in accumulator
N
# While that's not 0, output the same thing and read/store another one
Count z while _ {
Write _
N
}
Output all printable ASCII characters:
Count i while i-95 {
Write i+32
}