Embedding to C++: hooking up GNU readline

Alex Farber farber at cpan.org
Fri Mar 3 17:09:19 EST 2000


Hi,

Alex Farber wrote:
> Now the bad thing is, that I can not say if Py_CompileString() failed
> because of "not enough data" or because of "syntax error". That's why

in tradition of replying to my own messages, here is another method -
using Py_CompileString() and PyEval_EvalCode(). It looks cleaner to me,
because only Python.h have to be included and the _PyParser_Grammar is 
not used. I am not sure if there any bugs.

Regards
Alex

/* Q: How to distinguish between "syntax error" and "not enough input"? */
/* A: Py_CompileString() + PyEval_EvalCode() */

/* gcc -I/usr/include/python -I/usr/include/readline -lpython1.5 -lreadline -o compile compile.c */

#include <stdio.h>
#include <readline.h>
        
#include <Python.h>

int main (int argc, char* argv[])
{       
  int i, j, done = 0;                                                /* lengths of line, code */
  char ps1[] = ">>> ";                                     
  char ps2[] = "... ";
  char *prompt = ps1;
  char *msg, *line, *code = NULL;                          
  PyObject *src, *glb, *loc;
  PyObject *exc, *val, *trb, *obj;                         

  Py_Initialize ();
  loc = PyDict_New ();
  glb = PyDict_New (); 
  PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ());
        
  while (!done)
  {   
    line = readline (prompt);
        
    if (NULL == line ||                                              /* CTRL-D pressed */
        0 == strcmp (line, "quit") ||                      
        0 == strcmp (line, "exit"))  
    {       
      done = 1;
    }     
    else  
    {
      i = strlen (line);

      if (i > 0)
        add_history (line);                                          /* save non-empty lines */

      if (NULL == code)                                              /* nothing in code yet */
        j = 0;
      else
        j = strlen (code);

      code = realloc (code, i + j + 2);
      if (NULL == code)                                              /* out of memory */
        exit (1);
  
      if (0 == j)                                                    /* code was empty, so */
        code[0] = '\0';                                              /* keep strcat happy */
  
      strcat (code, line);                                           /* append line to code */
      code[i + j] = '\n';                                            /* append '\n' to code */
      code[i + j + 1] = '\0';
  
      src = Py_CompileString (code, "<stdin>", Py_file_input);       /* or Py_single_input? */
  
      if (NULL != src)                                               /* compiled just fine - */
      {
        if (ps1  == prompt ||                                        /* ">>> " or */
            '\n' == code[i + j - 1])                                 /* "... " and double '\n' */
        {
          PyEval_EvalCode (src, glb, loc);                           /* so execute it */
          Py_XDECREF(src);
          free (code);
          code = NULL;
          if (PyErr_Occurred ())
            PyErr_Print ();
          prompt = ps1;
        }
      }
      else if (PyErr_ExceptionMatches (PyExc_SyntaxError))           /* syntax error or E_EOF? */
      {
        PyErr_Fetch (&exc, &val, &trb);                              /* clears exception! */

        if (PyArg_ParseTuple (val, "sO", &msg, &obj) &&              /* string + object */
            !strcmp (msg, "unexpected EOF while parsing"))           /* not enough input */
        {
          Py_XDECREF (exc);
          Py_XDECREF (val);
          Py_XDECREF (trb);
          prompt = ps2;
        }
        else                                                         /* some other syntax error */
        {
          PyErr_Restore (exc, val, trb);
          PyErr_Print ();
          free (code);
          code = NULL;
          prompt = ps1;
        }
      }
      else                                                   /* some non-syntax error */
      {
        PyErr_Print ();
        free (code);
        code = NULL;
        prompt = ps1;
      }
    }

    free (line);
  }

  Py_XDECREF(glb);
  Py_XDECREF(loc);
  Py_Finalize();
  exit(0);
}



More information about the Python-list mailing list