Reputation: 37
In the program I am writing (a text-based rpg) I am going to include 'scripts', little pieces of code that add interactive functionality to the game (such as an NPC greeting you when you enter a room). Writing my own scripting language/parser seemed like a pretty big task so I thought I'd use Python code itself instead. It can do everything I will need out of the scripts so I started hacking away. For simple things like print statements or math, exec() is working fine. It's when I have a block that trouble arises. Here it is in action:
First - working code (from interactive shell):
>>> x = ''
>>> y = []
>>> while x != '@':
y.append(x)
x = raw_input(compile('''''', '<string>', 'exec'))
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>name = 'Drew'
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>print 'Hello, %s' % name
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>@
>>> del x[0] # removes the empty field created by the first y.append(x)
>>> for line in y:
exec line
>>> Hello, Drew
Now for the error (again from interactive prompt):
>>> x = ''
>>> y = []
>>> while x != '@':
y.append(x)
x = raw_input(compile('''''', '<string>', 'exec'))
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>name = 'Drew'
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>if name == 'Drew':
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>print 'Hi, %s!' % name
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>else:
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>print 'Greetings, stranger.'
<code object <module> at 0000000002B1DBB0, file "<string>", line 1>@
>>> del y[0]
>>> for line in y:
exec line
Traceback (most recent call last):
File "<pyshell#308>", line 2, in <module>
exec line
File "<string>", line 1
if name == 'Drew':
^
SyntaxError: unexpected EOF while parsing
So as you see, the : character (which is required for selection blocks) causes exec to error. Is there anything I can do to fix this? I've attempted to get around this for hours but I can't seem to figure it out. Is it simply not possible?
Thank you very much for reading this and I appreciate all help given to me.
Upvotes: 2
Views: 2077
Reputation: 19154
The following works in 2.7 when run from an IDLE edit window:
line=''
lines = []
print "Enter Python lines (@ to quit):"
while line != '@':
line=raw_input()
lines.append(line)
lines.pop() # delete '@' line
lines = '\n'.join(lines)
exec lines
The result in the Shell window:
>>>
Enter Python lines (@ to quit):
name = 'Terry'
if name == 'Drew':
print 'Hi Drew'
else:
print 'Hi stranger'
@
Hi stranger
Note that lines need to be joined with '\n', not ''. Also, after joining, the snippet does not end with '\n'. I believe this may be a problem of with earlier versions of Python, where exec may have needed a terminal '\n' for multiline blocks.
That said, this is an AWFUL way to enter code. It took me three tries to enter the above without error! Much better for both initial entry and editing would be, for instance, a tkinter text box widget.
Upvotes: 2
Reputation: 273526
You use exec
to evaluate a single line. In this code:
if a == b:
do_c()
The first line, evaluated by itself, is a syntax error. The above can be also folded to a single line as:
if a == b: do_c()
In the more general case, allowing multiple lines, what you could do is collect the whole input into a string (with correct whitespace), then call exec
on that:
source = '''
name = "joe"
if name == "joe":
print "hi joe"
else:
print "hi stranger"
'''
exec source
You're already figured out to end the input with a special char (@
), but you should also expect your user to provide correct whitespace for Python if he needs to write multi-line statements.
Upvotes: 4