Annotation of mstools/mfc/samples/templdef/templdef.cpp, revision 1.1.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.