For trying things out, unlike bc, gawk lack a REPL
I made a simple REPL for gawk, for trying things out.
Code:
# igawk.py
import sys
from subprocess import Popen, PIPE
class UserInput:
def __init__(self, inp):
self.inp = inp
self.output_chars = [0,0]
class Runner:
def __init__(self, name, args):
self.user_input = []
self.compile_error = ""
self.input_num = 0
self.prog = name + args
self.prompt = name + ":%d> "
self.output_chars = [0,0]
def read_line(self):
while 1:
prompt = self.prompt
if prompt: prompt = prompt % (self.input_num + 1)
line = raw_input(prompt)
if line == '\\': line = '\t'.join(sys.stdin.readlines())
line = line.strip()
if line: return line
def do_run(self):
while 1:
line = self.read_line()
type = dot_cmd_process(self, line)
if type is None: continue # DOT cmd processed
if type == 'INPUT': # add line + run_awk
if line[0] == '=': # shorthand for print ...
line = 'print ' + line[1:]
line += ')' * (line.count('(') - line.count(')'))
last = UserInput(line)
try: self.user_input[self.input_num] = last
except IndexError: self.user_input.append(last)
self.input_num += 1
else:
last = self.user_input[self.input_num - 1]
run = Popen(self.prog, stdin=PIPE, stdout=PIPE, stderr=PIPE)
outputs = run.communicate(self.get_source())
if run.returncode:
self.compile_error = '\n'.join(outputs)
print "[Compile error - type .e to see it.]"
dot_u(self)
continue
for i, output in enumerate(outputs):
n = len(output) - self.output_chars[i]
if not n: continue
last.output_chars[i] = n
self.output_chars[i] += n
print output[-n:]
def get_user_input(self):
return self.user_input[:self.input_num]
def get_source(self):
code = [ line.inp for line in self.get_user_input() ]
return 'BEGIN {\n%s\n}' % ';\n'.join(code)
def dot_q(runner): raise EOFError()
def dot_e(runner): print runner.compile_error
def dot_l(runner, i=0):
for line in runner.get_user_input():
i = i+1
print "%d\t%s" % (i, line.inp)
def dot_r(runner):
n = runner.input_num
if n < len(runner.user_input):
runner.input_num = n + 1
redo = runner.user_input[n]
print "[Redo '%s'.]" % redo.inp
return redo # execute command again!
else:
print "[Nothing to redo.]"
def dot_u(runner):
n = runner.input_num
if n:
runner.input_num = n = n - 1
undone = runner.user_input[n]
runner.output_chars[0] -= undone.output_chars[0]
runner.output_chars[1] -= undone.output_chars[1]
print "[Undone '%s'.]" % undone.inp
else:
print "[Nothing to undo.]"
def dot_U(runner):
runner.compile_error = ""
runner.input_num = 0
runner.output_chars = [0,0]
print "[Undo ALL]"
def dot_h(runner):
for cmd in sorted(dot_cmds, key=str.lower):
print cmd, dot_cmds[cmd][0]
def dot_cmd_process(runner, inp):
if inp not in dot_cmds: return 'INPUT'
return dot_cmds[inp][1]( runner )
dot_cmds = {
".h" : ( "Show this help message", dot_h ),
".q" : ( "Quit", dot_q ),
".e" : ( "Show the last compile errors/warnings", dot_e ),
".l" : ( "List the code you have entered", dot_l ),
".r" : ( "Redo undone command", dot_r ),
".u" : ( "Undo previous command", dot_u ),
".U" : ( "Undo all commands", dot_U),
}
if __name__ == '__main__':
prog = 'gawk' if len(sys.argv)==1 else sys.argv[1]
args = ' -vOFMT="%.17g" -vORS="" -f -'
if prog == 'perl': args = ' -'
elif prog == 'awk' : pass # NOTE: 53-bits rounding
elif prog != 'gawk': prog = None # Force TypeError
try: Runner(prog, args).do_run()
except EOFError: pass # Ctrl-Z to exit
except TypeError: print "Usage: igawk.py [perl | awk | gawk]"
Example, below trick returns base^(-precision), both decimal and binary system
> igawk.py
gawk:1> x = 1/3
gawk:2> = 1-x-x-x
1.1102230246251565e-016