有时,希望模仿Python交互式解释器的行为,在输入不完整时(例如,您键入了“if”语句的开头,或者没有关闭括号或三个字符串引号),给出一个延续提示,但当输入无效时,立即给出一条语法错误消息。
在Python中,您可以使用 codeop
模块,该模块非常接近解析器的行为。例如,IDLE就使用了这个。
在C中执行此操作的最简单方法是调用 PyRun_InteractiveLoop()
(可能在单独的线程中)并让Python解释器为您处理输入。您还可以设置 PyOS_ReadlineFunctionPointer()
指向您的自定义输入函数。有关更多提示,请参阅 Modules/readline.c
和 Parser/myreadline.c
。
但是,有时必须在与其他应用程序相同的线程中运行嵌入式Python解释器,并且不能允许 PyRun_InteractiveLoop()
在等待用户输入时停止。那么另一个解决方案是调用 PyParser_ParseString()
并测试 e.error
等于 E_EOF
,如果等于,就意味着输入不完整。这是一个示例代码片段,未经测试,灵感来自Alex Farber的代码:
<span class="cp">#define PY_SSIZE_T_CLEAN</span>
<span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><node.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><errcode.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><grammar.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><parsetok.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><compile.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">testcomplete</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">code</span><span class="p">)</span>
<span class="cm">/* code should end in
*/</span>
<span class="cm">/* return -1 for error, 0 for incomplete, 1 for complete */</span>
<span class="p">{</span>
<span class="n">node</span> <span class="o">*</span><span class="n">n</span><span class="p">;</span>
<span class="n">perrdetail</span> <span class="n">e</span><span class="p">;</span>
<span class="n">n</span> <span class="o">=</span> <span class="n">PyParser_ParseString</span><span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="o">&</span><span class="n">_PyParser_Grammar</span><span class="p">,</span>
<span class="n">Py_file_input</span><span class="p">,</span> <span class="o">&</span><span class="n">e</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">n</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">e</span><span class="p">.</span><span class="n">error</span> <span class="o">==</span> <span class="n">E_EOF</span><span class="p">)</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">PyNode_Free</span><span class="p">(</span><span class="n">n</span><span class="p">);</span>
<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
www#gaodaima.com来源gaodai$ma#com搞$$代**码网搞代码
另一个解决方案是尝试使用 Py_CompileString()
编译接收到的字符串。如果编译时没有出现错误,请尝试通过调用 PyEval_EvalCode()
来执行返回的代码对象。否则,请将输入保存到以后。如果编译失败,找出是错误还是只需要更多的输入-从异常元组中提取消息字符串,并将其与字符串 “分析时意外的EOF” 进行比较。下面是使用GNUreadline库的完整示例(您可能希望在调用readline()时忽略 SIGINT ):
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><readline.h></span><span class="cp"></span>
<span class="cp">#define PY_SSIZE_T_CLEAN</span>
<span class="cp">#include</span> <span class="cpf"><Python.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><object.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><compile.h></span><span class="cp"></span>
<span class="cp">#include</span> <span class="cpf"><eval.h></span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span><span class="o">*</span> <span class="n">argv</span><span class="p">[])</span>
<span class="p">{</span>
<span class="kt">int</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">done</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* lengths of line, code */</span>
<span class="kt">char</span> <span class="n">ps1</span><span class="p">[]</span> <span class="o">=</span> <span class="s">">>> "</span><span class="p">;</span>
<span class="kt">char</span> <span class="n">ps2</span><span class="p">[]</span> <span class="o">=</span> <span class="s">"... "</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">prompt</span> <span class="o">=</span> <span class="n">ps1</span><span class="p">;</span>
<span class="kt">char</span> <span class="o">*</span><span class="n">msg</span><span class="p">,</span> <span class="o">*</span><span class="n">line</span><span class="p">,</span> <span class="o">*</span><span class="n">code</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">PyObject</span> <span class="o">*</span><span class="n">src</span><span class="p">,</span> <span class="o">*</span><span class="n">glb</span><span class="p">,</span> <span class="o">*</span><span class="n">loc</span><span class="p">;</span>
<span class="n">PyObject</span> <span class="o">*</span><span class="n">exc</span><span class="p">,</span> <span class="o">*</span><span class="n">val</span><span class="p">,</span> <span class="o">*</span><span class="n">trb</span><span class="p">,</span> <span class="o">*</span><span class="n">obj</span><span class="p">,</span> <span class="o">*</span><span class="n">dum</span><span class="p">;</span>
<span class="n">Py_Initialize</span> <span class="p">();</span>
<span class="n">loc</span> <span class="o">=</span> <span class="n">PyDict_New</span> <span class="p">();</span>
<span class="n">glb</span> <span class="o">=</span> <span class="n">PyDict_New</span> <span class="p">();</span>
<span class="n">PyDict_SetItemString</span> <span class="p">(</span><span class="n">glb</span><span class="p">,</span> <span class="s">"__builtins__"</span><span class="p">,</span> <span class="n">PyEval_GetBuiltins</span> <span class="p">());</span>
<span class="k">while</span> <span class="p">(</span><span class="o">!</span><span class="n">done</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">line</span> <span class="o">=</span> <span class="n">readline</span> <span class="p">(</span><span class="n">prompt</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">line</span><span class="p">)</span> <span class="cm">/* Ctrl-D pressed */</span>
<span class="p">{</span>
<span class="n">done</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="n">i</span> <span class="o">=</span> <span class="n">strlen</span> <span class="p">(</span><span class="n">line</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">i</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span>
<span class="n">add_history</span> <span class="p">(</span><span class="n">line</span><span class="p">);</span> <span class="cm">/* save non-empty lines */</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">code</span><span class="p">)</span> <span class="cm">/* nothing in code yet */</span>
<span class="n">j</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">else</span>
<span class="n">j</span> <span class="o">=</span> <span class="n">strlen</span> <span class="p">(</span><span class="n">code</span><span class="p">);</span>
<span class="n">code</span> <span class="o">=</span> <span class="n">realloc</span> <span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="n">i</span> <span class="o">+</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">2</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">==</span> <span class="n">code</span><span class="p">)</span> <span class="cm">/* out of memory */</span>
<span class="n">exit</span> <span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="mi">0</span> <span class="o">==</span> <span class="n">j</span><span class="p">)</span> <span class="cm">/* code was empty, so */</span>
<span class="n">code</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">""</span><span class="p">;</span> <span class="cm">/* keep strncat happy */</span>
<span class="n">strncat</span> <span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="n">line</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="cm">/* append line to code */</span>
<span class="n">code</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span><span class="p">]</span> <span class="o">=</span> <span class="sc">"
"</span><span class="p">;</span> <span class="cm">/* append "
" to code */</span>
<span class="n">code</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span> <span class="o">+</span> <span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="sc">""</span><span class="p">;</span>
<span class="n">src</span> <span class="o">=</span> <span class="n">Py_CompileString</span> <span class="p">(</span><span class="n">code</span><span class="p">,</span> <span class="s">"<stdin>"</span><span class="p">,</span> <span class="n">Py_single_input</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nb">NULL</span> <span class="o">!=</span> <span class="n">src</span><span class="p">)</span> <span class="cm">/* compiled just fine - */</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">ps1</span> <span class="o">==</span> <span class="n">prompt</span> <span class="o">||</span> <span class="cm">/* ">>> " or */</span>
<span class="sc">"
"</span> <span class="o">==</span> <span class="n">code</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="n">j</span> <span class="o">-</span> <span class="mi">1</span><span class="p">])</span> <span class="cm">/* "... " and double "
" */</span>
<span class="p">{</span> <span class="cm">/* so execute it */</span>
<span class="n">dum</span> <span class="o">=</span> <span class="n">PyEval_EvalCode</span> <span class="p">(</span><span class="n">src</span><span class="p">,</span> <span class="n">glb</span><span class="p">,</span> <span class="n">loc</span><span class="p">);</span>
<span class="n">Py_XDECREF</span> <span class="p">(</span><span class="n">dum</span><span class="p">);</span>
<span class="n">Py_XDECREF</span> <span class="p">(</span><span class="n">src</span><span class="p">);</span>
<span class="n">free</span> <span class="p">(</span><span class="n">code</span><span class="p">);</span>
<span class="n">code</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">PyErr_Occurred</span> <span class="p">())</span>
<span class="n">PyErr_Print</span> <span class="p">();</span>
<span class="n">prompt</span> <span class="o">=</span> <span class="n">ps1</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span> <span class="cm">/* syntax error or E_EOF? */</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">PyErr_ExceptionMatches</span> <span class="p">(</span><span class="n">PyExc_SyntaxError</span><span class="p">))</span>
<span class="p">{</span>
<span class="n">PyErr_Fetch</span> <span class="p">(</span><span class="o">&</span><span class="n">exc</span><span class="p">,</span> <span class="o">&</span><span class="n">val</span><span class="p">,</span> <span class="o">&</span><span class="n">trb</span><span class="p">);</span> <span class="cm">/* clears exception! */</span>
<span class="k">if</span> <span class="p">(</span><span class="n">PyArg_ParseTuple</span> <span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="s">"sO"</span><span class="p">,</span> <span class="o">&</span><span class="n">msg</span><span class="p">,</span> <span class="o">&</span><span class="n">obj</span><span class="p">)</span> <span class="o">&&</span>
<span class="o">!</span><span class="n">strcmp</span> <span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="s">"unexpected EOF while parsing"</span><span class="p">))</span> <span class="cm">/* E_EOF */</span>
<span class="p">{</span>
<span class="n">Py_XDECREF</span> <span class="p">(</span><span class="n">exc</span><span class="p">);</span>
<span class="n">Py_XDECREF</span> <span class="p">(</span><span class="n">val</span><span class="p">);</span>
<span class="n">Py_XDECREF</span> <span class="p">(</span><span class="n">trb</span><span class="p">);</span>
<span class="n">prompt</span> <span class="o">=</span> <span class="n">ps2</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">else</span> <span class="cm">/* some other syntax error */</span>
<span class="p">{</span>
<span class="n">PyErr_Restore</span> <span class="p">(</span><span class="n">exc</span><span class="p">,</span> <span class="n">val</span><span class="p">,</span> <span class="n">trb</span><span class="p">);</span>
<span class="n">PyErr_Print</span> <span class="p">();</span>
<span class="n">free</span> <span class="p">(</span><span class="n">code</span><span class="p">);</span>
<span class="n">code</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">prompt</span> <span class="o">=</span> <span class="n">ps1</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">else</span> <span class="cm">/* some non-syntax error */</span>
<span class="p">{</span>
<span class="n">PyErr_Print</span> <span class="p">();</span>
<span class="n">free</span> <span class="p">(</span><span class="n">code</span><span class="p">);</span>
<span class="n">code</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
<span class="n">prompt</span> <span class="o">=</span> <span class="n">ps1</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">free</span> <span class="p">(</span><span class="n">line</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">glb</span><span class="p">);</span>
<span class="n">Py_XDECREF</span><span class="p">(</span><span class="n">loc</span><span class="p">);</span>
<span class="n">Py_Finalize</span><span class="p">();</span>
<span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span>
<span class="p">}</span>
来源:搞代码网:原文地址:https://www.gaodaima.com