3279 lines · 93.5 KB · C
RawDownload
/*  parsermodule.c * *  Copyright 1995-1996 by Fred L. Drake, Jr. and Virginia Polytechnic *  Institute and State University, Blacksburg, Virginia, USA. *  Portions copyright 1991-1995 by Stichting Mathematisch Centrum, *  Amsterdam, The Netherlands.  Copying is permitted under the terms *  associated with the main Python distribution, with the additional *  restriction that this additional notice be included and maintained *  on all distributed copies. * *  This module serves to replace the original parser module written *  by Guido.  The functionality is not matched precisely, but the *  original may be implemented on top of this.  This is desirable *  since the source of the text to be parsed is now divorced from *  this interface. * *  Unlike the prior interface, the ability to give a parse tree *  produced by Python code as a tuple to the compiler is enabled by *  this module.  See the documentation for more details. * *  I've added some annotations that help with the lint code-checking *  program, but they're not complete by a long shot.  The real errors *  that lint detects are gone, but there are still warnings with *  Py_[X]DECREF() and Py_[X]INCREF() macros.  The lint annotations *  look like "NOTE(...)". */ #include "Python.h"                     /* general Python API             */#include "graminit.h"                   /* symbols defined in the grammar */#include "node.h"                       /* internal parser structure      */#include "errcode.h"                    /* error codes for PyNode_*()     */#include "token.h"                      /* token definitions              */                                        /* ISTERMINAL() / ISNONTERMINAL() */#include "compile.h"                    /* PyNode_Compile()               */ #ifdef lint#include <note.h>#else#define NOTE(x)#endif /*  String constants used to initialize module attributes. * */static char parser_copyright_string[] ="Copyright 1995-1996 by Virginia Polytechnic Institute & State\n\University, Blacksburg, Virginia, USA, and Fred L. Drake, Jr., Reston,\n\Virginia, USA.  Portions copyright 1991-1995 by Stichting Mathematisch\n\Centrum, Amsterdam, The Netherlands.";  PyDoc_STRVAR(parser_doc_string,"This is an interface to Python's internal parser."); static char parser_version_string[] = "0.5";  typedef PyObject* (*SeqMaker) (Py_ssize_t length);typedef int (*SeqInserter) (PyObject* sequence,                            Py_ssize_t index,                            PyObject* element); /*  The function below is copyrighted by Stichting Mathematisch Centrum.  The *  original copyright statement is included below, and continues to apply *  in full to the function immediately following.  All other material is *  original, copyrighted by Fred L. Drake, Jr. and Virginia Polytechnic *  Institute and State University.  Changes were made to comply with the *  new naming conventions.  Added arguments to provide support for creating *  lists as well as tuples, and optionally including the line numbers. */  static PyObject*node2tuple(node *n,                     /* node to convert               */           SeqMaker mkseq,              /* create sequence               */           SeqInserter addelem,         /* func. to add elem. in seq.    */           int lineno)                  /* include line numbers?         */{    if (n == NULL) {        Py_INCREF(Py_None);        return (Py_None);    }    if (ISNONTERMINAL(TYPE(n))) {        int i;        PyObject *v;        PyObject *w;         v = mkseq(1 + NCH(n) + (TYPE(n) == encoding_decl));        if (v == NULL)            return (v);        w = PyInt_FromLong(TYPE(n));        if (w == NULL) {            Py_DECREF(v);            return ((PyObject*) NULL);        }        (void) addelem(v, 0, w);        for (i = 0; i < NCH(n); i++) {            w = node2tuple(CHILD(n, i), mkseq, addelem, lineno);            if (w == NULL) {                Py_DECREF(v);                return ((PyObject*) NULL);            }            (void) addelem(v, i+1, w);        }         if (TYPE(n) == encoding_decl)            (void) addelem(v, i+1, PyString_FromString(STR(n)));        return (v);    }    else if (ISTERMINAL(TYPE(n))) {        PyObject *result = mkseq(2 + lineno);        if (result != NULL) {            (void) addelem(result, 0, PyInt_FromLong(TYPE(n)));            (void) addelem(result, 1, PyString_FromString(STR(n)));            if (lineno == 1)                (void) addelem(result, 2, PyInt_FromLong(n->n_lineno));        }        return (result);    }    else {        PyErr_SetString(PyExc_SystemError,                        "unrecognized parse tree node type");        return ((PyObject*) NULL);    }}/* *  End of material copyrighted by Stichting Mathematisch Centrum. */   /*  There are two types of intermediate objects we're interested in: *  'eval' and 'exec' types.  These constants can be used in the st_type *  field of the object type to identify which any given object represents. *  These should probably go in an external header to allow other extensions *  to use them, but then, we really should be using C++ too.  ;-) */ #define PyST_EXPR  1#define PyST_SUITE 2  /*  These are the internal objects and definitions required to implement the *  ST type.  Most of the internal names are more reminiscent of the 'old' *  naming style, but the code uses the new naming convention. */ static PyObject*parser_error = 0;  typedef struct {    PyObject_HEAD                       /* standard object header           */    node* st_node;                      /* the node* returned by the parser */    int   st_type;                      /* EXPR or SUITE ?                  */} PyST_Object;  static void parser_free(PyST_Object *st);static int parser_compare(PyST_Object *left, PyST_Object *right);static PyObject *parser_getattr(PyObject *self, char *name);  staticPyTypeObject PyST_Type = {    PyObject_HEAD_INIT(NULL)    0,    "parser.st",                        /* tp_name              */    (int) sizeof(PyST_Object),          /* tp_basicsize         */    0,                                  /* tp_itemsize          */    (destructor)parser_free,            /* tp_dealloc           */    0,                                  /* tp_print             */    parser_getattr,                     /* tp_getattr           */    0,                                  /* tp_setattr           */    (cmpfunc)parser_compare,            /* tp_compare           */    0,                                  /* tp_repr              */    0,                                  /* tp_as_number         */    0,                                  /* tp_as_sequence       */    0,                                  /* tp_as_mapping        */    0,                                  /* tp_hash              */    0,                                  /* tp_call              */    0,                                  /* tp_str               */    0,                                  /* tp_getattro          */    0,                                  /* tp_setattro          */     /* Functions to access object as input/output buffer */    0,                                  /* tp_as_buffer         */     Py_TPFLAGS_DEFAULT,                 /* tp_flags             */     /* __doc__ */    "Intermediate representation of a Python parse tree."};  /* PyST_Type */  static intparser_compare_nodes(node *left, node *right){    int j;     if (TYPE(left) < TYPE(right))        return (-1);     if (TYPE(right) < TYPE(left))        return (1);     if (ISTERMINAL(TYPE(left)))        return (strcmp(STR(left), STR(right)));     if (NCH(left) < NCH(right))        return (-1);     if (NCH(right) < NCH(left))        return (1);     for (j = 0; j < NCH(left); ++j) {        int v = parser_compare_nodes(CHILD(left, j), CHILD(right, j));         if (v != 0)            return (v);    }    return (0);}  /*  int parser_compare(PyST_Object* left, PyST_Object* right) * *  Comparison function used by the Python operators ==, !=, <, >, <=, >= *  This really just wraps a call to parser_compare_nodes() with some easy *  checks and protection code. * */static intparser_compare(PyST_Object *left, PyST_Object *right){    if (left == right)        return (0);     if ((left == 0) || (right == 0))        return (-1);     return (parser_compare_nodes(left->st_node, right->st_node));}  /*  parser_newstobject(node* st) * *  Allocates a new Python object representing an ST.  This is simply the *  'wrapper' object that holds a node* and allows it to be passed around in *  Python code. * */static PyObject*parser_newstobject(node *st, int type){    PyST_Object* o = PyObject_New(PyST_Object, &PyST_Type);     if (o != 0) {        o->st_node = st;        o->st_type = type;    }    else {        PyNode_Free(st);    }    return ((PyObject*)o);}  /*  void parser_free(PyST_Object* st) * *  This is called by a del statement that reduces the reference count to 0. * */static voidparser_free(PyST_Object *st){    PyNode_Free(st->st_node);    PyObject_Del(st);}  /*  parser_st2tuple(PyObject* self, PyObject* args, PyObject* kw) * *  This provides conversion from a node* to a tuple object that can be *  returned to the Python-level caller.  The ST object is not modified. * */static PyObject*parser_st2tuple(PyST_Object *self, PyObject *args, PyObject *kw){    PyObject *line_option = 0;    PyObject *res = 0;    int ok;     static char *keywords[] = {"ast", "line_info", NULL};     if (self == NULL) {        ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|O:st2tuple", keywords,                                         &PyST_Type, &self, &line_option);    }    else        ok = PyArg_ParseTupleAndKeywords(args, kw, "|O:totuple", &keywords[1],                                         &line_option);    if (ok != 0) {        int lineno = 0;        if (line_option != NULL) {            lineno = (PyObject_IsTrue(line_option) != 0) ? 1 : 0;        }        /*         *  Convert ST into a tuple representation.  Use Guido's function,         *  since it's known to work already.         */        res = node2tuple(((PyST_Object*)self)->st_node,                         PyTuple_New, PyTuple_SetItem, lineno);    }    return (res);}  /*  parser_st2list(PyObject* self, PyObject* args, PyObject* kw) * *  This provides conversion from a node* to a list object that can be *  returned to the Python-level caller.  The ST object is not modified. * */static PyObject*parser_st2list(PyST_Object *self, PyObject *args, PyObject *kw){    PyObject *line_option = 0;    PyObject *res = 0;    int ok;     static char *keywords[] = {"ast", "line_info", NULL};     if (self == NULL)        ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|O:st2list", keywords,                                         &PyST_Type, &self, &line_option);    else        ok = PyArg_ParseTupleAndKeywords(args, kw, "|O:tolist", &keywords[1],                                         &line_option);    if (ok) {        int lineno = 0;        if (line_option != 0) {            lineno = PyObject_IsTrue(line_option) ? 1 : 0;        }        /*         *  Convert ST into a tuple representation.  Use Guido's function,         *  since it's known to work already.         */        res = node2tuple(self->st_node,                         PyList_New, PyList_SetItem, lineno);    }    return (res);}  /*  parser_compilest(PyObject* self, PyObject* args) * *  This function creates code objects from the parse tree represented by *  the passed-in data object.  An optional file name is passed in as well. * */static PyObject*parser_compilest(PyST_Object *self, PyObject *args, PyObject *kw){    PyObject*     res = 0;    char*         str = "<syntax-tree>";    int ok;     static char *keywords[] = {"ast", "filename", NULL};     if (self == NULL)        ok = PyArg_ParseTupleAndKeywords(args, kw, "O!|s:compilest", keywords,                                         &PyST_Type, &self, &str);    else        ok = PyArg_ParseTupleAndKeywords(args, kw, "|s:compile", &keywords[1],                                         &str);     if (ok)        res = (PyObject *)PyNode_Compile(self->st_node, str);     return (res);}  /*  PyObject* parser_isexpr(PyObject* self, PyObject* args) *  PyObject* parser_issuite(PyObject* self, PyObject* args) * *  Checks the passed-in ST object to determine if it is an expression or *  a statement suite, respectively.  The return is a Python truth value. * */static PyObject*parser_isexpr(PyST_Object *self, PyObject *args, PyObject *kw){    PyObject* res = 0;    int ok;     static char *keywords[] = {"ast", NULL};     if (self == NULL)        ok = PyArg_ParseTupleAndKeywords(args, kw, "O!:isexpr", keywords,                                         &PyST_Type, &self);    else        ok = PyArg_ParseTupleAndKeywords(args, kw, ":isexpr", &keywords[1]);     if (ok) {        /* Check to see if the ST represents an expression or not. */        res = (self->st_type == PyST_EXPR) ? Py_True : Py_False;        Py_INCREF(res);    }    return (res);}  static PyObject*parser_issuite(PyST_Object *self, PyObject *args, PyObject *kw){    PyObject* res = 0;    int ok;     static char *keywords[] = {"ast", NULL};     if (self == NULL)        ok = PyArg_ParseTupleAndKeywords(args, kw, "O!:issuite", keywords,                                         &PyST_Type, &self);    else        ok = PyArg_ParseTupleAndKeywords(args, kw, ":issuite", &keywords[1]);     if (ok) {        /* Check to see if the ST represents an expression or not. */        res = (self->st_type == PyST_EXPR) ? Py_False : Py_True;        Py_INCREF(res);    }    return (res);}  #define PUBLIC_METHOD_TYPE (METH_VARARGS|METH_KEYWORDS) static PyMethodDefparser_methods[] = {    {"compile",         (PyCFunction)parser_compilest,  PUBLIC_METHOD_TYPE,        PyDoc_STR("Compile this ST object into a code object.")},    {"isexpr",          (PyCFunction)parser_isexpr,     PUBLIC_METHOD_TYPE,        PyDoc_STR("Determines if this ST object was created from an expression.")},    {"issuite",         (PyCFunction)parser_issuite,    PUBLIC_METHOD_TYPE,        PyDoc_STR("Determines if this ST object was created from a suite.")},    {"tolist",          (PyCFunction)parser_st2list,    PUBLIC_METHOD_TYPE,        PyDoc_STR("Creates a list-tree representation of this ST.")},    {"totuple",         (PyCFunction)parser_st2tuple,   PUBLIC_METHOD_TYPE,        PyDoc_STR("Creates a tuple-tree representation of this ST.")},     {NULL, NULL, 0, NULL}};  static PyObject*parser_getattr(PyObject *self, char *name){    return (Py_FindMethod(parser_methods, self, name));}  /*  err_string(char* message) * *  Sets the error string for an exception of type ParserError. * */static voiderr_string(char *message){    PyErr_SetString(parser_error, message);}  /*  PyObject* parser_do_parse(PyObject* args, int type) * *  Internal function to actually execute the parse and return the result if *  successful or set an exception if not. * */static PyObject*parser_do_parse(PyObject *args, PyObject *kw, char *argspec, int type){    char*     string = 0;    PyObject* res    = 0;     static char *keywords[] = {"source", NULL};     if (PyArg_ParseTupleAndKeywords(args, kw, argspec, keywords, &string)) {        node* n = PyParser_SimpleParseString(string,                                             (type == PyST_EXPR)                                             ? eval_input : file_input); 	if (n)	    res = parser_newstobject(n, type);    }    return (res);}

Lines 1–500 of 3279.