From patchwork Sat Jan 28 19:52:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [esnacc-dev,2/2] compiler/python: Initial handling of Python code X-Patchwork-Submitter: Aaron Conole X-Patchwork-Id: 9 Message-Id: <1485633123-4103-3-git-send-email-aconole@bytheb.org> To: dev@lists.esnacc.org Date: Sat, 28 Jan 2017 14:52:03 -0500 From: Aaron Conole List-Id: eSNACC Development discussion 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 --- 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 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 +#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 );\n"); + fprintf(src," * if the ids are OBJECT IDENTIFIERs use the following:\n"); + fprintf(src," * AsnAny::InstallAnyByOid (OidValue, ??_ANY_ID, new );\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 +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#include + +#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 +#include +#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 */