[esnacc-dev,2/2] compiler/python: Initial handling of Python code

Message ID 1485633123-4103-3-git-send-email-aconole@bytheb.org
State Accepted, archived
Headers show
Series
  • Library and Back-end support: Python
Related show

Commit Message

Aaron Conole Jan. 28, 2017, 7:52 p.m.
This is a simple python backend for generating code.  It currently doesn't
handle constraints, implicit tagging, or non-BER forms of serialization.

Signed-off-by: Aaron Conole <aconole@bytheb.org>

---
 NEWS                                 |   2 +
 compiler/automake.mk                 |   5 +
 compiler/back-ends/py-gen/gen-any.c  | 265 ++++++++++
 compiler/back-ends/py-gen/gen-code.c | 929 +++++++++++++++++++++++++++++++++++
 compiler/back-ends/py-gen/rules.c    | 569 +++++++++++++++++++++
 compiler/back-ends/py-gen/rules.h    |  36 ++
 compiler/back-ends/py-gen/types.c    | 529 ++++++++++++++++++++
 compiler/back-ends/str-util.c        |  48 +-
 compiler/back-ends/str-util.h        |   1 +
 compiler/core/define.c               |   3 +-
 compiler/core/snacc.c                | 171 +++++--
 11 files changed, 2515 insertions(+), 43 deletions(-)
 create mode 100644 compiler/back-ends/py-gen/gen-any.c
 create mode 100644 compiler/back-ends/py-gen/gen-code.c
 create mode 100644 compiler/back-ends/py-gen/rules.c
 create mode 100644 compiler/back-ends/py-gen/rules.h
 create mode 100644 compiler/back-ends/py-gen/types.c

Patch

diff --git a/NEWS b/NEWS
index 5e1c2dd..a18b389 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@  Future
 * documentation: Developer's guides
 * esnacc-logo: A mascot (and CC-BY license) was added for esnacc
 * py-lib: Introduce a first cut at a python back-end
+* py-gen: Add python backend, which supports only basic explicit tagging, no
+          extensions, and BER only.
 
 
 1.80
diff --git a/compiler/automake.mk b/compiler/automake.mk
index 7a1f910..b46372f 100644
--- a/compiler/automake.mk
+++ b/compiler/automake.mk
@@ -70,6 +70,11 @@  compiler_esnacc_SOURCES = \
 	compiler/back-ends/idl-gen/gen-code.c \
 	compiler/back-ends/idl-gen/types.c \
 	compiler/back-ends/idl-gen/gen-vals.c \
+	compiler/back-ends/py-gen/gen-any.c \
+	compiler/back-ends/py-gen/gen-code.c \
+	compiler/back-ends/py-gen/rules.c \
+	compiler/back-ends/py-gen/rules.h \
+	compiler/back-ends/py-gen/types.c \
 	policy.h \
 	version.h
 
diff --git a/compiler/back-ends/py-gen/gen-any.c b/compiler/back-ends/py-gen/gen-any.c
new file mode 100644
index 0000000..76bb86b
--- /dev/null
+++ b/compiler/back-ends/py-gen/gen-any.c
@@ -0,0 +1,265 @@ 
+/*
+ * compiler/back-ends/py-gen/gen-any.c - routines for printing python
+ *                                       anytype code
+ *
+ * assumes that the type tree has already been run through the
+ * python type generator (py-gen/types.c).
+ *
+ * Copyright (C) 2016 Aaron Conole
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <string.h>
+#include "asn-incl.h"
+#include "asn1module.h"
+#include "str-util.h"
+#include "rules.h"
+#include "snacc-util.h"
+
+#ifdef WIN32
+#pragma  warning( disable : 4100 )  /* IGNORE unreferenced formal parameter */
+#endif
+
+
+void PrintPyAnyEnum PROTO ((FILE *hdr, Module *m));
+void PrintPyAnyHashInitRoutine PROTO ((FILE *src, FILE *hdr,
+									   Module *m, PyRules *r));
+void PrintPyOidValue PROTO ((FILE *f, PyRules *r, AsnOid *oid, int parenOrQuote));
+
+static TypeDef* GetTypeDef PROTO ((Type *t));
+
+
+extern int anyEnumValG;
+
+
+void
+PrintPyAnyCode PARAMS ((src, hdr, r, mods, m),
+    FILE *src _AND_
+    FILE *hdr _AND_
+    PyRules *r _AND_
+    ModuleList *mods _AND_
+    Module *m)
+{
+
+    if (!m->hasAnys)
+        return;
+
+    PrintPyAnyEnum(hdr, m);
+    PrintPyAnyHashInitRoutine(src, hdr, m, r);
+
+}  /* PrintAnyCode */
+
+
+
+void
+PrintPyAnyEnum PARAMS ((hdr, m),
+                       FILE *hdr _AND_
+                       Module *m)
+{
+    int firstPrinted = TRUE;
+    char *modName;
+	ValueDef *vd;
+	Type *t;
+    char anyId[512];
+
+    modName = Asn1TypeName2CTypeName (m->modId->name);
+
+    fprintf (hdr,"typedef enum %sAnyId\n", modName);
+    fprintf (hdr,"{\n");
+
+    FOR_EACH_LIST_ELMT (vd, m->valueDefs) {
+        if (vd->value != NULL) {
+            t = vd->value->type;
+            if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) &&
+                (t->basicType->a.macroType->choiceId ==
+                 MACROTYPE_SNMPOBJECTTYPE)) {
+                strcpy(anyId, vd->definedName);
+                Dash2Underscore(anyId, strlen (anyId));
+                strcat(anyId, "_ANY_ID");
+
+                if (!firstPrinted)
+                    fprintf (hdr,",\n");
+                fprintf (hdr,"    %s = %d", anyId, anyEnumValG);
+                anyEnumValG++;
+                firstPrinted = FALSE;
+            }
+        }
+    }
+
+    if (firstPrinted)
+        fprintf (hdr,"/* NO INTEGER or OBJECT IDENTIFIER to ANY type relationships were defined (via MACROs or other mechanism) */\n ??? \n");
+
+    fprintf (hdr,"\n} %sAnyId;\n\n\n", modName);
+    Free (modName);
+
+}  /* PrintAnyEnum */
+
+
+void
+PrintPyAnyHashInitRoutine PARAMS ((src, hdr, m, r),
+    FILE *src _AND_
+    FILE *hdr _AND_
+    Module *m _AND_
+    PyRules *r)
+{
+
+    TypeDef *td;
+    int i;
+    int installedSomeHashes=0;
+    struct CxxTDI *cxxtdi;
+    char *modName;
+    enum BasicTypeChoiceId typeId;
+	ValueDef *vd;
+	Type *t;
+	BasicValue *bv;
+    char anyId[512];
+	char *typeName = NULL;
+
+    modName = Asn1TypeName2CTypeName (m->modId->name);
+
+    /* print Any class src file */
+    fprintf (src,"// this class will automatically intialize the any hash tbl\n");
+    fprintf (src,"class InitAny%s\n", modName);
+    fprintf (src,"{\n");
+    fprintf (src,"  public:\n");
+    fprintf (src,"    InitAny%s();\n", modName);
+    fprintf (src,"    /* Do not add a destructor to this class!  It could\n");
+    fprintf (src,"     * cause pre-mature destruction of the ANY tables.\n");
+    fprintf (src,"     * The ANY tables will be destroyed by the runtime library.\n");
+    fprintf (src,"     */\n");
+    fprintf (src,"};\n\n");
+
+    fprintf (src,"static InitAny%s anyInitalizer;\n", modName);
+
+    /* print constructor method that build hash tbl to src file*/
+    fprintf (src,"InitAny%s::InitAny%s()\n", modName, modName);
+    fprintf (src,"{\n");
+
+	/* first print value for OID's */
+    i = 0;
+
+    FOR_EACH_LIST_ELMT (vd, m->valueDefs) {
+        if (vd->value != NULL) {
+            t = vd->value->type;
+            if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) &&
+                (t->basicType->a.macroType->choiceId ==
+                 MACROTYPE_SNMPOBJECTTYPE)) {
+                bv = vd->value->basicValue;
+                if (bv != NULL)	{
+                    installedSomeHashes = TRUE;
+                    if (bv->choiceId == BASICVALUE_OID)	{
+                        fprintf(src,"    %s oid%d",
+                                r->typeConvTbl[BASICTYPE_OID].className, i++);
+#if 0
+                        PrintPyOidValue(src, r, bv->a.oid, 1);
+#endif
+                        fprintf(src,";\n");
+					}
+				}
+            }
+        }
+    }
+    fprintf (src,"\n\n");
+
+    /* now print hash init calls */
+    i = 0;
+
+    FOR_EACH_LIST_ELMT (vd, m->valueDefs) {
+        if (vd->value != NULL) {
+            t = vd->value->type;
+            if ((GetBuiltinType(t) == BASICTYPE_MACROTYPE) &&
+                (t->basicType->a.macroType->choiceId ==
+                 MACROTYPE_SNMPOBJECTTYPE))	{
+                bv = vd->value->basicValue;
+                if (bv != NULL) {
+                    strcpy (anyId, vd->definedName);
+                    Dash2Underscore (anyId, strlen (anyId));
+					strcat (anyId, "_ANY_ID");
+
+                    installedSomeHashes = TRUE;
+                    t = t->basicType->a.macroType->a.snmpObjectType->syntax;
+
+					/* If the syntax of this any is a basic type, get the
+					class name from the rules table. */
+                    typeId = t->basicType->choiceId;
+                    if (((typeId >= BASICTYPE_BOOLEAN) &&
+                         (typeId <= BASICTYPE_SETOF)) ||
+                        ((typeId >= BASICTYPE_NUMERIC_STR) &&
+                         (typeId <= BASICTYPE_T61_STR))) {
+                        typeName = r->typeConvTbl[typeId].className;
+                    } else {
+                        /* Else if the syntax of this any is either a locally
+                           defined type or an imported type, get the name from
+                           the this type's ref info. */
+                        td = GetTypeDef(t);
+                        if (td != NULL)	{
+                            cxxtdi = td->cxxTypeDefInfo;
+                            typeName = cxxtdi->className;
+						} else
+					        typeName = NULL;
+					}
+
+                    if (typeName == NULL) {
+                        fprintf(src, "*** ERROR *** Unknown ANY\n\n");
+                    } else {
+                        if (bv->choiceId == BASICVALUE_OID)	{
+                            fprintf(src,
+                                    "    AsnAny::InstallAnyByOid (oid%d, %s, new %s);\n",
+                                    i++, anyId, typeName);
+                        } else if (bv->choiceId == BASICVALUE_INTEGER) {
+                            fprintf(src,
+                                    "    AsnAny::InstallAnyByInt (%d, %s, new %s);\n",
+                                    bv->a.integer, anyId, typeName);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    if (!installedSomeHashes) {
+        fprintf(src,"    /* Since no INTEGER/OID to ANY type relations were defined\n");
+        fprintf(src,"     * (usually done via MACROs) you must manually do the code\n");
+        fprintf(src,"     * to fill the hash tbl.\n");
+        fprintf(src,"     * if the ids are INTEGER use the following:\n");
+        fprintf(src,"     * AsnAny::InstallAnyByInt (3, ??_ANY_ID, new <className>);\n");
+        fprintf(src,"     * if the ids are OBJECT IDENTIFIERs use the following:\n");
+        fprintf(src,"     * AsnAny::InstallAnyByOid (OidValue, ??_ANY_ID, new <className>);\n");
+        fprintf(src,"     * put the ??_ANY_IDs in the AnyId enum.\n\n");
+        fprintf(src,"     * For example if you have some thing like\n");
+        fprintf(src,"     * T1 ::= SEQUENCE { id INTEGER, ANY DEFINED BY id }\n");
+        fprintf(src,"     * and the id 1 maps to the type BOOLEAN use the following:\n");
+        fprintf(src,"     * AsnAny::InstallAnyByInt (1, SOMEBOOL_ANY_ID, new AsnBool);\n");
+        fprintf(src,"     */\n ???????\n");  /* generate compile error */
+    }
+
+
+    fprintf (src,"}  /* InitAny::InitAny */\n\n\n");
+}  /* PrintAnyHashInitRoutine */
+
+
+static TypeDef*
+GetTypeDef PARAMS ((t),
+    Type *t)
+{
+    if (t == NULL)
+		return NULL;
+
+	switch (t->basicType->choiceId)
+    {
+        case BASICTYPE_LOCALTYPEREF:
+        case BASICTYPE_IMPORTTYPEREF:
+			return t->basicType->a.localTypeRef->link;
+            break;
+
+        default:
+            return NULL;
+    }
+    return NULL;*/
+
+}  /* GetTypeDef */
diff --git a/compiler/back-ends/py-gen/gen-code.c b/compiler/back-ends/py-gen/gen-code.c
new file mode 100644
index 0000000..77a5301
--- /dev/null
+++ b/compiler/back-ends/py-gen/gen-code.c
@@ -0,0 +1,929 @@ 
+/*
+ * compiler/back-ends/py-gen/gen-code.c - routines for printing python
+ *                                        code from type trees
+ *
+ * assumes that the type tree has already been run through the
+ * python type generator (py-gen/types.c).
+ *
+ * Copyright (C) 2016 Aaron Conole
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "snacc.h"
+
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+#  include <sys/time.h>
+# else
+#  include <time.h>
+# endif
+#endif
+
+#include <string.h>
+
+#include "asn-incl.h"
+#include "asn1module.h"
+#include "rules.h"
+#include "snacc-util.h"
+#include "print.h"
+#include "tag-util.h"  /* get GetTags/FreeTags/CountTags/TagByteLen */
+
+#if META
+#include "meta.h"
+#endif
+
+
+enum BasicTypeChoiceId ParanoidGetBuiltinType PARAMS ((t),Type *t);
+void PrintPyAnyCode PROTO ((FILE *src, FILE *hdr, PyRules *r,
+							ModuleList *mods, Module *m));
+void PrintPyValueDef PROTO ((FILE *src, PyRules *r, ValueDef *v));
+void PrintPyValueExtern PROTO ((FILE *hdr, PyRules *r, ValueDef *v));
+static char *
+LookupNamespace PROTO ((Type *t, ModuleList *mods));
+
+/* flag to see if constraints were present */
+static int constraints_flag;
+static long lconstraintvar=0;
+
+extern char *bVDAGlobalDLLExport;
+extern int gNO_NAMESPACE;
+extern const char *gAlternateNamespaceString;
+extern int genPERCode;
+//extern short ImportedFilesG;
+
+static const char bufTypeNameG[] = "asn_buffer.AsnBuf";
+static const char lenTypeNameG[] = "AsnLen";
+static const char tagTypeNameG[] = "AsnTag";
+static const char baseClassesG[] = "(asn_base.AsnBase)";
+
+static int printTypesG;
+static int printEncodersG;
+static int printDecodersG;
+static int printPrintersG;
+static int printFreeG;
+
+static char *GetImportFileName (char *Impname, ModuleList *mods)
+{
+    Module *currMod;
+    char *fileName = NULL;
+    FOR_EACH_LIST_ELMT (currMod, mods) {
+        /* Find the import Module in the Modules and
+         * return the header file name
+         */
+        if ((strcmp(Impname, currMod->modId->name) == 0)) {
+            /* Set the file name and break */
+            fileName = currMod->cxxHdrFileName;
+            break;
+        }
+    }
+    return fileName;
+}
+
+static Module *GetImportModuleRef (char *Impname, ModuleList *mods)
+{
+    Module *currMod=NULL;
+    FOR_EACH_LIST_ELMT (currMod, mods) {
+        /* Find the import Module in the Modules and
+         * return the header file name
+         */
+        if ((strcmp(Impname, currMod->modId->name) == 0)) {
+            break;
+        }
+    }
+    return currMod;
+}
+
+/* Prints the default instantiation for a typedefined object */
+static void PrintPyTypeDefDefault PARAMS((src, td),
+                                         FILE* src _AND_
+                                         TypeDef* td)
+{
+    fprintf(src,
+            "%s=%s\n\n",
+
+            td->cxxTypeDefInfo->className ?
+            td->cxxTypeDefInfo->className :
+            "ERROR__",
+
+            td->type->cxxTypeRefInfo->className ?
+            td->type->cxxTypeRefInfo->className :
+            "BAD__");
+}
+
+
+static void
+PrintSrcComment PARAMS ((src, m),
+    FILE *src _AND_
+    Module *m)
+{
+    time_t now = time (NULL);
+
+    fprintf (src, "# %s - class definitions for ASN.1 module %s\n",
+             m->cxxSrcFileName, m->modId->name);
+    fprintf (src, "#\n");
+    fprintf (src, "#   This file was generated by esnacc on %s\n",
+             ctime(&now));
+    fprintf (src, "#   NOTE: this is a machine generated file-"
+             "-editing not recommended\n");
+    fprintf (src, "\n");
+
+} /* PrintSrcComment */
+
+
+static void
+PrintSrcIncludes PARAMS ((src), FILE *src)
+{
+    fprintf(src, "from esnacc import asn_base\n");
+    fprintf(src, "from esnacc import asn_bool\n");
+    fprintf(src, "from esnacc import asn_buffer\n");
+    fprintf(src, "from esnacc import asn_ints\n");
+    fprintf(src, "from esnacc import asn_list\n");
+    fprintf(src, "from esnacc import asn_octs\n");
+    fprintf(src, "from esnacc import asn_useful\n");
+    /* TODO: import modules */
+    fprintf(src, "\n");
+} /* PrintSrcIncludes */
+
+/*
+ * prints inline definition of constructors if this class is
+ * derived from a library class.
+ * assumes FILE *f is positioned in the derived class definition (.h)
+ *
+ * 12/92 MS - added overloaded "=" ops for string types.
+ */
+static void
+PrintDerivedConstructors PARAMS ((f, td),
+    FILE *f _AND_
+    TypeDef *td)
+{
+    char *baseClassName = td->type->cxxTypeRefInfo->className;
+    fprintf(f,
+            "    def __init__(self, value=None):\n"
+            "        %s.__init__(self,value)\n\n", baseClassName);
+}
+
+/*
+ * prints length encoding code.  Primitives always use
+ * definite length and constructors get "ConsLen"
+ * which can be configured at compile to to be indefinite
+ * or definite.  Primitives can also be "short" (isShort is true)
+ * in which case a fast macro is used to write the length.
+ * Types for which isShort apply are: boolean, null and
+ * (almost always) integer and reals
+ */
+static void
+PrintPyLenEncodingCode PARAMS ((f, lenVarName, bufVarName, classStr,
+                                formStr),
+                               FILE *f _AND_
+                               char *lenVarName _AND_
+                               char *bufVarName _AND_
+                               char *classStr _AND_
+                               char *formStr)
+{
+    fprintf(f, "        %s += asn_buffer.BEncDefLen(%s, %s)\n",
+            lenVarName, bufVarName, lenVarName);
+    fprintf(f, "        TAG_CODE = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s,\n"
+             "                                              self.%s,\n"
+             "                                              self.BER_TAG)\n",
+             classStr, formStr);
+}
+
+/* prints last tag's encoding code first */
+static void
+PrintPyTagAndLenList PARAMS ((src, tagList, lenVarName, bufVarName),
+    FILE *src _AND_
+    TagList *tagList _AND_
+    char *lenVarName _AND_
+    char *bufVarName)
+{
+    char *classStr;
+    char *formStr;
+    Tag *tg;
+    int tagLen;
+
+    if ((tagList == NULL) || LIST_EMPTY (tagList))
+        return;
+
+    /*
+     * since encoding backward encode tags backwards
+     */
+    FOR_EACH_LIST_ELMT_RVS (tg, tagList) {
+        classStr = Class2ClassStr (tg->tclass);
+
+        if (tg->form == CONS) {
+            formStr = Form2FormStr (CONS);
+        } else {
+            formStr = Form2FormStr (PRIM);
+        }
+        PrintPyLenEncodingCode (src, lenVarName, bufVarName,
+                                classStr, formStr);
+        fprintf (src, "\n");
+
+        if (tg->tclass == UNIV) {
+            const char* ptr = DetermineCode(tg, &tagLen, 0);
+            fprintf (src, "    %s += BEncTag%d (%s, %s, %s, %s);\n", lenVarName, tagLen, bufVarName, classStr, formStr, ptr);
+        } else {
+            const char* ptr = DetermineCode(tg, &tagLen, 1);
+            fprintf(src, "    %s += BEncTag%d(%s, %s, %s, %s);\n", lenVarName, tagLen, bufVarName, classStr, formStr, ptr);
+        }                                                       //RWC;tg->code);
+    }
+} /* PrintPyTagAndLenList */
+
+/*
+ *  Recursively walks through tags, printing lower lvl tags
+ *  first (since encoding is done backwards).
+ *
+ */
+static void
+PrintPyTagAndLenEncodingCode PARAMS ((src, t, lenVarName, bufVarName),
+    FILE *src _AND_
+    Type *t _AND_
+    char *lenVarName _AND_
+    char *bufVarName)
+{
+    TagList *tl;
+    int stoleChoiceTags;
+
+    /*
+     * get all the tags on this type
+     */
+    tl = (TagList*) GetTags(t, &stoleChoiceTags);
+
+    /*
+     * leave choice elmt tag enc to encoding routine
+     */
+    if (!stoleChoiceTags)
+        PrintPyTagAndLenList(src, tl, lenVarName, bufVarName);
+
+    FreeTags(tl);
+} /* PrintPyTagAndLenEncodingCode */
+
+
+/*
+ * returns true if elmts curr following
+ *  onward are all optional ow. false
+ */
+static int
+RestAreTailOptional PARAMS ((e),
+    NamedTypeList *e)
+{
+    NamedType *elmt;
+    void *tmp;
+    int retVal;
+
+    if (e == NULL)
+        return TRUE;
+
+    tmp = (void*)CURR_LIST_NODE (e);
+    retVal = TRUE;
+    AsnListNext (e);
+    FOR_REST_LIST_ELMT (elmt, e)
+    {
+        if ((!elmt->type->optional) && (elmt->type->defaultVal == NULL)&&(!elmt->type->extensionAddition))
+        {
+            retVal = FALSE;
+            break;
+        }
+    }
+    SET_CURR_LIST_NODE (e, tmp); /* reset list to orig loc */
+    return retVal;
+}
+
+
+/*
+ * prints typedef or new class given an ASN.1  type def of a primitive type
+ * or typeref.  Uses inheritance to cover re-tagging and named elmts.
+ */
+static void
+PrintPySimpleDef PARAMS ((src, td),
+                         FILE *src _AND_
+                         TypeDef *td)
+{
+    Tag *tag;
+    TagList *tags;
+    char *formStr;
+    char *classStr;
+    CNamedElmt *n;
+    int stoleChoiceTags;
+
+    if (IsNewType (td->type)) {
+        int	hasNamedElmts;
+
+        fprintf(src, "class %s(%s):\n",
+                td->cxxTypeDefInfo->className,
+                td->type->cxxTypeRefInfo->className);
+
+        if ((hasNamedElmts = HasNamedElmts (td->type)) != 0) {
+            int count = 0;
+            fprintf(src, "    # ENUMERATIONS\n");
+            FOR_EACH_LIST_ELMT (n, td->type->cxxTypeRefInfo->namedElmts) {
+                fprintf(src, "    %s = %d\n", n->name, n->value);
+                count++;
+            }
+            fprintf(src, "\n");
+        }
+
+        /*
+         * must explicitly call constructors for base class
+         */
+        PrintDerivedConstructors (src, td);
+
+        fprintf(src, "    def typename(self):\n");
+        fprintf(src, "        return \"%s\"\n\n",
+                td->cxxTypeDefInfo->className);
+        /*
+         * Re-do BerEncode, BerDeocode, BerDecodePdu and BerDecodePdu
+         * if this type has been re-tagged
+         */
+        if ((IsDefinedByLibraryType(td->type) && !HasDefaultTag(td->type))
+            || (IsTypeRef (td->type) && ((td->type->tags != NULL)
+                                         && !LIST_EMPTY(td->type->tags)))) {
+
+            int tagLen = 0;
+            tags = GetTags (td->type, &stoleChoiceTags);
+            if (tags->count > 1) {
+                fprintf(src, "    # WARNING: only one tag added...\n");
+            }
+            tag = tags->first->data;
+            classStr = Class2ClassStr (tag->tclass);
+            formStr = Form2FormStr((tag->form == ANY_FORM) ? PRIM : tag->form);
+            fprintf(src, "    BER_FORM = asn_base.BERConsts.%s\n", formStr);
+            fprintf(src, "    BER_CLASS = asn_base.BERConsts.%s\n", classStr);
+            fflush(src);
+            if (!stoleChoiceTags) {
+                const char *ptr = DetermineCode(tag, &tagLen, (tag->tclass == UNIV) ? 0 : 1);
+                fprintf(src, "    BER_TAG = %s\n", ptr);
+            }
+            FreeTags(tags);
+            fprintf(src, "\n\n");
+        }
+    } else {
+        /* For now, we don't handle constrained values in primitive types */
+        PrintPyTypeDefDefault(src, td);
+    }
+}
+
+static void
+PrintPyChoiceDefCode(FILE *src, FILE *hdr, ModuleList *mods, Module *m,
+                     PyRules *r, TypeDef *td,Type *parent, Type *choice,
+                     int novolatilefuncs)
+{
+    fprintf(src, "# WARNING : Choice code not implemented.\n");
+    fprintf(src, "# This ASN.1 file will not load properly.\n");
+}
+
+static char *
+PyDetermineCode(Tag *tag, int *ptagLen, int bJustIntegerFlag)
+{
+    static char retstring[256];
+    char *codeStr=NULL;
+    int iValue=500;
+    memset(retstring, 0, sizeof(retstring));
+    if (tag->valueRef == NULL) {
+        if (!bJustIntegerFlag) {
+            char *univstr = Code2UnivCodeStr(tag->code);
+            sprintf(retstring, "asn_base.BERConsts.%s", univstr);
+        } else {
+            sprintf(retstring, "%d", tag->code);
+        }
+        codeStr = retstring;
+        if (ptagLen) {
+            *ptagLen = TagByteLen(tag->code);
+        }
+    } else {
+        if (tag->valueRef && tag->valueRef->basicValue &&
+            tag->valueRef->basicValue->choiceId == BASICVALUE_LOCALVALUEREF &&
+            tag->valueRef->basicValue->a.localValueRef &&
+            tag->valueRef->basicValue->a.localValueRef->link &&
+            tag->valueRef->basicValue->a.localValueRef->link->value &&
+            tag->valueRef->basicValue->a.localValueRef->link->value->basicValue) {
+            if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId ==
+                BASICVALUE_INTEGER) {
+                iValue = tag->valueRef->basicValue->a.localValueRef->link->
+                    value->basicValue->a.integer;
+            } else if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId ==
+                       BASICVALUE_LOCALVALUEREF) {
+                ValueRef *pvalueRef = NULL;
+                if (tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->choiceId == BASICVALUE_LOCALVALUEREF) {
+                    pvalueRef = tag->valueRef->basicValue->a.localValueRef->link->value->basicValue->a.localValueRef;
+                    if (pvalueRef->link->value && pvalueRef->link->value->basicValue &&
+                        pvalueRef->link->value->basicValue->choiceId == BASICVALUE_INTEGER)
+                        iValue = pvalueRef->link->value->basicValue->a.integer;
+                }
+            } else {
+                printf("Tag value type NOT RECOGNIZED; COULD NOT RESOLVE tag integer!\n");
+            }
+        } else if (tag->valueRef->basicValue->choiceId ==
+                   BASICVALUE_IMPORTVALUEREF &&
+                   tag->valueRef->basicValue->a.importValueRef &&
+                   tag->valueRef->basicValue->a.importValueRef->link &&
+                   tag->valueRef->basicValue->a.importValueRef->link->value &&
+                   tag->valueRef->basicValue->a.importValueRef->link->value->
+                   basicValue &&
+                   tag->valueRef->basicValue->a.importValueRef->link->value->
+                   basicValue->choiceId == BASICVALUE_INTEGER) {
+            iValue = tag->valueRef->basicValue->a.importValueRef->link->
+                value->basicValue->a.integer;
+        }
+        sprintf(retstring, "%d", iValue);
+        codeStr = retstring;
+        if (ptagLen) {
+            *ptagLen = TagByteLen(iValue);
+        }
+    }
+    return(codeStr);
+}
+
+static void
+PrintPySeqOrSetDefCode(FILE *src,
+                       FILE *hdr ESNACC_UNUSED,
+                       ModuleList *mods ESNACC_UNUSED,
+                       Module *m ESNACC_UNUSED,
+                       PyRules *r ESNACC_UNUSED,
+                       TypeDef *td,
+                       Type *parent ESNACC_UNUSED,
+                       Type *seq, int novolatilefuncs ESNACC_UNUSED,
+                       int isSequence)
+{
+    NamedType *e;
+    char *classStr;
+    char *codeStr;
+    Tag *tag;
+
+    fprintf(src, "class %s%s:\n\n", td->cxxTypeDefInfo->className,
+            baseClassesG);
+
+    tag = seq->tags->first->data;
+    classStr = Class2ClassStr (tag->tclass);
+    codeStr = PyDetermineCode(tag, NULL, (tag->tclass == UNIV) ? 0 : 1);
+    fprintf(src, "    BER_CLASS=asn_base.BERConsts.%s\n", classStr);
+    fprintf(src, "    BER_FORM=asn_base.BERConsts.BER_CONSTRUCTED_FORM\n\n");
+    fprintf(src, "    BER_TAG=%s\n", codeStr);
+    /* write out the sequence elmts */
+
+    if (!seq->basicType->a.sequence || !seq->basicType->a.sequence->count) {
+        fprintf(stderr, "WARNING: Sequence unknown?\n");
+    }
+
+    fprintf(src, "    def typename(self):\n");
+    fprintf(src, "        return \"%s\"\n\n", td->cxxTypeDefInfo->className);
+    /* constructor */
+    fprintf(src, "    def __init__(self");
+    FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) {
+        if (e->type->extensionAddition)
+            continue;
+
+        fprintf(src, ", %s", e->type->cxxTypeRefInfo->fieldName);
+
+        if (e->type->defaultVal) {
+            Value *defVal = GetValue(e->type->defaultVal->value);
+            switch (ParanoidGetBuiltinType(e->type)) {
+            case BASICTYPE_INTEGER:
+            case BASICTYPE_ENUMERATED:
+                fprintf(src, " = %s(%d)",
+                        e->type->cxxTypeRefInfo->className,
+                        defVal->basicValue->a.integer);
+                break;
+            case BASICTYPE_BOOLEAN:
+                fprintf(src, " = asn_bool.AsnBool(%s)",
+                        defVal->basicValue->a.boolean == 0 ?
+                        "\"False\"" : "\"True\"");
+                break;
+            case BASICTYPE_BITSTRING:
+                fprintf(stderr,
+                        "WARNING: unsupported default BIT STRING\n");
+                break;
+            default:
+                fprintf(src, " = %s()\n",
+                        e->type->cxxTypeRefInfo->className);
+                break;
+            } /* end switch */
+        } else {
+            fprintf(src, " = None");
+        }
+    }
+    fprintf(src, "):\n");
+
+    FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) {
+        if (e->type->extensionAddition)
+            continue;
+
+        fprintf(src, "        if ");
+        fprintf(src, "%s is not None and ",
+                    e->type->cxxTypeRefInfo->fieldName);
+        fprintf(src, "not isinstance(%s, %s):\n",
+                e->type->cxxTypeRefInfo->fieldName,
+                e->type->cxxTypeRefInfo->className);
+        fprintf(src, "            raise TypeError(\"Expected %s for %s\")\n",
+                e->type->cxxTypeRefInfo->className,
+                e->type->cxxTypeRefInfo->fieldName);
+        fprintf(src, "        else:\n");
+        fprintf(src, "            self.%s = %s\n",
+                e->type->cxxTypeRefInfo->fieldName,
+                e->type->cxxTypeRefInfo->fieldName);
+    }
+
+    fprintf(src, "\n\n");
+
+    /* benccontent */
+    fprintf(src, "    def BEncContent(self, asnbuf):\n");
+    fprintf(src, "        asnlen = 0\n");
+    FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) {
+        if (e->type->extensionAddition)
+            continue;
+
+        fprintf(src, "        ");
+        char *indent = "        ";
+        if (e->type->cxxTypeRefInfo->isPtr) {
+            fprintf(src, "if self.%s is not None:\n",
+                    e->type->cxxTypeRefInfo->fieldName);
+            indent = "            ";
+        } else {
+            fprintf(src, "if self.%s is None:\n            "
+                    "raise UnboundLocalError('Populate %s before encoding')\n",
+                    e->type->cxxTypeRefInfo->fieldName,
+                    e->type->cxxTypeRefInfo->fieldName);
+        }
+        if (e->type->tags->count) {
+            fprintf(src, "%s# %d tags to encode\n", indent,
+                    e->type->tags->count);
+            fprintf(src, "%ssafe_buf = asnbuf\n", indent);
+            fprintf(src, "%ssafe_len = asnlen\n", indent);
+            fprintf(src, "%sasnlen = 0\n", indent);
+            fprintf(src, "%sasnbuf = %s()\n", indent, bufTypeNameG);
+        }
+        fprintf(src, "%sasnlen += self.%s.BEnc(asnbuf)\n", indent,
+                e->type->cxxTypeRefInfo->fieldName);
+        /* this will only be entered if the above check for count is true */
+        FOR_EACH_LIST_ELMT(tag, e->type->tags) {
+            fprintf(src, "%snewbuf = %s()\n", indent, bufTypeNameG);
+            fprintf(src, "%stagCode = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s, asn_base.BERConsts.%s, %d)\n",
+                    indent, Class2ClassStr(tag->tclass),
+                    Form2FormStr(tag->form), tag->code);
+            fprintf(src, "%sasnlen += asn_buffer.BEncDefLen(asnbuf, asnlen)\n",
+                    indent);
+            fprintf(src, "%sasnlen += asnbuf.PutBufReverse(tagCode)\n",
+                    indent);
+            fprintf(src, "%snewbuf.PutBuf(asnbuf.buf)\n", indent);
+            fprintf(src, "%sasnbuf = newbuf\n", indent);
+        }
+        if (e->type->tags->count) {
+            fprintf(src, "%ssafe_buf.PutBuf(asnbuf.buf)\n", indent);
+            fprintf(src, "%sasnbuf = safe_buf\n", indent);
+            fprintf(src, "%sasnlen = asnlen + safe_len\n", indent);
+        }
+    }
+    fprintf(src, "        return asnlen\n\n");
+
+    /* bdeccontent */
+    fprintf(src, "    def BDecContent(self, asnbuf, length):\n");
+    fprintf(src, "        asnlen = 0\n");
+    FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) {
+        if (e->type->extensionAddition)
+            continue;
+
+        int i = 0;
+        Tag *lastTag = NULL;
+        fprintf(src, "        # tags: %d\n", e->type->tags->count);
+        FOR_EACH_LIST_ELMT(tag, e->type->tags) {
+            char *formStr = Form2FormStr(tag->form);
+            lastTag = tag;
+            if (i) {
+                fprintf(src, "        bufTag, al = self.BDecTag(asnbuf, asnlen)\n");
+                fprintf(src, "        if bufTag != TAG_CODE_EXPECTED:\n");
+                fprintf(src, "            raise Exception('ahh: %%x vs %%x' %% (bufTag, TAG_CODE_EXPECTED))\n");
+                fprintf(src, "        asnlen += al\n"
+                             "        asnbuf.swallow(al)\n");
+                fprintf(src, "        tagTotalLen, totalBytesLen = asn_buffer.BDecDefLen(asnbuf)\n");
+                fprintf(src, "        asnlen += tagTotalLen\n");
+            } else {
+                i = 1;
+            }
+            if (tag->tclass == CNTX)
+                formStr = Form2FormStr(CONS);
+            fprintf(src,
+                    "        TAG_CODE_EXPECTED = asn_base.BERConsts.MakeTag(asn_base.BERConsts.%s, asn_base.BERConsts.%s, %d)\n",
+                    Class2ClassStr(tag->tclass), formStr, tag->code);
+        }
+        if (!e->type->tags->count) {
+            fprintf(src,
+                    "        TAG_CODE_EXPECTED = asn_base.BERConsts.MakeTag(%s.BER_CLASS,\n"
+                    "                                              %s.BER_FORM,\n"
+                    "                                              %s.BER_TAG)\n",
+                    e->type->cxxTypeRefInfo->className,
+                    e->type->cxxTypeRefInfo->className,
+                    e->type->cxxTypeRefInfo->className);
+        }
+        fprintf(src, "        bufTag, al = self.BDecTag(asnbuf, asnlen)\n");
+        fprintf(src, "        if bufTag != TAG_CODE_EXPECTED:\n");
+        if (!e->type->cxxTypeRefInfo->isPtr)
+            fprintf(src, "            raise Exception('Unexpected: %%x; expected: %%x' %% (bufTag, TAG_CODE_EXPECTED))\n");
+        else
+            fprintf(src, "            pass\n");
+        fprintf(src, "        else:\n");
+        if (e->type->tags->count == 1 && lastTag && lastTag->tclass == CNTX) {
+            fprintf(src, "            asnbuf.swallow(al)\n");
+            fprintf(src, "            tagTotalLen, totalBytesLen = asn_buffer.BDecDefLen(asnbuf)\n");
+            fprintf(src, "            asnlen += tagTotalLen\n");
+        }
+        fprintf(src, "            self.%s = %s()\n",
+                e->type->cxxTypeRefInfo->fieldName,
+                e->type->cxxTypeRefInfo->className);
+        fprintf(src, "            asnlen += self.%s.BDec(asnbuf, length)\n",
+                e->type->cxxTypeRefInfo->fieldName);
+    }
+    fprintf(src, "        return asnlen\n\n");
+
+    fprintf(src, "    def __str__(self):\n");
+    fprintf(src, "        s = \"%%s = {\" %% self.typename()\n");
+    FOR_EACH_LIST_ELMT(e, seq->basicType->a.sequence) {
+        fprintf(src, "        s += \"%s = \"\n",
+                e->type->cxxTypeRefInfo->fieldName);
+        fprintf(src, "        if self.%s is not None:\n",
+                e->type->cxxTypeRefInfo->fieldName);
+        fprintf(src, "            s += str(self.%s)\n",
+                e->type->cxxTypeRefInfo->fieldName);
+        fprintf(src, "        else:\n");
+        fprintf(src, "            s += \"None\"\n");
+        fprintf(src, "        s += \"\\n\"\n");
+    }
+    fprintf(src, "        s += \"}\"\n");
+    fprintf(src, "        return s;\n");
+}
+
+
+static void
+PrintPySeqDefCode (FILE *src, FILE *hdr, ModuleList *mods, Module *m,
+                    PyRules *r ,TypeDef *td, Type *parent ESNACC_UNUSED,
+                    Type *seq, int novolatilefuncs ESNACC_UNUSED)
+{
+
+    PrintPySeqOrSetDefCode (src, hdr, mods, m, r, td, parent, seq,
+                            novolatilefuncs, 1);
+
+} /* PrintPySeqDefCode */
+
+
+static void
+PrintPySetDefCode (FILE *src, FILE *hdr, ModuleList *mods, Module *m,
+                    PyRules *r, TypeDef *td, Type *parent ESNACC_UNUSED,
+                    Type *set, int novolatilefuncs ESNACC_UNUSED)
+{
+    PrintPySeqOrSetDefCode (src, hdr, mods, m, r, td, parent, set,
+                            novolatilefuncs, 0);
+
+} /* PrintPySetDefCode */
+
+
+static void
+PrintPyListClass(FILE *src, TypeDef *td, Type *lst, Module* m)
+{
+   struct NamedType p_etemp;
+   NamedType* p_e;
+   char *lcn; /* list class name */
+   char *ecn; /* (list) elmt class name */
+
+   p_e = &p_etemp;
+   p_e->type = lst->basicType->a.setOf;
+
+   ecn = lst->basicType->a.setOf->cxxTypeRefInfo->className;
+   lcn = td->cxxTypeDefInfo->className;
+
+   fprintf(src, "class %s(asn_list.", lcn);
+
+   switch (lst->basicType->choiceId) {
+   case BASICTYPE_SEQUENCEOF:
+       fprintf(src, "AsnSequenceOf");
+	    break;
+   case BASICTYPE_SETOF:
+       fprintf(src, "AsnSetOf");
+       break;
+
+   default:
+       break;
+   }
+
+   fprintf(src, "):\n");
+   fprintf(src, "    def __init__(self, elemts=None, expected=None):\n");
+   fprintf(src, "        if expected is None:\n");
+   fprintf(src, "            expected = %s\n", ecn);
+   fprintf(src, "        asn_list.%s.__init__(self, elemts, expected)\n\n",
+           (lst->basicType->choiceId == BASICTYPE_SEQUENCEOF) ?
+           "AsnSequenceOf" : "AsnSetOf");
+
+   fprintf(src, "    def typename(self):\n");
+   fprintf(src, "        return \"%s\"\n\n", lcn);
+
+   if (td->type->subtypes != NULL) {
+       if ((td->type->subtypes->choiceId == SUBTYPE_SINGLE) &&
+           (td->type->subtypes->a.single->choiceId ==
+            SUBTYPEVALUE_SIZECONSTRAINT) &&
+           (td->type->subtypes->a.single->a.sizeConstraint->choiceId ==
+            SUBTYPE_SINGLE)) {
+#if 0
+			PrintPySetOfSizeConstraint(src,
+				td->type->subtypes->a.single->a.sizeConstraint->a.single,
+				m, td->type);
+#endif
+       } else {
+           PrintErrLoc(m->asn1SrcFileName, (long)td->type->lineNo);
+           fprintf(errFileG, "ERROR - unsupported constraint\n");
+       }
+   }
+}
+
+static void
+PrintPySetOfDefCode PARAMS ((src, m, td, setOf),
+    FILE *src _AND_
+    Module *m _AND_
+    TypeDef *td _AND_
+    Type *setOf)
+{
+    /* do class */
+	PrintPyListClass(src, td, setOf, m);
+
+} /* PrintPySetOfDefCode */
+
+
+static void
+PrintPyTypeDefCode PARAMS ((src, hdr, mods, m, r, td, novolatilefuncs),
+                           FILE *src _AND_
+                           FILE *hdr _AND_
+                           ModuleList *mods _AND_
+                           Module *m _AND_
+                           PyRules *r _AND_
+                           TypeDef *td _AND_
+                           int novolatilefuncs)
+{
+    switch (td->type->basicType->choiceId) {
+    case BASICTYPE_BOOLEAN:  /* library type */
+    case BASICTYPE_REAL:  /* library type */
+    case BASICTYPE_OCTETSTRING:  /* library type */
+    case BASICTYPE_NULL:  /* library type */
+    case BASICTYPE_EXTERNAL:		/* library type */
+    case BASICTYPE_OID:  /* library type */
+    case BASICTYPE_RELATIVE_OID:
+    case BASICTYPE_INTEGER:  /* library type */
+    case BASICTYPE_BITSTRING:  /* library type */
+    case BASICTYPE_ENUMERATED:  /* library type */
+    case BASICTYPE_NUMERIC_STR:  /* 22 */
+    case BASICTYPE_PRINTABLE_STR: /* 23 */
+    case BASICTYPE_UNIVERSAL_STR: /* 24 */
+    case BASICTYPE_IA5_STR:      /* 25 */
+    case BASICTYPE_BMP_STR:      /* 26 */
+    case BASICTYPE_UTF8_STR:     /* 27 */
+    case BASICTYPE_UTCTIME:      /* 28 tag 23 */
+    case BASICTYPE_GENERALIZEDTIME: /* 29 tag 24 */
+    case BASICTYPE_GRAPHIC_STR:     /* 30 tag 25 */
+    case BASICTYPE_VISIBLE_STR:     /* 31 tag 26  aka ISO646String */
+    case BASICTYPE_GENERAL_STR:     /* 32 tag 27 */
+    case BASICTYPE_OBJECTDESCRIPTOR:	/* 33 tag 7 */
+    case BASICTYPE_VIDEOTEX_STR:	/* 34 tag 21 */
+    case BASICTYPE_T61_STR:			/* 35 tag 20 */
+        PrintPySimpleDef(src, td);
+        break;
+    case BASICTYPE_SEQUENCEOF:  /* list types */
+    case BASICTYPE_SETOF:
+        PrintPySetOfDefCode(src, m, td, td->type);
+        break;
+    case BASICTYPE_IMPORTTYPEREF:  /* type references */
+    case BASICTYPE_LOCALTYPEREF:
+        /* if this type has been re-tagged then must create new class
+         * instead of using a typedef */
+        PrintPySimpleDef(src, td);
+        break;
+    case BASICTYPE_CHOICE:
+        PrintPyChoiceDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs);
+        break;
+    case BASICTYPE_SET:
+        PrintPySetDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs);
+        break;
+    case BASICTYPE_SEQUENCE:
+        PrintPySeqDefCode(src, hdr, mods, m, r, td, NULL, td->type, novolatilefuncs);
+        break;
+    case BASICTYPE_COMPONENTSOF:
+    case BASICTYPE_SELECTION:
+    case BASICTYPE_UNKNOWN:
+    case BASICTYPE_MACRODEF:
+    case BASICTYPE_MACROTYPE:
+    case BASICTYPE_ANYDEFINEDBY:  /* ANY types */
+    case BASICTYPE_ANY:
+        /* do nothing */
+        break;
+    default:
+        /* TBD: print error? */
+        break;
+    }
+} /* PrintPyTypeDefCode */
+
+void
+PrintPyCode PARAMS ((src, hdr, if_META (printMeta COMMA meta COMMA meta_pdus COMMA)
+					 mods, m, r, longJmpVal, printTypes, printValues,
+					 printEncoders, printDecoders, printPrinters, printFree
+					 if_TCL (COMMA printTcl), novolatilefuncs),
+    FILE *src _AND_
+    FILE *hdr _AND_
+    if_META (MetaNameStyle printMeta _AND_)
+    if_META (const Meta *meta _AND_)
+    if_META (MetaPDU *meta_pdus _AND_)
+    ModuleList *mods _AND_
+    Module *m _AND_
+    PyRules *r _AND_
+    long longJmpVal ESNACC_UNUSED _AND_
+    int printTypes _AND_
+    int printValues _AND_
+    int printEncoders _AND_
+    int printDecoders _AND_
+    int printPrinters _AND_
+    int printFree
+    if_TCL (_AND_ int printTcl) _AND_
+    int novolatilefuncs)
+{
+	Module *currMod;
+    AsnListNode *currModTmp;
+    TypeDef *td;
+    ValueDef *vd;
+
+
+    printTypesG = printTypes;
+    printEncodersG = printEncoders;
+    printDecodersG = printDecoders;
+    printPrintersG = printPrinters;
+    printFreeG = printFree;
+
+    PrintSrcComment(src, m);
+    PrintSrcIncludes(src);
+
+    FOR_EACH_LIST_ELMT (currMod, mods) {
+		if (!strcmp(m->cxxHdrFileName, currMod->cxxHdrFileName)) {
+            ImportModuleList *ModLists;
+            ImportModule *impMod;
+            char *ImpFile = NULL;
+            ModLists = currMod->imports;
+            currModTmp = mods->curr;
+            FOR_EACH_LIST_ELMT(impMod, ModLists) {
+                ImpFile = GetImportFileName(impMod->modId->name, mods);
+                if (ImpFile != NULL)
+                    fprintf(src, "import %s\n", ImpFile);
+                if (impMod->moduleRef == NULL)
+                    impMod->moduleRef = GetImportModuleRef(impMod->modId->name, mods);
+            }
+            mods->curr = currModTmp;
+        }
+    }
+    fprintf(src, "\n");
+
+    if (printValues) {
+        fprintf(src, "# value defs\n\n");
+        FOR_EACH_LIST_ELMT (vd, m->valueDefs) {
+            /* PrintPyValueDef(src, r, vd); */
+        }
+        fprintf(src, "\n");
+    }
+
+    fprintf(src, "# class member definitions:\n\n");
+    PrintPyAnyCode (src, hdr, r, mods, m);
+
+    FOR_EACH_LIST_ELMT (td, m->typeDefs) {
+        PrintPyTypeDefCode(src, hdr, mods, m, r, td, novolatilefuncs);
+    }
+
+} /* PrintPyCode */
+
+static char *
+LookupNamespace PARAMS ((t, mods),
+    Type *t _AND_
+    ModuleList *mods)
+{
+    char *pszNamespace = NULL;
+    Module *mTmp = NULL;
+    TypeDef *ptTmp = NULL;
+    BasicType *pbtTmp2 = NULL;
+
+    pbtTmp2 = t->basicType;
+    if (pbtTmp2->choiceId == BASICTYPE_SEQUENCEOF ||
+        pbtTmp2->choiceId == BASICTYPE_SETOF)
+        pbtTmp2 = pbtTmp2->a.sequenceOf->basicType;  // Burrow 1 more layer down for SequenceOf/SetOf
+    if (pbtTmp2->choiceId == BASICTYPE_IMPORTTYPEREF) {
+        FOR_EACH_LIST_ELMT (mTmp, mods) {
+            ptTmp = LookupType(mTmp->typeDefs,
+                               pbtTmp2->a.importTypeRef->typeName); //WHAT we are looking for...
+            if (ptTmp != NULL)
+                break;      //FOUND the MODULE that contains our defninition...
+        }
+
+        if (ptTmp != NULL && mTmp != NULL && mTmp->namespaceToUse) {
+            pszNamespace = mTmp->namespaceToUse;
+        }
+    }
+
+    return(pszNamespace);
+}
diff --git a/compiler/back-ends/py-gen/rules.c b/compiler/back-ends/py-gen/rules.c
new file mode 100644
index 0000000..2d2ba11
--- /dev/null
+++ b/compiler/back-ends/py-gen/rules.c
@@ -0,0 +1,569 @@ 
+/*
+ * compiler/back-ends/py-gen/rules.c - initialized rule structure
+ *           inits a table that contains info about
+ *           converting each ASN.1 type to a python class
+ *
+ * Copyright (C) 2016 Aaron Conole
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include "asn-incl.h"
+#include "asn1module.h"
+#include "rules.h"
+
+PyRules pyRulesG =
+{
+   4,
+   "choiceId",
+   "ChoiceIdEnum",
+   "a",
+   "ChoiceUnion",
+   FALSE,
+   "Enc",
+   "Dec",
+   "EncContent",
+   "DecContent",
+   "EncPdu",
+   "DecPdu",
+   {
+      {  /* 0 */
+         BASICTYPE_UNKNOWN,
+         "???",
+         FALSE,
+         FALSE,
+         FALSE,
+         TRUE,
+         TRUE,
+         TRUE,
+         TRUE,
+         "None",
+         "unknown"
+      },
+      { /* 1 */
+         BASICTYPE_BOOLEAN,
+         "asn_bool.AsnBool",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bool"
+      },
+      {  /* 2 */
+         BASICTYPE_INTEGER, /* 2 */
+         "asn_ints.AsnInt",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "integer"
+      },
+      { /* 3 */
+         BASICTYPE_BITSTRING,
+         "asn_octs.AsnBits",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bits"
+      },
+      {/* 4 */
+         BASICTYPE_OCTETSTRING,
+         "asn_octs.AsnOcts",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "octs"
+      },
+      {/* 5 */
+         BASICTYPE_NULL,
+         "asn_base.AsnNull",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "null"
+      },
+      { /* 6 */
+         BASICTYPE_OID,
+         "asn_oid.AsnOid",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "oid"
+      },
+      { /* 7 */
+         BASICTYPE_REAL,
+         "asn_ints.AsnReal",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "real"
+      },
+      {/* 8 */
+         BASICTYPE_ENUMERATED,
+         "asn_ints.AsnEnum",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "enumeration"
+      },
+      {/* 9 */
+         BASICTYPE_SEQUENCE,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "seq"
+      },
+      {/* 10 */
+         BASICTYPE_SEQUENCEOF,
+         "asn_list.AsnSequenceOf",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "seqOf"
+      },
+      {/* 11 */
+         BASICTYPE_SET,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         FALSE,
+         "None",
+         "set"
+      },
+      {/* 12 */
+         BASICTYPE_SETOF,
+         "asn_list.AsnSetOf",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "setOf"
+      },
+      {/* 13 */
+         BASICTYPE_CHOICE,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         FALSE,
+         "None",
+         "choice"
+      },
+      {/* 14 */
+         BASICTYPE_SELECTION,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "foo"
+      },
+      {/* 15 */
+         BASICTYPE_COMPONENTSOF,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bar"
+      },
+      {/* 16 */
+         BASICTYPE_ANY,
+         "asn_base.AsnAny",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "any"
+      },
+      {/* 17 */
+         BASICTYPE_ANYDEFINEDBY,
+         "AsnAnyDefinedBy",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "anyDefBy"
+      },
+      {/* 18 */
+         BASICTYPE_LOCALTYPEREF,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "foo"
+      },
+      {/* 19 */
+         BASICTYPE_IMPORTTYPEREF,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bar"
+      },
+      {/* 20 */
+         BASICTYPE_MACROTYPE,
+         NULL,
+         FALSE,
+         FALSE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "foo"
+      },
+      {/* 21 */
+         BASICTYPE_MACRODEF,
+         NULL,
+         FALSE,
+         FALSE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "foo"
+      },
+      {/* 22 */
+         BASICTYPE_NUMERIC_STR,
+         "asn_useful.NumericString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "numericString"
+      },
+      {/* 23 */
+         BASICTYPE_PRINTABLE_STR,
+         "asn_useful.PrintableString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "printableString"
+      },
+      {/* 24 */
+         BASICTYPE_UNIVERSAL_STR,
+         "asn_useful.UniversalString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "universalString"
+      },
+      {/* 25 */
+         BASICTYPE_IA5_STR,
+         "asn_useful.IA5String",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "ia5String"
+      },
+      {/* 26 */
+         BASICTYPE_BMP_STR,
+         "asn_useful.BMPString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bmpString"
+      },
+      {/* 27 */
+         BASICTYPE_UTF8_STR,
+         "asn_useful.UTF8String",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "utf8String"
+      },
+      {/* 28 */
+         BASICTYPE_UTCTIME, /* 23 */
+         "asn_useful.UTCTime",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "utcTime"
+      },
+      {/* 29 */
+         BASICTYPE_GENERALIZEDTIME, /* 24 */
+         "asn_useful.GeneralizedTime",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "generalizedTime"
+      },
+      {/* 30 */
+         BASICTYPE_GRAPHIC_STR, /* 25 */
+         "asn_useful.GraphicString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "graphicString"
+      },
+      {/* 31 */
+         BASICTYPE_VISIBLE_STR, /* 26 */
+         "asn_useful.VisibleString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "visibleString"
+      },
+      {/* 32 */
+         BASICTYPE_GENERAL_STR, /* 27 */
+         "asn_useful.GeneralString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "generalString"
+      },
+      {/* 33 */
+         BASICTYPE_OBJECTDESCRIPTOR,
+         "asn_useful.ObjectDescriptor",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "objectDescriptor"
+      } ,
+      {/* 34 */
+         BASICTYPE_VIDEOTEX_STR,
+         "asn_useful.VideotexString",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "videotexString"
+      },
+      {/* 35 */
+         BASICTYPE_T61_STR,
+         "asn_useful.T61String",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "t61String"
+      },
+      {/* 36 */
+         BASICTYPE_EXTERNAL,
+         "asn_useful.EXTERNAL",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         TRUE,
+         TRUE,
+         "None",
+         "external"
+      },
+      {/* 37 */
+         BASICTYPE_OCTETCONTAINING,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "octetContainer"
+		},
+      {/* 38 */
+         BASICTYPE_BITCONTAINING,
+         NULL,
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "bitContainer"
+		},
+        { /* 39 */
+         BASICTYPE_RELATIVE_OID,
+         "AsnRelativeOid",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "relativeOid"
+        },
+        { /* 40 */
+         BASICTYPE_EXTENSION,
+         "asn_base.AsnExtension",
+         FALSE,
+         TRUE,
+         FALSE,
+         TRUE,
+         TRUE,
+         FALSE,
+         TRUE,
+         "None",
+         "extension"
+        }
+
+   }
+};
diff --git a/compiler/back-ends/py-gen/rules.h b/compiler/back-ends/py-gen/rules.h
new file mode 100644
index 0000000..e5d61bf
--- /dev/null
+++ b/compiler/back-ends/py-gen/rules.h
@@ -0,0 +1,36 @@ 
+/*
+ * compiler/back-ends/py-gen/rules.h
+ *
+ * Copyright (C) 2016 Aaron Conole
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef PY_RulesInclude
+#define PY_RulesInclude
+/* see asn1module.h for CxxTDI (C++ type def info) */
+
+typedef struct PyRules
+{
+    int  maxDigitsToAppend;
+    char *choiceIdFieldName;   /* name of choiceId field */
+    char *choiceIdEnumName;  /* name (tag) for choiceId enum def name */
+    char *choiceUnionFieldName; /* what the name of the choice's union is */
+    char *choiceUnionName;  /* name (tag) for choice union def name */
+    int   capitalizeNamedElmts;
+    char *encodeBaseName;
+    char *decodeBaseName;
+    char *encodeContentBaseName;
+    char *decodeContentBaseName;
+    char *encodePduBaseName;
+    char *decodePduBaseName;
+    CxxTDI typeConvTbl[BASICTYPE_EXTENSION + 1];
+}  PyRules;
+
+extern PyRules pyRulesG;
+
+#endif
diff --git a/compiler/back-ends/py-gen/types.c b/compiler/back-ends/py-gen/types.c
new file mode 100644
index 0000000..a6a7f3b
--- /dev/null
+++ b/compiler/back-ends/py-gen/types.c
@@ -0,0 +1,529 @@ 
+/*
+ * compiler/back-ends/py-gen/types.c  - fills in python type information
+ *
+ * Copyright (C) 2016 Aaron Conole
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include "asn-incl.h"
+#include "asn1module.h"
+#include "snacc-util.h"
+#include "str-util.h"
+#include "rules.h"
+
+static DefinedObj *definedNamesG;
+
+/* unexported prototypes */
+
+void FillPyTypeDefInfo PROTO ((PyRules *r, Module *m, TypeDef *td));
+static void FillPyFieldNames PROTO ((PyRules *r,
+                                      NamedTypeList *firstSibling));
+static void FillPyTypeRefInfo PROTO ((PyRules *r, Module *m,
+                                       TypeDef *head, Type *parent, Type *t));
+static void FillPyStructElmts PROTO ((PyRules *r, Module *m,
+                                       TypeDef *head, Type *parent,
+                                       NamedTypeList *t));
+static void FillPyChoiceElmts PROTO ((PyRules *r, Module *m, TypeDef *head,
+                                       Type *parent, NamedTypeList *first));
+static int IsPyNone PROTO ((PyRules *r, TypeDef *td, Type *parent, Type *t));
+void FillPyTDIDefaults PROTO ((PyRules *r, CxxTDI *ctdi, TypeDef *td));
+
+
+static char *pykwds[] = {
+    "False", 	"class", 	"finally", 	"is", 	"return",
+    "None", 	"continue", 	"for", 	"lambda", 	"try",
+    "True", 	"def", 	"from", 	"nonlocal", 	"while",
+    "and", 	"del", 	"global", 	"not", 	"with",
+    "as", 	"elif", 	"if", 	"or", 	"yield",
+    "assert", 	"else", 	"import", 	"pass",
+    "break", 	"except", 	"in", 	"raise", NULL
+};
+
+
+/*
+ * returns non-zero if the given str is a C++ key word
+ */
+int
+IsPyKeyWord PARAMS ((str),
+    char *str)
+{
+    size_t i;
+
+    for (i=0; pykwds[i] != NULL && strcmp(pykwds[i], str); i++);
+
+    return pykwds[i] != NULL;
+}
+
+
+/*
+ *  allocates and fills all the cxxTypeInfos
+ *  in the type trees for every module in the list
+ */
+void
+FillPyTypeInfo PARAMS ((r, modList),
+    PyRules *r _AND_
+    ModuleList *modList)
+{
+    TypeDef *td;
+    Module *m;
+
+    /*
+     * go through each module's type defs and fill
+     * in the C type and enc/dec routines etc
+     */
+    definedNamesG = NULL;
+
+    FOR_EACH_LIST_ELMT (m, modList) {
+        FOR_EACH_LIST_ELMT (td, m->typeDefs)
+            FillPyTypeDefInfo (r, m, td);
+    }
+
+    /*
+     * now that type def info is filled in
+     * set up set/seq/list/choice elements that ref
+     * those definitions
+     */
+    FOR_EACH_LIST_ELMT (m, modList) {
+        FOR_EACH_LIST_ELMT (td, m->typeDefs)
+            FillPyTypeRefInfo (r, m, td, NULL, td->type);
+    }
+
+    /* done with checking for name conflicts */
+    FreeDefinedObjs (&definedNamesG);
+    definedNamesG = NULL;
+
+}
+
+
+/*
+ *  allocates and fills structure holding C type definition information
+ *  fo the given ASN.1 type definition.  Does not fill CTRI for contained
+ *  types etc.
+ */
+void
+FillPyTypeDefInfo PARAMS ((r, m, td),
+    PyRules *r _AND_
+    Module *m _AND_
+    TypeDef *td)
+{
+    char *tmpName;
+    CxxTDI *cxxtdi;
+
+    /*
+     * if CxxTDI is present this type def has already been 'filled'
+     */
+    if (td->cxxTypeDefInfo != NULL)
+        return;
+
+
+    cxxtdi = MT (CxxTDI);
+    td->cxxTypeDefInfo = cxxtdi;
+
+    /* get default type def attributes from table for type on rhs of ::= */
+
+    FillPyTDIDefaults (r, cxxtdi, td);
+
+
+    /*
+     * if defined by a ref to another type definition fill in that type
+     * def's CxxTDI so can inherit (actully completly replace default
+     * attributes) from it
+     */
+    if ((td->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) ||
+        (td->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF))
+    {
+        /*
+         * Fill in CxxTDI for defining type if nec.
+         * this works for importTypeRef as well since both a.localTypeRef
+         * and a.importTypeRef are of type TypeRef
+         */
+        FillPyTypeDefInfo(r, td->type->basicType->a.localTypeRef->module,
+                          td->type->basicType->a.localTypeRef->link);
+
+        tmpName = cxxtdi->className; /* save className */
+        /* copy all type def info and restore name related stuff - hack*/
+        *cxxtdi = *td->type->basicType->a.localTypeRef->link->cxxTypeDefInfo;
+        cxxtdi->className = tmpName; /* restore className */
+    }
+}  /* FillCxxTypeDefInfo */
+
+
+static void
+FillPyTypeRefInfo PARAMS ((r, m, head, parent, t),
+    PyRules *r _AND_
+    Module *m _AND_
+    TypeDef *head _AND_
+    Type *parent _AND_
+    Type *t)
+{
+    CxxTRI *cxxtri;
+    CxxTDI *tmpCxxtdi;
+    ValueDef *namedElmt;
+    CNamedElmt *cne;
+    CNamedElmt **cneHndl;
+    char       *elmtName;
+    int         len;
+    enum BasicTypeChoiceId basicTypeId;
+
+    /*
+     * you must check for cycles yourself before calling this
+     */
+    if (t->cxxTypeRefInfo == NULL) {
+        cxxtri = MT (CxxTRI);
+        t->cxxTypeRefInfo = cxxtri;
+    } else
+        cxxtri = t->cxxTypeRefInfo;
+
+    basicTypeId = t->basicType->choiceId;
+
+    tmpCxxtdi = &r->typeConvTbl[basicTypeId];
+
+    /* get base type def info from the conversion table in the rules */
+    cxxtri->isEnc = tmpCxxtdi->isEnc;
+    if ((basicTypeId == BASICTYPE_OCTETCONTAINING) ||
+        (basicTypeId == BASICTYPE_BITCONTAINING)) {
+        cxxtri->className =
+            r->typeConvTbl[t->basicType->a.stringContaining->basicType->
+                           choiceId].className;
+    } else
+        cxxtri->className = tmpCxxtdi->className;
+
+    cxxtri->optTestRoutineName = tmpCxxtdi->optTestRoutineName;
+
+
+    /*
+     * convert named elmts to C++ names.
+     * check for name conflict with other defined Types/Names/Values
+     */
+    if (((basicTypeId == BASICTYPE_INTEGER) ||
+         (basicTypeId == BASICTYPE_ENUMERATED) ||
+         (basicTypeId == BASICTYPE_BITSTRING)) &&
+        (!(LIST_EMPTY (t->basicType->a.integer)))) {
+        cxxtri->namedElmts = AsnListNew (sizeof (void*));
+
+        FOR_EACH_LIST_ELMT (namedElmt, t->basicType->a.integer) {
+            cneHndl = (CNamedElmt**)AsnListAppend (cxxtri->namedElmts);
+            cne = *cneHndl = MT(CNamedElmt);
+            elmtName = Asn1ValueName2CValueName(namedElmt->definedName);
+            cne->name = elmtName; /* not very efficient */
+
+            if (namedElmt->value->basicValue->choiceId == BASICVALUE_INTEGER)
+                cne->value = namedElmt->value->basicValue->a.integer;
+            else {
+                fprintf (errFileG, "Warning: unlinked defined value. Using -9999999\n");
+                cne->value = -9999999;
+            }
+
+            if (r->capitalizeNamedElmts)
+                Str2UCase(cne->name, len);
+
+            /*
+             * append digits if enum value name is a keyword
+             */
+            MakePyStrUnique(definedNamesG, cne->name, r->maxDigitsToAppend, 1);
+        }
+    }
+
+    /* fill in rest of type info depending on the type */
+    switch (basicTypeId)
+    {
+    default:
+    case BASICTYPE_UNKNOWN:
+    case BASICTYPE_MACRODEF:
+    case BASICTYPE_MACROTYPE:
+        /* do nothing */
+    case BASICTYPE_BOOLEAN:  /* library types */
+    case BASICTYPE_INTEGER:
+    case BASICTYPE_BITSTRING:
+    case BASICTYPE_OCTETSTRING:
+    case BASICTYPE_NULL:
+    case BASICTYPE_OID:
+    case BASICTYPE_RELATIVE_OID:
+    case BASICTYPE_REAL:
+    case BASICTYPE_ENUMERATED:
+    case BASICTYPE_ANY:
+    case BASICTYPE_ANYDEFINEDBY:  /* ANY types */
+        /* don't need to do anything else */
+        break;
+
+    case BASICTYPE_SEQUENCEOF:  /* list types */
+    case BASICTYPE_SETOF:
+        /* fill in component type */
+        FillPyTypeRefInfo (r, m, head, t, t->basicType->a.setOf);
+        break;
+
+    case BASICTYPE_IMPORTTYPEREF:  /* type references */
+    case BASICTYPE_LOCALTYPEREF:
+        /*
+         * grab class name from link (link is the def of the
+         * the ref'd type)
+         */
+        if (t->basicType->a.localTypeRef->link != NULL) {
+            /* inherit attributes from referenced type */
+            tmpCxxtdi=  t->basicType->a.localTypeRef->link->cxxTypeDefInfo;
+            cxxtri->className = tmpCxxtdi->className;
+            cxxtri->isEnc = tmpCxxtdi->isEnc;
+            cxxtri->optTestRoutineName = tmpCxxtdi->optTestRoutineName;
+        }
+        break;  /* these are handled now */
+
+    case BASICTYPE_CHOICE:
+        /*
+         * must fill field names BEFORE filling choice elmts
+         * (allows better naming for choice ids)
+         */
+        FillPyFieldNames(r, t->basicType->a.choice);
+        FillPyChoiceElmts(r, m, head, t, t->basicType->a.choice);
+        break;
+
+    case BASICTYPE_SET:
+    case BASICTYPE_SEQUENCE:
+        FillPyStructElmts (r, m, head, t, t->basicType->a.set);
+        FillPyFieldNames (r, t->basicType->a.set);
+        break;
+
+    case BASICTYPE_COMPONENTSOF:
+    case BASICTYPE_SELECTION:
+        fprintf(errFileG,
+                "Compiler error - COMPONENTS OF or SELECTION type slipped through normalizing phase.\n");
+        exit(-1);
+        break;
+    }
+
+    /*
+     * figure out whether this is a ptr based on the enclosing
+     * type (if any) and optionality/default
+     */
+    cxxtri->isPtr = (unsigned char)IsPyNone(r, head, parent, t);
+}  /* FillCxxTypeRefInfo */
+
+
+
+static void
+FillPyStructElmts PARAMS ((r, m, head, parent, elmts),
+    PyRules *r _AND_
+    Module *m _AND_
+    TypeDef *head _AND_
+    Type *parent _AND_
+    NamedTypeList *elmts)
+{
+    NamedType *et;
+
+    FOR_EACH_LIST_ELMT (et, elmts) {
+        FillPyTypeRefInfo(r, m, head, parent, et->type);
+    }
+}
+
+/*
+ *  Figures out non-conflicting enum names for the
+ *  choice id's
+ */
+static void
+FillPyChoiceElmts PARAMS ((r, m, head, parent, elmts),
+    PyRules *r _AND_
+    Module *m _AND_
+    TypeDef *head _AND_
+    Type *parent _AND_
+    NamedTypeList *elmts)
+{
+    NamedType *et;
+    int idCount = 0;
+    CxxTRI *cxxtri;
+    int   len;
+
+    /*
+     * fill in type info for elmt types first
+     */
+    FOR_EACH_LIST_ELMT (et, elmts)
+        FillPyTypeRefInfo (r, m, head, parent, et->type);
+
+    FOR_EACH_LIST_ELMT (et, elmts) {
+        cxxtri =  et->type->cxxTypeRefInfo;
+
+        if (cxxtri == NULL)
+            continue; /* wierd type */
+
+        cxxtri->choiceIdValue = idCount++;
+
+        len = strlen (cxxtri->fieldName);
+        cxxtri->choiceIdSymbol = Malloc (len + 4);
+        strcpy (cxxtri->choiceIdSymbol, cxxtri->fieldName);
+        strcat (cxxtri->choiceIdSymbol, "Cid");
+
+        if (r->capitalizeNamedElmts)
+            Str2UCase (cxxtri->choiceIdSymbol, len);
+    }
+}
+
+/*
+ * takes a list of "sibling" (eg same level in a structure)
+ * ElmtTypes and fills sets up the c field names in
+ * the CxxTRI struct
+ */
+static void
+FillPyFieldNames PARAMS ((r, elmts),
+    PyRules *r _AND_
+    NamedTypeList *elmts)
+{
+    NamedType  *et;
+    CxxTRI *cxxtri;
+    DefinedObj *fieldNames;
+    int        len;
+    char      *tmpName;
+    char      *asn1FieldName;
+    char      *cFieldName = NULL;
+
+    /*
+     * Initialize fieldname data
+     * allocate (if nec) and fill in CTRI fieldname if poss
+     * from asn1 field name.  leave blank otherwise
+     */
+    fieldNames = NewObjList();
+    FOR_EACH_LIST_ELMT (et, elmts) {
+        cxxtri = et->type->cxxTypeRefInfo;
+        if (cxxtri == NULL) {
+            cxxtri = MT(CxxTRI);
+            et->type->cxxTypeRefInfo = cxxtri;
+        }
+
+        if (et->fieldName != NULL) {
+            /*
+             * can assume that the field names are
+             * distinct because they have passed the
+             * error checking step.
+             * However, still call MakeStrUnique
+             * to change any field names that
+             * conflict with C++ keywords
+             */
+            asn1FieldName = et->fieldName;
+            cxxtri->fieldName = Asn1FieldName2CFieldName(asn1FieldName);
+            MakePyStrUnique(fieldNames, cxxtri->fieldName,
+                            r->maxDigitsToAppend, 1);
+            DefineObj(&fieldNames, cxxtri->fieldName);
+        }
+
+        /*
+         * generate field names for those without them
+         */
+        cFieldName = cxxtri->fieldName;
+        if (cxxtri->fieldName == NULL) {
+            if ((et->type->basicType->choiceId == BASICTYPE_LOCALTYPEREF) ||
+                (et->type->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) {
+                /*
+                 * take ref'd type name as field name
+                 * convert first let to lower case
+                 */
+                tmpName = et->type->basicType->a.localTypeRef->link->
+                    cxxTypeDefInfo->className;
+                tmpName = Asn1TypeName2CTypeName(tmpName);
+            } else {
+                /*
+                 * get default field name for this type
+                 */
+                tmpName = Strdup(r->typeConvTbl[et->type->basicType->choiceId].
+                                 defaultFieldName);
+            }
+            cFieldName = tmpName;
+            if (isupper(cFieldName[0]))
+                cFieldName[0] = (char)tolower(cFieldName[0]);
+
+            len = strlen(cFieldName);
+
+            /*
+             * try to use just the type name (with lower case first char).
+             * if that is already used in this type or a C++ keyword,
+             * append ascii digits to field name until unique
+             * in this type
+             */
+            MakePyStrUnique(fieldNames, cFieldName, r->maxDigitsToAppend, 1);
+            DefineObj(&fieldNames, cFieldName);
+            cxxtri->fieldName = cFieldName;
+        }
+    }
+    FreeDefinedObjs (&fieldNames);
+}
+
+/*
+ * returns true if this c type for this type should be
+ * be ref'd as a ptr
+ */
+static int
+IsPyNone PARAMS ((r, td, parent, t),
+    PyRules *r _AND_
+    TypeDef *td _AND_
+    Type *parent _AND_
+    Type *t)
+{
+    CxxTDI *cxxtdi;
+    int retVal = FALSE;
+
+    /*
+     * inherit ptr attriubutes from ref'd type if any
+     * otherwise grab lib c type def from the PyRules
+     */
+    if ((t->basicType->choiceId == BASICTYPE_LOCALTYPEREF) ||
+        (t->basicType->choiceId == BASICTYPE_IMPORTTYPEREF)) {
+        cxxtdi = t->basicType->a.localTypeRef->link->cxxTypeDefInfo;
+    } else
+        cxxtdi = &r->typeConvTbl[GetBuiltinType (t)];
+
+    /* no parent means t is the root of a typedef */
+    if ((parent == NULL) && (cxxtdi->isPtrForTypeDef))
+        retVal = TRUE;
+    else if ((parent != NULL) &&
+             ((parent->basicType->choiceId == BASICTYPE_SET) ||
+             (parent->basicType->choiceId == BASICTYPE_SEQUENCE)) &&
+             (cxxtdi->isPtrInSetAndSeq))
+        retVal = TRUE;
+    else if ((parent != NULL) &&
+             ((parent->basicType->choiceId == BASICTYPE_SETOF) ||
+             (parent->basicType->choiceId == BASICTYPE_SEQUENCEOF)) &&
+             (cxxtdi->isPtrInList))
+        retVal = TRUE;
+    else if ((parent != NULL) &&
+             (parent->basicType->choiceId == BASICTYPE_CHOICE) &&
+             (cxxtdi->isPtrInChoice))
+        retVal = TRUE;
+    else if (((t->optional) || (t->defaultVal != NULL)) && (cxxtdi->isPtrForOpt))
+        retVal = TRUE;
+
+    return retVal;
+}
+
+/* fill given cxxtdi with defaults from table for given typedef */
+void
+FillPyTDIDefaults PARAMS ((r, cxxtdi, td),
+    PyRules *r _AND_
+    CxxTDI *cxxtdi _AND_
+    TypeDef *td)
+{
+    CxxTDI *tblCxxtdi;
+    int typeIndex;
+    char *tmpName;
+
+    typeIndex = GetBuiltinType (td->type);
+
+    if (typeIndex < 0)
+        return;
+
+    tblCxxtdi = &r->typeConvTbl[typeIndex];
+
+    memcpy (cxxtdi, tblCxxtdi, sizeof (CxxTDI));
+
+    /* make sure class name is unique wrt to previously defined classes */
+    tmpName = Asn1TypeName2CTypeName (td->definedName);
+    cxxtdi->className = Malloc (strlen (tmpName) + r->maxDigitsToAppend +1);
+    strcpy (cxxtdi->className, tmpName);
+    Free (tmpName);
+
+    MakePyStrUnique (definedNamesG, cxxtdi->className, r->maxDigitsToAppend, 1);
+    DefineObj (&definedNamesG, cxxtdi->className);
+
+}
diff --git a/compiler/back-ends/str-util.c b/compiler/back-ends/str-util.c
index 073a4f1..b8c6dfb 100644
--- a/compiler/back-ends/str-util.c
+++ b/compiler/back-ends/str-util.c
@@ -90,6 +90,7 @@ 
 
 int IsCKeyWord PROTO ((char *str));
 int IsCxxKeyWord PROTO ((char *str));
+int IsPyKeyWord PROTO ((char *str));
 
 
 int	keepbaseG = TRUE;
@@ -127,9 +128,8 @@  Asn1FieldName2CFieldName PARAMS ((aName),
     if (aName == NULL)
         return NULL;
 
-    retVal = Malloc (strlen (aName) + 1);
-    strcpy (retVal, aName);
-    Dash2Underscore (retVal, strlen (retVal));
+    retVal = Strdup(aName);
+    Dash2Underscore(retVal, strlen(retVal));
 
     return retVal;
 }  /* Asn1FieldName2CFieldName */
@@ -262,8 +262,7 @@  Dash2Underscore PARAMS ((str, len),
     int len)
 {
     int i;
-    for (i=0; i < len; i++)
-    {
+    for (i=0; i < len; i++) {
         if (str[i] == '-')
             str[i] = '_';
     }
@@ -377,6 +376,34 @@  MakeCxxStrUnique PARAMS ((nameList, str, maxDigits, startingDigit),
     }
 }  /* MakeCxxStrUnique */
 
+
+/*
+ * same as MakeCStrUnique except checks against C++ keywords
+ */
+void
+MakePyStrUnique PARAMS ((nameList, str, maxDigits, startingDigit),
+    DefinedObj *nameList _AND_
+    char *str _AND_
+    int maxDigits _AND_
+    int startingDigit)
+{
+    int digit, len, maxDigitVal;
+
+    if (ObjIsDefined(nameList, str, StrObjCmp) || IsPyKeyWord (str)) {
+        for (maxDigitVal = 1; maxDigits > 0; maxDigits--)
+            maxDigitVal *= 10;
+
+        len = strlen(str);
+        digit = startingDigit;
+        do
+        {
+            str[len] = '\0';
+            AppendDigit (str, digit++);
+        } while (ObjIsDefined (nameList, str, StrObjCmp) &&
+                 (digit < maxDigitVal));
+    }
+}  /* MakeCxxStrUnique */
+
 static char *OutputDirectoryName;
 
 void StoreOutputDirectory PARAMS ((directory),
@@ -596,6 +623,17 @@  MakeCxxSrcFileName PARAMS ((refName),
 	return MakeFileName (refName, ".cpp");
 }
 
+char *
+MakePySrcFileName PARAMS ((refName),
+    const char *refName)
+{
+    char *name = Strdup(refName);
+    Dash2Underscore(name, strlen(refName));
+    char *ret = MakeFileName(name, ".py");
+    Free(name);
+    return ret;
+}
+
 #if IDL
 char *
 MakeIDLFileName PARAMS ((refName),
diff --git a/compiler/back-ends/str-util.h b/compiler/back-ends/str-util.h
index d3a0b54..b758c44 100644
--- a/compiler/back-ends/str-util.h
+++ b/compiler/back-ends/str-util.h
@@ -72,6 +72,7 @@  char *MakeCHdrFileName PROTO ((const char *moduleName));
 char *MakeCSrcFileName PROTO ((const char *moduleName));
 char *MakeCxxHdrFileName PROTO ((const char *moduleName));
 char *MakeCxxSrcFileName PROTO ((const char *moduleName));
+char *MakePySrcFileName PROTO ((const char *moduleName));
 #if IDL
 char *MakeIDLFileName PROTO ((const char *moduleName));
 #endif
diff --git a/compiler/core/define.c b/compiler/core/define.c
index 5d4d92d..3583a19 100644
--- a/compiler/core/define.c
+++ b/compiler/core/define.c
@@ -176,8 +176,7 @@  UndefineObj PARAMS ((objListHndl, obj, cmpRoutine),
 int
 ObjIsDefined (DefinedObj *objListPtr, void *obj, CmpObjsRoutine cmpRoutine)
 {
-    for ( ; objListPtr != NULL; objListPtr = objListPtr->next)
-    {
+    for ( ; objListPtr != NULL; objListPtr = objListPtr->next) {
         if (cmpRoutine (objListPtr->obj, obj))
             return TRUE;
     }
diff --git a/compiler/core/snacc.c b/compiler/core/snacc.c
index cb0cba8..407394b 100644
--- a/compiler/core/snacc.c
+++ b/compiler/core/snacc.c
@@ -81,6 +81,8 @@  char *bVDAGlobalDLLExport=(char *)0;
 
 #include "c++-gen/rules.h"		/* for c++ file generation */
 
+#include "py-gen/rules.h"
+
 #if IDL
 #include "idl-gen/rules.h"		/* for idl file generation */
 #endif
@@ -126,6 +128,12 @@  void PrintCxxCode (FILE *src, FILE *hdr, if_META (MetaNameStyle genMeta COMMA
 				   int printTypes, int printValues, int printEncoders,
 				   int printDecoders, int printPrinters, int printFree,
 				   if_TCL (int printTcl COMMA) int novolatilefuncs);
+void PrintPyCode (FILE *src, FILE *hdr, if_META (MetaNameStyle genMeta COMMA
+				   const Meta *meta COMMA MetaPDU *metapdus COMMA)
+				   ModuleList *mods, Module *m, CxxRules *r, long longJmpVal,
+				   int printTypes, int printValues, int printEncoders,
+				   int printDecoders, int printPrinters, int printFree,
+				   if_TCL (int printTcl COMMA) int novolatilefuncs);
 void PrintIDLCode PROTO ((FILE *idl, ModuleList *mods, Module *m, IDLRules *r,
 						 long int longJmpVal, int printValues));
 void ProcessMacros PROTO ((Module *m));
@@ -143,6 +151,11 @@  static void GenCxxCode PROTO ((ModuleList *allMods, long longJmpVal,
 							 int genPrinters, int genValues, int genFree,
 							 if_META (MetaNameStyle genMeta COMMA MetaPDU *meta_pdus COMMA)
 							 if_TCL (int genTcl COMMA) int novolatilefuncs));
+static void GenPyCode PROTO ((ModuleList *allMods, long longJmpVal,
+							 int genTypes, int genEncoders, int genDecoders,
+							 int genPrinters, int genValues, int genFree,
+							 if_META (MetaNameStyle genMeta COMMA MetaPDU *meta_pdus COMMA)
+							 if_TCL (int genTcl COMMA) int novolatilefuncs));
 static void GenIDLCode PROTO ((ModuleList *allMods, long longJmpVal, int genTypes,
 							 int genPrinters, int genValues, int genFree));
 static int ModNamesUnique PROTO ((ModuleList *m));
@@ -317,6 +330,7 @@  int main PARAMS ((argc, argv),
     int         genCCode = FALSE;        /* defaults to C if neither specified */
     int         genCxxCode = FALSE;
     int         genIDLCode = FALSE;
+    int         genPyCode = FALSE;
     long        longJmpVal = -100;
     int         novolatilefuncs = FALSE;
     char*       dirName;                    /* REN -- 6/2/03 -- added */
@@ -432,7 +446,11 @@  int main PARAMS ((argc, argv),
                 break;
 
             case 'p':
-                genPrintCode = TRUE;
+                if (argv[currArg][2] == 'y') {
+                    genPyCode = TRUE;
+                } else {
+                    genPrintCode = TRUE;
+                }
                 currArg++;
                 break;
 
@@ -693,15 +711,15 @@  error:
         genFreeCode = TRUE;
         genPrintCode = TRUE;
     }
-    else if (genCCode + genCxxCode + genTypeTbls + genIDLCode > 1)
+    else if (genCCode + genPyCode + genCxxCode + genTypeTbls + genIDLCode > 1)
     {
-        fprintf (stderr, "%s: ERROR---Choose only one of the -c -C or -T options\n",
+        fprintf (stderr, "%s: ERROR---Choose only one of the -py, -p py, -c, -C or -T options\n",
             argv[0]);
         Usage (argv[0], stderr);
         return 1;
     }
 
-    if (!genCCode && !genCxxCode && !genTypeTbls && !genIDLCode)
+    if (!genCCode && !genCxxCode && !genPyCode && !genTypeTbls && !genIDLCode)
         genCCode = TRUE;  /* default to C if neither specified */
 
     /* Set the encoding rules to BER if not set */
@@ -714,11 +732,9 @@  error:
     allMods = (ModuleList *)AsnListNew (sizeof (void*));
     
     tmpLst = srcList;
-    while (tmpLst != NULL)
-    {
+    while (tmpLst != NULL) {
         // Only do if not NULL 
-        if (tmpLst->fileName)
-        {
+        if (tmpLst->fileName) {
             currMod = ParseAsn1File (tmpLst->fileName,
                                      tmpLst->ImportFileFlag);
         
@@ -738,8 +754,7 @@  error:
     /*
      * Check that the module names/oids are unique
      */
-    if (!ModNamesUnique (allMods))
-    {
+    if (!ModNamesUnique (allMods)) {
         fprintf (errFileG, "\nConflicting module names, cannot proceed.\n");
         return 1;
     }
@@ -750,8 +765,7 @@  error:
      * Now that all files have been parsed,
      * link local and locatable import type refs
      */
-    if (LinkTypeRefs (allMods) < 0)
-    {
+    if (LinkTypeRefs (allMods) < 0) {
         fprintf (errFileG, "\nType linking errors---cannot proceed\n");
         return 2;
     }
@@ -763,8 +777,7 @@  error:
      * and have been linked.  Need type info to be able to
      * parse values easily (elimitate ambiguity).
      */
-    FOR_EACH_LIST_ELMT (currMod, allMods)
-    {
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
         if (ParseValues (allMods, currMod) != 0)
             fprintf (errFileG, "WARNING: Value parsing error (s), attempting to continue\n");
     }
@@ -775,8 +788,7 @@  error:
      * Value parsing may have defined some new values
      * so can link local and locatable import value refs now.
      */
-    if (LinkValueRefs (allMods) < 0)
-    {
+    if (LinkValueRefs (allMods) < 0) {
         fprintf (errFileG, "\nValue linking errors---cannot proceed\n");
         return 4;
     }
@@ -790,8 +802,8 @@  error:
      *     so they are put in the id to ANY type hash tbl.
      */
     semErr = 0;
-    FOR_EACH_LIST_ELMT (currMod, allMods)
-    {   // For Macors, New TypeDefs are added here, if required
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
+        // For Macros, New TypeDefs are added here, if required
         ProcessMacros (currMod);
         if (currMod->status == MOD_ERROR)
             semErr = 1;
@@ -808,8 +820,8 @@  error:
      * boil down values into simplest rep. (eg OID -> ENC_OID)
      */
     semErr = 0;
-    FOR_EACH_LIST_ELMT (currMod, allMods)
-    {   // New TypeDefs are added here, if required
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
+        // New TypeDefs are added here, if required
         NormalizeModule (currMod);
         if (currMod->status == MOD_ERROR)
             semErr = 1;
@@ -823,8 +835,7 @@  error:
      * Mark recusive types.  Currently the recursive information is
      * not used elsewhere.
      */
-    FOR_EACH_LIST_ELMT (currMod, allMods)
-    {
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
         MarkRecursiveTypes (currMod);
     }
 
@@ -835,8 +846,7 @@  error:
      * Check all modules and exit if errors were found
      */
     semErr = 0;
-    FOR_EACH_LIST_ELMT (currMod, allMods)
-    {
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
         ErrChkModule (currMod);
         if (currMod->status == MOD_ERROR)
             semErr = 1;
@@ -851,23 +861,20 @@  error:
      * production but should not affect the other processing/error
      * checking steps.  This allows full display of errors.
      */
-    if (smallErrG)
-    {
+    if (smallErrG) {
         /*
          * for debugging show "parsed" version of ASN.1 module if
          * the print flag is set.
          * Dumps each module to stdout. Printed from Module data struct
          * print here before exiting otherwise print after sorting
          */
-        if (printModuleFlag)
-        {
-            FOR_EACH_LIST_ELMT (currMod, allMods)
-            {
+        if (printModuleFlag) {
+            FOR_EACH_LIST_ELMT (currMod, allMods) {
                 printf ("\n\n");
                 PrintModule (stdout, currMod);
             }
         }
-        
+
         return 8;
     }
 
@@ -893,6 +900,8 @@  error:
         FillIDLTypeInfo (&idlRulesG, allMods);
 #endif
 
+    else if (genPyCode)
+        FillPyTypeInfo(&pyRulesG, allMods);
 
     /*
      * STEP 10
@@ -911,10 +920,8 @@  error:
      * dumps each module to stdout. Printed from Module data struct
      * Shows the results of normalization and sorting.
      */
-    if (printModuleFlag)
-    {
-        FOR_EACH_LIST_ELMT (currMod, allMods)
-        {
+    if (printModuleFlag) {
+        FOR_EACH_LIST_ELMT (currMod, allMods) {
             printf ("\n\n");
             PrintModule (stdout, currMod);
         }
@@ -944,6 +951,12 @@  error:
             genPrintCode, genFreeCode);
 #endif
 
+    else if (genPyCode)
+        GenPyCode(allMods, longJmpVal, genTypeCode, genValueCode,
+                  genEncodeCode, genDecodeCode, genPrintCode, genFreeCode,
+                  if_META (genMetaCode COMMA meta_pdus COMMA)
+                  if_TCL (genTclCode COMMA) novolatilefuncs);
+
     tmpLst = srcList;
     while(tmpLst) {
         SRC_FILE *tmp;
@@ -1159,6 +1172,92 @@  GenCCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDeco
 }  /* GenCCode */
 
 
+void
+GenPyCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree, if_META (genMeta COMMA meta_pdus COMMA) if_TCL (genTcl COMMA) novolatilefuncs),
+    ModuleList *allMods _AND_
+    long longJmpVal _AND_
+    int genTypes _AND_
+    int genValues _AND_
+    int genEncoders _AND_
+    int genDecoders _AND_
+    int genPrinters _AND_
+    int genFree _AND_
+    if_META (MetaNameStyle genMeta _AND_)
+    if_META (MetaPDU *meta_pdus _AND_)
+    if_TCL (int genTcl _AND_)
+    int novolatilefuncs)
+{
+    Module      *currMod;
+	AsnListNode *saveMods;
+    char        *modBaseFileName;
+    FILE        *hdrFilePtr;
+    FILE        *srcFilePtr;
+    DefinedObj  *fNames;
+    int         fNameConflict = FALSE;
+
+    /*
+     * Make names for each module's encoder/decoder src and hdr files
+     * so import references can be made via include files
+     * check for truncation --> name conflicts & exit if nec
+     */
+    fNames = NewObjList();
+
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
+        modBaseFileName = MakeBaseFileName (keepbaseG
+                                            ? currMod->asn1SrcFileName
+                                            : currMod->modId->name);
+        currMod->cxxHdrFileName = "";
+        currMod->cxxSrcFileName = MakePySrcFileName(modBaseFileName);
+        if (ObjIsDefined (fNames, currMod->cxxHdrFileName, StrObjCmp) ||
+            ObjIsDefined (fNames, currMod->cxxSrcFileName, StrObjCmp)) {
+            fprintf(errFileG,
+                    "ERROR: file name conflict for generated source files with names `%s' and `%s'.\n\n",
+                    currMod->cxxHdrFileName, currMod->cxxSrcFileName);
+            fprintf(errFileG,
+                    "This usually means the max file name length is truncating the file names.\n");
+            fprintf(errFileG,
+                    "Try re-naming the modules with shorter names or increasing the argument to -mf option (if you are using it).\n");
+            fprintf(errFileG,
+                    "This error can also be caused by 2 modules have the same names but different OBJECT IDENTIFIERs.");
+            fprintf(errFileG,
+                    "  Try renaming the modules to correct this.\n");
+            fNameConflict = TRUE;
+        } else {
+            DefineObj (&fNames, currMod->cxxHdrFileName);
+            DefineObj (&fNames, currMod->cxxSrcFileName);
+        }
+        Free (modBaseFileName);
+
+        if (fNameConflict)
+            return;
+
+        FreeDefinedObjs (&fNames);
+    }
+
+    FOR_EACH_LIST_ELMT (currMod, allMods) {
+        if (currMod->ImportedFlag == FALSE) {
+            /*
+             * create and fill .h file for module's data structs
+             */
+            srcFilePtr = fopen (currMod->cxxSrcFileName, "wt");
+
+            if (srcFilePtr == NULL) {
+                perror ("fopen");
+            } else {
+                saveMods = allMods->curr;
+                PrintPyCode (srcFilePtr, hdrFilePtr,
+                             if_META (genMeta COMMA &meta COMMA meta_pdus COMMA)
+                             allMods, currMod, &cxxRulesG, longJmpVal,
+                             genTypes, genValues, genEncoders, genDecoders,
+                             genPrinters, genFree,
+                             if_TCL (genTcl COMMA) novolatilefuncs);
+                allMods->curr = saveMods;
+                fclose (srcFilePtr);
+            }
+        }
+    }
+}
+
 /*
  * Given the list of parsed, linked, normalized, error-checked and sorted
  * modules, and some code generation flags, generates C++ code and
@@ -1345,7 +1444,7 @@  GenCxxCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDe
 	fclose (meta.srcfp);
     
 #endif
-	}
+        }
 	}
 }  /* GenCxxCode */