Annotation of mstools/mfc/samples/templdef/templdef.cpp, revision 1.1

1.1     ! root        1: // templdef.cpp : A simple C++ template expansion utility.
        !             2: //
        !             3: //   This utility takes a template file which uses a syntax
        !             4: //   subset similar to the proposed future C++ template
        !             5: //   (parameterized type) syntax, and expands it into the
        !             6: //   equivalent current C++ syntax.
        !             7: //
        !             8: //   Note that this is intended as an example program, and
        !             9: //   handles only a specific syntax in the template files.
        !            10: //
        !            11: // This is a part of the Microsoft Foundation Classes C++ library.
        !            12: // Copyright (C) 1992 Microsoft Corporation
        !            13: // All rights reserved.
        !            14: //
        !            15: // This source code is only intended as a supplement to the
        !            16: // Microsoft Foundation Classes Reference and Microsoft
        !            17: // QuickHelp documentation provided with the library.
        !            18: // See these sources for detailed information regarding the
        !            19: // Microsoft Foundation Classes product.
        !            20: 
        !            21: #include <ctype.h>
        !            22: #include <afxcoll.h>
        !            23: 
        !            24: #define istringTypeParamMax 10
        !            25: 
        !            26: CString string_h;
        !            27: CString string_cpp;
        !            28: CString string_ctt;
        !            29: 
        !            30: CString stringTemplate = "template";
        !            31: CString stringClass = "class";
        !            32: CString stringTemplateName;
        !            33: CString stringTypedefName;
        !            34: 
        !            35: const char chMoreThanOne = '\0';
        !            36: const char chNot = '\0';
        !            37: 
        !            38: /////////////////////////////////////////////////////////////////////////////
        !            39: 
        !            40: // UsageErr:
        !            41: // A utility function.  Write an error message, followed by a usage summary.
        !            42: //
        !            43: void UsageErr(const char* szErrorMessage = NULL,
        !            44:                          const char* szErrorParam = NULL)
        !            45: {
        !            46:        if (szErrorMessage != NULL)
        !            47:        {
        !            48:                fprintf(stderr, "templdef : error: ");
        !            49:                fprintf(stderr, szErrorMessage, szErrorParam);
        !            50:                fprintf(stderr, ".\n\n");
        !            51:        }
        !            52: 
        !            53:        fprintf(stderr, "templdef : usage:\n\n"
        !            54:                "  Suppose a class CMap exists in the template file map.ctt, which\n"
        !            55:                "  has two parameterized types Foo and Bar. To create a new class\n"
        !            56:                "  CMapFooToBar, declared in footobar.h and defined in footobar.cpp,\n"
        !            57:                "  use the following command:\n"
        !            58:                "\n"
        !            59:                "  templdef \"CMap<Foo, Bar> CMapFooToBar\" map.ctt footobar.h footobar.cpp\n"
        !            60:                "\n"
        !            61:                "  This command is similar to the proposed future C++ syntax for templates:\n"
        !            62:                "\n"
        !            63:                "  typedef CMap<Foo, Bar> CMapFooToBar;\n");
        !            64: 
        !            65:        exit(1);
        !            66: }
        !            67: 
        !            68: void CheckSyntax(BOOL fGoodSyntax, const char* sz)
        !            69: {
        !            70:        if (!fGoodSyntax)
        !            71:                UsageErr("expecting %s", sz);
        !            72: }
        !            73: 
        !            74: /////////////////////////////////////////////////////////////////////////////
        !            75: // CTokenFile
        !            76: // For the purpose of reading source code, this sort of CStdioFile derivative
        !            77: // proves quite handy.  This could be made really powerful, but this is a
        !            78: // start.
        !            79: 
        !            80: class CTokenFile : public CStdioFile
        !            81: {
        !            82: private:
        !            83:        enum { ichMax = 1024 };
        !            84:        char ach[ichMax];
        !            85:        int ich;
        !            86:        static CString stringToken;
        !            87:        BOOL fComment;
        !            88:        void GetBuf();
        !            89:        char GetChar() { if (ach[ich] == chNot) GetBuf(); return ach[ich++]; }
        !            90:        char PeekChar() { return ach[ich]; }
        !            91:        void UnGetChar() { --ich; } // note: really a single char pushback
        !            92: public:
        !            93:        void InitBuf(const char* sz);
        !            94:        static CString& TokenString() { return stringToken; }
        !            95:        CTokenFile();
        !            96:        char GetToken();
        !            97:        char GetPrintToken();
        !            98:        char GetTypeToken();
        !            99:        char GetNameToken();
        !           100:        void PutToken(char ch) { fputc(ch, m_pStream); }
        !           101:        void PutToken(const CString& string) { WriteString(string); }
        !           102:        void PutToken() { WriteString(stringToken); }
        !           103:        BOOL AtFileEnd() { return ach[0] == chNot; }
        !           104:        BOOL AtBufEnd() { return ach[ich] == chNot; }
        !           105:        void SafeOpen(const CString& string, UINT nStyleFlags);
        !           106: };
        !           107: CString CTokenFile::stringToken;
        !           108: 
        !           109: CTokenFile::CTokenFile()
        !           110: {
        !           111:        ach[0] = '\n';
        !           112:        ach[1] = chNot;
        !           113:        ich = 1;
        !           114:        fComment = FALSE;
        !           115: };
        !           116: 
        !           117: void CTokenFile::GetBuf()
        !           118: {
        !           119:        if (ReadString(ach, ichMax) == NULL)
        !           120:                ach[0] = chNot;
        !           121: 
        !           122:        ich = 0;
        !           123: }
        !           124: 
        !           125: void CTokenFile::InitBuf(const char* sz)
        !           126: {
        !           127:        strncpy(ach, sz, ichMax);
        !           128:        ich = 0;
        !           129: }
        !           130: 
        !           131: void CTokenFile::SafeOpen(const CString& string, UINT nStyleFlags)
        !           132: {
        !           133:        BOOL fSuccess = Open(string, nStyleFlags, 0);
        !           134: 
        !           135:        if (!fSuccess)
        !           136:                UsageErr("can't open file \"%s\"", string);
        !           137: }
        !           138: 
        !           139: char CTokenFile::GetToken()
        !           140: {
        !           141:        if (AtBufEnd())
        !           142:                GetBuf();
        !           143:        
        !           144:        if (AtFileEnd())
        !           145:                exit(0);
        !           146: 
        !           147:        fComment = FALSE;
        !           148: 
        !           149:        char ch = GetChar();
        !           150:        char* pch = stringToken.GetBuffer(1024);
        !           151:        char* pchInit = pch;
        !           152:        *pch++ = ch;
        !           153:        *pch = '\0';
        !           154: 
        !           155:        // assuming this doesn't "really" release the buffer!
        !           156:        stringToken.ReleaseBuffer(1);
        !           157: 
        !           158:        if (!isalnum(ch) &&
        !           159:                ch != '/'    &&
        !           160:                ch != '_'    &&
        !           161:                ch != '\''   &&
        !           162:                ch != '"'    &&
        !           163:                ch != '#')
        !           164:        {
        !           165:                return ch;
        !           166:        }
        !           167: 
        !           168:        if ((ch == '\'') || (ch == '"'))
        !           169:        {
        !           170:                char ch2;
        !           171:                while ((ch2 = GetChar()) != ch)
        !           172:                {
        !           173:                        *pch++ = ch2;
        !           174:                }
        !           175:                *pch++ = ch2;
        !           176:                stringToken.ReleaseBuffer(pch - pchInit);
        !           177:                return chMoreThanOne;
        !           178:        }
        !           179: 
        !           180:        if (ch == '/')
        !           181:        {   
        !           182:                char ch2 = GetChar();
        !           183:                if (AtFileEnd()) exit(0);
        !           184:                if (ch2 == '/')
        !           185:                {
        !           186:                        char ch3 = GetChar();
        !           187:                        if (ch3 != '$')
        !           188:                        {
        !           189:                                UnGetChar();
        !           190:                                *pch++ = '/';
        !           191:                                fComment = TRUE;
        !           192:                                while ((ch3 = GetChar()) != '\n')
        !           193:                                        *pch++ = ch3;
        !           194:                        }
        !           195:                        else
        !           196:                        {
        !           197:                                stringToken.ReleaseBuffer(0);
        !           198:                        }
        !           199:                        *pch++ = '\n';
        !           200:                        stringToken.ReleaseBuffer(pch - pchInit);
        !           201:                        return chMoreThanOne;
        !           202:                }
        !           203:                else if (ch2 == '*')
        !           204:                {
        !           205:                        char ch3 = chNot;
        !           206:                        char ch4 = chNot;
        !           207:                        *pch++ = '*';
        !           208:                        fComment = TRUE;
        !           209:                        while (ch4 != '/')
        !           210:                        {
        !           211:                                while ((ch3 = GetChar()) != '*')
        !           212:                                        *pch++ = ch3;
        !           213:                                *pch++ = '*';   
        !           214: 
        !           215:                                ch4 = GetChar();
        !           216:                                if (ch4 != '/')
        !           217:                                        UnGetChar();
        !           218:                        }
        !           219:                        *pch++ = '/';
        !           220:                        stringToken.ReleaseBuffer(pch - pchInit);
        !           221:                        return chMoreThanOne;
        !           222:                }
        !           223:                else
        !           224:                {
        !           225:                        UnGetChar();
        !           226:                        return ch;
        !           227:                }
        !           228:        }
        !           229: 
        !           230:        if (isdigit(ch))
        !           231:        {
        !           232:                char ch2;
        !           233:                ch2 = GetChar();
        !           234:                if (!isalpha(ch2))
        !           235:                {
        !           236:                        UnGetChar();
        !           237:                        return ch;
        !           238:                }
        !           239: 
        !           240:                *pch++ = ch2;
        !           241:                stringToken.ReleaseBuffer(pch - pchInit);
        !           242:                return chMoreThanOne;
        !           243:        }
        !           244: 
        !           245:        while ((!AtFileEnd()) &&
        !           246:                (ch = GetChar(), (isalnum(ch) || (ch == '_'))))
        !           247:        {
        !           248:                *pch++ = ch;
        !           249:        }
        !           250: 
        !           251:        if (!AtFileEnd())
        !           252:                UnGetChar();
        !           253: 
        !           254:        stringToken.ReleaseBuffer(pch - pchInit);
        !           255:        return chMoreThanOne;
        !           256: }
        !           257: 
        !           258: char CTokenFile::GetPrintToken()
        !           259: {
        !           260:        char chToken;
        !           261:        while (((chToken = GetToken()) != chMoreThanOne) &&
        !           262:                   (isspace(chToken)) || fComment)
        !           263:                /* try again */ ;
        !           264: 
        !           265:        return chToken;
        !           266: }
        !           267: 
        !           268: char CTokenFile::GetTypeToken()
        !           269: {
        !           270:        char chToken = GetPrintToken();
        !           271:        CString typeStr = stringToken;
        !           272:        char chFirst = typeStr[0];
        !           273: 
        !           274:        CheckSyntax( 
        !           275:                isalnum(chFirst) || 
        !           276:                chFirst == '_'   || 
        !           277:                chFirst == '\''  || 
        !           278:                chFirst == '"',
        !           279:                "a type description or constant starting with an\n"
        !           280:                "alphanumeric or an underbar, or a string or char constant");
        !           281: 
        !           282:        while ((chToken = GetPrintToken()) != ',' && chToken != '>')
        !           283:        {
        !           284:                if (chToken != '*' && chToken != '&')
        !           285:                        typeStr += ' ';
        !           286: 
        !           287:                typeStr += stringToken;
        !           288:        }
        !           289: 
        !           290:        stringToken = typeStr;
        !           291:        return chToken;
        !           292: }
        !           293: 
        !           294: char CTokenFile::GetNameToken()
        !           295: {
        !           296:        GetPrintToken();
        !           297: 
        !           298:        CheckSyntax((isalpha(stringToken[0]) || stringToken[0] == '_'),
        !           299:                "a name token starting in an alpha char or underbar");
        !           300: 
        !           301:        int l = stringToken.GetLength();
        !           302:        for (int i=1; i<l; ++i)
        !           303:        {
        !           304:                CheckSyntax(isalnum(stringToken[i]) || stringToken[i] == '_',
        !           305:                        "a name token consisting of alphanumerics or underbars");
        !           306:        }
        !           307: 
        !           308:        CheckSyntax(stringToken != stringTemplate, "a name token");
        !           309:        CheckSyntax(stringToken != stringClass, "a name token");
        !           310: 
        !           311:        return chMoreThanOne;
        !           312: }
        !           313: 
        !           314: /////////////////////////////////////////////////////////////////////////////
        !           315: 
        !           316: CMapStringToString map;
        !           317: 
        !           318: BOOL isTailMatch(CString string, CString tail)
        !           319: {
        !           320:        BOOL retval = string.Right(tail.GetLength()) == tail;
        !           321:        ASSERT(retval);
        !           322:        return retval;
        !           323: }
        !           324: 
        !           325: CTokenFile file_h;
        !           326: CTokenFile file_cpp;
        !           327: CTokenFile file_ctt;
        !           328: 
        !           329: static BOOL fEnableIfElseEating = FALSE;
        !           330: 
        !           331: // TranslateTo:
        !           332: // Copy file_ctt to file_out, translating words as necessary.
        !           333: // On the way, swallow things outside of blocks and after
        !           334: // the "template" word inside of '<' '>' brackets.
        !           335: //
        !           336: // Also, on the way, any #if or #else statements that are conditional
        !           337: // on a constant "1" or "0" template parameter will be swallowed as
        !           338: // appropriate.
        !           339: //
        !           340: void TranslateTo(CTokenFile& file_out)
        !           341: {
        !           342:        char chToken;
        !           343:        static BOOL fswallowParams = TRUE;
        !           344:        BOOL fswallow = FALSE;
        !           345:        BOOL finIf = FALSE;
        !           346:        BOOL finElse = FALSE;
        !           347:        BOOL fswallowIf = FALSE;
        !           348:        BOOL fswallowElse = FALSE;
        !           349:        CString stringTokenOut;
        !           350: 
        !           351:        while ((chToken = file_ctt.GetToken()) != chMoreThanOne ||
        !           352:                   file_ctt.TokenString() != "IMPLEMENT_TEMPLATE")
        !           353:        {
        !           354:                if (chToken != chMoreThanOne)
        !           355:                {
        !           356:                        if (chToken == '{')
        !           357:                                fswallowParams = FALSE;
        !           358:                        if (fswallowParams && (chToken == '<'))
        !           359:                        {
        !           360:                                while (chToken != '>')
        !           361:                                        chToken = file_ctt.GetToken();
        !           362:                        }
        !           363:                        else
        !           364:                        {
        !           365:                                if (!fswallow)
        !           366:                                        file_out.PutToken();
        !           367:                        }
        !           368:                }
        !           369:                else
        !           370:                {
        !           371:                        if (fEnableIfElseEating && file_ctt.TokenString()[0] == '#')
        !           372:                        {
        !           373:                                if (file_ctt.TokenString() == "#if")
        !           374:                                {   
        !           375:                                        file_ctt.GetPrintToken();
        !           376:                                        if (map.Lookup(file_ctt.TokenString(), stringTokenOut))
        !           377:                                        {
        !           378:                                                if (stringTokenOut == "0")
        !           379:                                                {
        !           380:                                                        fswallowIf = TRUE;
        !           381:                                                        fswallowElse = FALSE;
        !           382:                                                }
        !           383:                                                else
        !           384:                                                {
        !           385:                                                        if (stringTokenOut == "1");
        !           386:                                                        {
        !           387:                                                                fswallowElse = TRUE;
        !           388:                                                                fswallowIf = FALSE;
        !           389:                                                        }
        !           390:                                                }
        !           391: 
        !           392:                                                if (fswallowIf || fswallowElse)
        !           393:                                                {
        !           394:                                                        file_ctt.TokenString() = "";
        !           395:                                                        finIf = TRUE;
        !           396:                                                }
        !           397: 
        !           398:                                                fswallow = fswallowIf;
        !           399:                                        }
        !           400:                                        else
        !           401:                                        {
        !           402:                                                file_out.PutToken("#if ");
        !           403:                                        }
        !           404:                                }
        !           405:                                else if (file_ctt.TokenString() == "#else")
        !           406:                                {
        !           407:                                        if (finIf)
        !           408:                                        {
        !           409:                                                file_ctt.TokenString() = "";
        !           410:                                                finIf = FALSE;
        !           411:                                                finElse = TRUE;
        !           412:                                        }
        !           413: 
        !           414:                                        fswallow = fswallowElse;
        !           415:                                }
        !           416:                                else if (file_ctt.TokenString() == "#endif")
        !           417:                                {
        !           418:                                        if (finIf || finElse)
        !           419:                                        {
        !           420:                                                file_ctt.TokenString() = "";
        !           421: 
        !           422:                                                // eat any evil
        !           423:                                                //junk after the #endif
        !           424:                                                while ((chToken = file_ctt.GetToken()) != '\n' &&
        !           425:                                                        file_ctt.TokenString()[0] != '/')
        !           426:                                                        /* spin */ ;
        !           427: 
        !           428:                                                if (chToken != '\n')
        !           429:                                                        file_ctt.GetToken();
        !           430:                                        }
        !           431:                                        finIf = FALSE;
        !           432:                                        finElse = FALSE;
        !           433:                                        fswallowIf = FALSE;
        !           434:                                        fswallowElse = FALSE;
        !           435:                                        fswallow = FALSE;
        !           436:                                }
        !           437:                        }
        !           438: 
        !           439:                        if (file_ctt.TokenString() == stringTemplate)
        !           440:                                fswallowParams = TRUE;
        !           441: 
        !           442:                        if (map.Lookup(file_ctt.TokenString(), stringTokenOut))
        !           443:                        {
        !           444:                                if (!fswallow)
        !           445:                                        file_out.PutToken(stringTokenOut);
        !           446:                        }
        !           447:                        else
        !           448:                        {
        !           449:                                if (!fswallow)
        !           450:                                        file_out.PutToken();
        !           451:                        }
        !           452:                }
        !           453:        }
        !           454: }
        !           455: 
        !           456: // main:
        !           457: // Gets the arguments, checks them, then processes the files.
        !           458: //
        !           459: main(int argc, char* argv[])
        !           460: {
        !           461:        CString stringTypes;
        !           462:        {
        !           463:                for (int i=1; i<(argc-3); ++i)
        !           464:                {
        !           465:                        stringTypes += CString(argv[i]) + ' ';
        !           466:                }
        !           467:        }
        !           468: 
        !           469:        if (argc < 4)
        !           470:                UsageErr(NULL, NULL);
        !           471: 
        !           472:        // Copy the template, header and source file name arguments.
        !           473:        //
        !           474:        string_ctt = argv[argc-3];
        !           475:        string_h   = argv[argc-2];
        !           476:        string_cpp = argv[argc-1];
        !           477: 
        !           478:        // Check to make sure that the args are in the right order.
        !           479:        //
        !           480:        if (!isTailMatch(string_cpp, ".cpp") &&
        !           481:                !isTailMatch(string_cpp, ".cxx"))
        !           482:                UsageErr("module file should have a .cpp or .cxx extension");
        !           483: 
        !           484:        if (!isTailMatch(string_ctt, ".ctt"))
        !           485:                UsageErr("template file should have a .ctt extension");
        !           486: 
        !           487:        if (!isTailMatch(string_h, ".h") &&
        !           488:                !isTailMatch(string_h, ".hpp") &&
        !           489:                !isTailMatch(string_h, ".hxx"))
        !           490:                UsageErr("header file should have an .h, .hpp or .hxx extension");
        !           491: 
        !           492:        // Open the files.
        !           493:        //
        !           494:        file_ctt.SafeOpen(string_ctt, CTokenFile::modeRead);
        !           495:        file_h.SafeOpen(string_h,
        !           496:                CTokenFile::modeWrite | CTokenFile::modeCreate);
        !           497:        file_cpp.SafeOpen(string_cpp,
        !           498:                CTokenFile::modeWrite | CTokenFile::modeCreate);
        !           499: 
        !           500:        // Push the command line onto the file buffer, so that we can parse it
        !           501:        // using our standard tool set.
        !           502:        //
        !           503:        file_ctt.InitBuf(stringTypes);
        !           504: 
        !           505:        int chToken;
        !           506:        CString astringTypeParam[istringTypeParamMax];
        !           507:        int istringTypeParam = 0;
        !           508: 
        !           509:        file_ctt.GetNameToken();
        !           510:        stringTemplateName = file_ctt.TokenString();
        !           511: 
        !           512:        chToken = file_ctt.GetPrintToken();
        !           513:        CheckSyntax(chToken == '<', "'<'");
        !           514: 
        !           515:        do
        !           516:        {
        !           517:                chToken = file_ctt.GetTypeToken();
        !           518:                if ((file_ctt.TokenString() == "0") ||
        !           519:                        (file_ctt.TokenString() == "1"))
        !           520:                {
        !           521:                        fEnableIfElseEating = TRUE;
        !           522:                }
        !           523:                astringTypeParam[istringTypeParam++] = file_ctt.TokenString();
        !           524:                CheckSyntax(istringTypeParam < istringTypeParamMax,
        !           525:                        "fewer parameterized types (program limit)");
        !           526:        } while (chToken == ',');
        !           527: 
        !           528:        CheckSyntax(chToken == '>', "'>'");
        !           529: 
        !           530:        file_ctt.GetNameToken();
        !           531:        stringTypedefName = file_ctt.TokenString();
        !           532: 
        !           533:        map.SetAt(stringTemplate, " ");
        !           534:        map.SetAt(stringTemplateName, stringTypedefName);
        !           535: 
        !           536:        // Done processing the command line part, now eat any initial comments
        !           537:        // appearing before the //$DECLARE_TEMPLATE flag.
        !           538:        //
        !           539:        while ((chToken = file_ctt.GetPrintToken()) != chMoreThanOne ||
        !           540:                   file_ctt.TokenString() != "DECLARE_TEMPLATE")
        !           541:        {
        !           542:                /* spin */ ;
        !           543:        }
        !           544: 
        !           545:        while ((file_ctt.GetToken() != chMoreThanOne) ||
        !           546:                   (file_ctt.TokenString() != stringTemplate))
        !           547:        {   
        !           548:                file_h.PutToken();
        !           549:        }
        !           550: 
        !           551:        // Token must now be "template".
        !           552:        
        !           553:        // Eat opening '<'.
        !           554:        //
        !           555:        chToken = file_ctt.GetPrintToken();
        !           556: 
        !           557:        // Now get a list of type parameters.
        !           558:        //
        !           559:        int istringTypeParamMaxPrev = istringTypeParam;
        !           560:        istringTypeParam = 0;
        !           561:        while (chToken !='>')
        !           562:        {
        !           563:                CString stringParamName;
        !           564: 
        !           565:                // The parameter name is the last thing before a ',' or '>'.
        !           566:                //
        !           567:                while ((chToken = file_ctt.GetPrintToken()) != ',' && chToken != '>')
        !           568:                {
        !           569:                        stringParamName = file_ctt.TokenString();
        !           570:                }
        !           571: 
        !           572:                map.SetAt(stringParamName, astringTypeParam[istringTypeParam++]);
        !           573:        }
        !           574: 
        !           575:        CheckSyntax(istringTypeParam == istringTypeParamMaxPrev,
        !           576:                "same number of template parameters");
        !           577: 
        !           578:        // Copy template to header file, translating words as necessary,
        !           579:        // terminating when the //$IMPLEMENT_TEMPLATE flag is hit.
        !           580:        //
        !           581:        TranslateTo(file_h);
        !           582: 
        !           583:        // Copy template to source file, translating words as necessary.
        !           584:        //
        !           585:        TranslateTo(file_cpp);
        !           586: 
        !           587:        return 0;
        !           588: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.