home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / Ami / source / lexer.cpp next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  14.4 KB  |  668 lines

  1. #include <stdio.h>
  2. #include <list>
  3. #include <vector>
  4.  
  5. #include "lexer.h"
  6. #include "utils.h"
  7.  
  8. FILE *g_file;
  9. bool g_bUnicode;
  10. std::string g_filename;
  11. int g_lineno;
  12. int g_commentlineno;
  13. bool g_bInComment;
  14. std::vector<wint_t> g_backstack;
  15. int g_pushedToken;
  16. int g_intVal;
  17. std::wstring g_identifier;
  18.  
  19. struct IncludeEntry {
  20.     FILE *f;
  21.     std::string filename;
  22.     int lineno;
  23.     bool bUnicode;
  24. };
  25.  
  26. std::list<IncludeEntry> g_includeStack;
  27.  
  28. static const struct {
  29.     const wchar_t *name;
  30.     const char *ansi_name;
  31.     int token;
  32. } g_keywords[]={
  33.     { L"include",            "include",                kTokenInclude },
  34.     { L"enum",                "enum",                    kTokenEnum },
  35.     { L"let",                "let",                    kTokenLet },
  36.     { L"declare",            "declare",                kTokenDeclare },
  37.     { L"using",                "using",                kTokenUsing },
  38.     { L"now",                "now",                    kTokenNow },
  39.  
  40.     { L"label",                "label",                kTokenLabel },
  41.     { L"edit",                "edit",                    kTokenEdit },
  42.     { L"editInt",            "editInt",                kTokenEditInt },
  43.     { L"button",            "button",                kTokenButton },
  44.     { L"checkBox",            "checkBox",                kTokenCheckBox },
  45.     { L"listBox",            "listBox",                kTokenListBox },
  46.     { L"comboBox",            "comboBox",                kTokenComboBox },
  47.     { L"listView",            "listView",                kTokenListView },
  48.     { L"trackBar",            "trackBar",                kTokenTrackbar },
  49.     { L"fileControl",        "fileControl",            kTokenFileControl },
  50.     { L"set",                "set",                    kTokenSet },
  51.     { L"pageset",            "pageset",                kTokenPageSet },
  52.     { L"grid",                "grid",                    kTokenGrid },
  53.     { L"option",            "option",                kTokenOption },
  54.     { L"group",                "group",                kTokenGroup },
  55.     { L"splitter",            "splitter",                kTokenSplitter },
  56.     { L"textedit",            "textedit",                kTokenTextEdit },
  57.     { L"textarea",            "textarea",                kTokenTextArea },
  58.     { L"hotkey",            "hotkey",                kTokenHotkey },
  59.     { L"customWindow",        "customWindow",            kTokenCustomWindow },
  60.  
  61.     { L"listitem",            "listitem",                kTokenListItem },
  62.     { L"page",                "page",                    kTokenPage },
  63.     { L"row",                "row",                    kTokenRow },
  64.     { L"column",            "column",                kTokenColumn },
  65.     { L"nextrow",            "nextrow",                kTokenNextRow },
  66.  
  67.     { L"stringSet",            "stringSet",            kTokenStringSet },
  68.     { L"message",            "message",                kTokenMessage },
  69.     { L"override",            "override",                kTokenOverride },
  70.     { L"dialog",            "dialog",                kTokenDialog },
  71.     { L"template",            "template",                kTokenTemplate },
  72.  
  73.     { L"marginl",            "marginl",                kTokenMarginL },
  74.     { L"margint",            "margint",                kTokenMarginT },
  75.     { L"marginr",            "marginr",                kTokenMarginR },
  76.     { L"marginb",            "marginb",                kTokenMarginB },
  77.     { L"padl",                "padl",                    kTokenPadL },
  78.     { L"padt",                "padt",                    kTokenPadT },
  79.     { L"padr",                "padr",                    kTokenPadR },
  80.     { L"padb",                "padb",                    kTokenPadB },
  81.     { L"minw",                "minw",                    kTokenMinW },
  82.     { L"minh",                "minh",                    kTokenMinH },
  83.     { L"maxw",                "maxw",                    kTokenMaxW },
  84.     { L"maxh",                "maxh",                    kTokenMaxH },
  85.     { L"align",                "align",                kTokenAlign },
  86.     { L"valign",            "valign",                kTokenVAlign },
  87.     { L"spacing",            "spacing",                kTokenSpacing },
  88.     { L"aspect",            "aspect",                kTokenAspect },
  89.     { L"affinity",            "affinity",                kTokenAffinity },
  90.     { L"rowspan",            "rowspan",                kTokenRowSpan },
  91.     { L"colspan",            "colspan",                kTokenColSpan },
  92.  
  93.     { L"vertical",            "vertical",                kTokenVertical },
  94.     { L"raised",            "raised",                kTokenRaised },
  95.     { L"sunken",            "sunken",                kTokenSunken },
  96.     { L"child",                "child",                kTokenChild },
  97.     { L"multiline",            "multiline",            kTokenMultiline },
  98.     { L"readonly",            "readonly",                kTokenReadonly },
  99.     { L"checkable",            "checkable",            kTokenCheckable },
  100.     { L"noheader",            "noheader",                kTokenNoHeader },
  101.     { L"default",            "default",                kTokenDefault },
  102.  
  103.     { L"enable",            "enable",                kTokenEnable },
  104.     { L"value",                "value",                kTokenValue },
  105.  
  106.     { L"left",                "left",                    kTokenLeft },
  107.     { L"center",            "center",                kTokenCenter },
  108.     { L"right",                "right",                kTokenRight },
  109.     { L"top",                "top",                    kTokenTop },
  110.     { L"bottom",            "bottom",                kTokenBottom },
  111.     { L"fill",                "fill",                    kTokenFill },
  112.     { L"expand",            "expand",                kTokenExpand },
  113.     { L"link",                "link",                    kTokenLink },
  114.     { L"addColumn",            "addColumn",            kTokenAddColumn },
  115. };
  116.  
  117. enum { kKeywordCount = sizeof g_keywords / sizeof g_keywords[0] };
  118.  
  119.  
  120. ///////////////////////////////////////////////////////////////////////////
  121. //
  122. //    lexical analyzer
  123. //
  124. ///////////////////////////////////////////////////////////////////////////
  125.  
  126. const std::wstring& lexident() {
  127.     return g_identifier;
  128. }
  129.  
  130. int lexint() {
  131.     return g_intVal;
  132. }
  133.  
  134. const char *lexfilename() {
  135.     return g_filename.c_str();
  136. }
  137.  
  138. int lexlineno() {
  139.     return g_lineno;
  140. }
  141.  
  142. bool lexisunicode() {
  143.     return g_bUnicode;
  144. }
  145.  
  146. void lextestunicode() {
  147.     int c = getc(g_file);
  148.  
  149.     g_bUnicode = false;
  150.  
  151.     if (c == 0xFF) {
  152.         int d = getc(g_file);
  153.  
  154.         if (d == 0xFE) {
  155.             g_bUnicode = true;
  156.         } else {
  157.             lexungetc(d);
  158.             lexungetc(c);
  159.         }
  160.     } else
  161.         lexungetc(c);
  162. }
  163.  
  164. void lexopen(const char *fn) {
  165.     g_filename = fn;
  166.     g_file = fopen(fn, "rb");
  167.     if (!g_file)
  168.         fatal("cannot open input file %s", g_filename.c_str());
  169.     g_lineno = 1;
  170.     lextestunicode();
  171. }
  172.  
  173. void lexinclude(const std::string& filename) {
  174.     FILE *f = fopen(filename.c_str(), "rb");
  175.  
  176.     if (!f)
  177.         fatal("Cannot open include file \"%s\"", filename.c_str());
  178.  
  179.     g_includeStack.push_front(IncludeEntry());
  180.     g_includeStack.front().f = g_file;
  181.     g_includeStack.front().filename = g_filename;
  182.     g_includeStack.front().lineno = g_lineno;
  183.     g_includeStack.front().bUnicode = g_bUnicode;
  184.  
  185.     g_file = f;
  186.     g_filename = filename;
  187.     g_lineno = 1;
  188.  
  189.     lextestunicode();
  190.  
  191.     printf("Ami: Including file \"%s\" (%s)\n", g_filename.c_str(), g_bUnicode ? "Unicode" : "ANSI");
  192. }
  193.  
  194. wint_t lexrawgetc() {
  195.     wint_t c;
  196.     
  197.     if (g_backstack.empty()) {
  198.         for(;;) {
  199.             if (g_bUnicode) {
  200.                 c = getwc(g_file);
  201.             } else
  202.                 c = getc(g_file);
  203.  
  204.             if (c != WEOF || g_includeStack.empty())
  205.                 break;
  206.  
  207.             fclose(g_file);
  208.             g_file = g_includeStack.front().f;
  209.             g_filename = g_includeStack.front().filename;
  210.             g_lineno = g_includeStack.front().lineno;
  211.             g_bUnicode = g_includeStack.front().bUnicode;
  212.             g_includeStack.pop_front();
  213.         }
  214.     } else {
  215.         c = g_backstack.back();
  216.         g_backstack.pop_back();
  217.     }
  218.     return c;
  219. }
  220.  
  221. // We can't just use unget[w]c() here, because the Unicode escape mechanism
  222. // may cause more than one character to be pushed back.
  223.  
  224. void lexungetc(wint_t c) {
  225.     if (c < 0)
  226.         return;
  227.  
  228.     g_backstack.push_back(c);
  229. }
  230.  
  231. wint_t lexgetc() {
  232.     wint_t c = lexrawgetc();
  233.  
  234.     // check if it is a Unicode escape
  235.  
  236.     if (c == '\\') {
  237.         c = lexrawgetc();
  238.  
  239.         if (c == 'u') {
  240.             // Unicode escape!
  241.  
  242.             wint_t c1 = lexrawgetc();
  243.             wint_t c2 = lexrawgetc();
  244.             wint_t c3 = lexrawgetc();
  245.             wint_t c4 = lexrawgetc();
  246.  
  247.             if (c1 == WEOF || c2 == WEOF || c3 == WEOF || c4 == WEOF)
  248.                 fatal("EOF encountered in Unicode escape");
  249.  
  250.             if (!iswxdigit(c1) || !iswxdigit(c2) || !iswxdigit(c3) || !iswxdigit(c4))
  251.                 fatal("Non-hex digit encountered in Unicode escape");
  252.  
  253.             c1 -= '0';
  254.             if (c1 > 10)
  255.                 c1 -= 6;
  256.             c2 -= '0';
  257.             if (c2 > 10)
  258.                 c2 -= 6;
  259.             c3 -= '0';
  260.             if (c3 > 10)
  261.                 c3 -= 6;
  262.             c4 -= '0';
  263.             if (c4 > 10)
  264.                 c4 -= 6;
  265.  
  266.             return (c1<<12) + (c2<<8) + (c3<<4) + c4;
  267.         } else
  268.             lexungetc(c);
  269.  
  270.         return '\\';
  271.     }
  272.  
  273.     return c;
  274. }
  275.  
  276. wint_t lexgetescape() {
  277.     wint_t c = lexgetc();
  278.  
  279.     if (c < 0)
  280.         fatal("Newline found in escape sequence");
  281.  
  282.     switch(c) {
  283.     case '0':    return 0;
  284.     case 'a':    return '\a';
  285.     case 'b':    return '\b';
  286.     case 'f':    return '\f';
  287.     case 'n':    return '\n';
  288.     case 'r':    return '\r';
  289.     case 't':    return '\t';
  290.     case 'v':    return '\v';
  291.     case 'x':
  292.         {
  293.             wint_t c1 = lexgetc();
  294.             wint_t c2 = lexgetc();
  295.  
  296.             if (c1 == WEOF || c2 == WEOF)
  297.                 fatal("Newline found in escape sequence");
  298.                 
  299.             if (!iswxdigit(c1) || !iswxdigit(c2))
  300.                 fatal("Invalid \\x escape sequence");
  301.  
  302.             c1 -= '0';
  303.             if (c1 > 10)
  304.                 c1 -= 6;
  305.  
  306.             c2 -= '0';
  307.             if (c2 > 10)
  308.                 c2 -= 6;
  309.  
  310.             return (c1<<4) + c2;
  311.         }
  312.  
  313.     case '"':    return '"';
  314.     case '\'':    return '\'';
  315.     default:
  316.         if (c<0x100 && isprint(c))
  317.             fatal("Invalid escape sequence \\%c", c);
  318.         else
  319.             fatal("Invalid escape sequence \\\\u%04x", c);
  320.     }
  321.  
  322.     return 0;    // this won't actually ever get executed...
  323. }
  324.  
  325. void lexpush(int token) {
  326.     if (g_pushedToken)
  327.         fatal_internal(__FILE__, __LINE__);
  328.  
  329.     g_pushedToken = token;
  330. }
  331.  
  332. int lex() {
  333.     wint_t c;
  334.  
  335.     if (g_pushedToken) {
  336.         int t = g_pushedToken;
  337.  
  338.         g_pushedToken = 0;
  339.         return t;
  340.     }
  341.  
  342.     for(;;) {
  343.         c = lexgetc();
  344.  
  345.         if (c == WEOF) {
  346.             if (ferror(g_file))
  347.                 fatal("Read error");
  348.  
  349.             if (g_bInComment)
  350.                 fatal("EOF found while parsing comment starting at line %d", g_commentlineno);
  351.  
  352.             return kTokenEOF;
  353.         }
  354.  
  355.         // process EOLs
  356.  
  357.         if (c == '\r') {
  358.             c = lexgetc();
  359.  
  360.             if (c != '\n')
  361.                 lexungetc(c);
  362.  
  363.             ++g_lineno;
  364.             continue;
  365.         } else if (c == '\n') {
  366.             ++g_lineno;
  367.             continue;
  368.         }
  369.  
  370.         // discard whitespace and ^Z
  371.  
  372.         if (iswspace(c) || c == 26)
  373.             continue;
  374.  
  375.         // are we in a comment?
  376.  
  377.         if (g_bInComment) {
  378.             if (c == '/') {
  379.                 c = lexgetc();
  380.  
  381.                 if (c == '*')
  382.                     fatal("C-style comment already started at line %d", g_commentlineno);
  383.                 else if (c == '/') {
  384.                     do {
  385.                         c = lexgetc();
  386.                     } while(c != '\r' && c != '\n');
  387.                 }
  388.  
  389.                 lexungetc(c);
  390.             } else if (c == '*') {
  391.                 c = lexgetc();
  392.  
  393.                 if (c == '/')
  394.                     g_bInComment = false;
  395.                 else
  396.                     lexungetc(c);
  397.             }
  398.         } else {
  399.             switch(c) {
  400.  
  401.             // single character, non-overloaded tokens
  402.             case '~':
  403.             case ',':
  404.             case ':':
  405.             case ';':
  406.             case '{':
  407.             case '}':
  408.             case '(':
  409.             case ')':
  410.             case '[':
  411.             case ']':
  412.             case '@':
  413.                 return c;
  414.  
  415.             case '+':
  416.                 c = lexgetc();
  417.                 if (c == '+')
  418.                     return kTokenPlusPlus;
  419.                 lexungetc(c);
  420.                 return '+';
  421.  
  422.             case '-':
  423.                 c = lexgetc();
  424.                 if (c == '-')
  425.                     return kTokenMinusMinus;
  426.                 lexungetc(c);
  427.                 return '-';
  428.  
  429.             // these must be overloaded for comments
  430.             case '*':
  431.                 c = lexgetc();
  432.                 if (c == '/')
  433.                     fatal("'*/' found outside of C-style comment");
  434.  
  435.                 lexungetc(c);
  436.                 return '*';
  437.  
  438.             case '/':
  439.                 c = lexgetc();
  440.                 if (c == '*') {
  441.                     g_commentlineno = g_lineno;
  442.                     g_bInComment = true;
  443.                     continue;
  444.                 } else if (c == '/') {
  445.                     do {
  446.                         c = lexgetc();
  447.                     } while(c != '\r' && c != '\n');
  448.  
  449.                     lexungetc(c);
  450.                     continue;
  451.                 }
  452.                 lexungetc(c);
  453.                 return '/';
  454.  
  455.             case '=':
  456.                 c = lexgetc();
  457.                 if (c == '=')
  458.                     return kTokenEQ;
  459.                 lexungetc(c);
  460.                 return '=';
  461.  
  462.             case '!':
  463.                 c = lexgetc();
  464.                 if (c == '=')
  465.                     return kTokenNE;
  466.                 lexungetc(c);
  467.                 return '!';
  468.  
  469.             case '<':
  470.                 c = lexgetc();
  471.                 if (c == '=')
  472.                     return kTokenLE;
  473.                 lexungetc(c);
  474.                 return '<';
  475.  
  476.             case '>':
  477.                 c = lexgetc();
  478.                 if (c == '=')
  479.                     return kTokenGE;
  480.                 lexungetc(c);
  481.                 return '>';
  482.  
  483.             case '&':
  484.                 c = lexgetc();
  485.                 if (c == '&')
  486.                     return kTokenLogicalAnd;
  487.                 lexungetc(c);
  488.                 break;
  489.  
  490.             case '|':
  491.                 c = lexgetc();
  492.                 if (c == '|')
  493.                     return kTokenLogicalOr;
  494.                 lexungetc(c);
  495.                 break;
  496.  
  497.             case '\'':
  498.                 g_intVal = 0;
  499.                 c = lexgetc();
  500.                 if (c == '\'')
  501.                     fatal("Empty character literal constant");
  502.  
  503.                 {
  504.                     int count = 0;
  505.                     do {
  506.                         if (++count > 4)
  507.                             fatal("Character constant too large");
  508.  
  509.                         if (c == '\\') {
  510.                             c = lexgetescape();
  511.                         }
  512.                         if (c == '\r' || c == '\n')
  513.                             fatal("Newline found in character constant");
  514.  
  515.                         g_intVal = (g_intVal << 8) + c;
  516.                         c = lexgetc();
  517.                     } while(c != '\'');
  518.                 }
  519.                 return kTokenInteger;
  520.  
  521.             case '"':
  522.                 g_identifier.resize(0);
  523.                 for(;;) {
  524.                     c = lexgetc();
  525.                     if (c == '\\') {
  526.                         c = lexgetescape();
  527.                         g_identifier += (wchar_t) c;
  528.                         continue;
  529.                     }
  530.  
  531.                     if (c == '\r' || c=='\n')
  532.                         fatal("Newline found in string constant");
  533.  
  534.                     if (c == '"')
  535.                         break;
  536.  
  537.                     g_identifier += (wchar_t)c;
  538.                 }
  539.  
  540.                 return kTokenString;
  541.  
  542.             default:
  543.                 if (iswdigit(c)) {
  544.                     // check for a leading zero -- we don't care about octal, but
  545.                     // we do care about hex....
  546.  
  547.                     int v = 0;
  548.  
  549.                     if (c == '0') {
  550.                         c = lexgetc();
  551.  
  552.                         if (c == 'x') {
  553.                             // hex constant!
  554.  
  555.                             for(;;) {
  556.                                 c = lexgetc();
  557.                                 if (!iswxdigit(c))
  558.                                     break;
  559.                                 c = toupper(c) - 0x30;
  560.  
  561.                                 if (c>10)
  562.                                     c -= 6;
  563.  
  564.                                 v = (v<<4) + c;
  565.                             }
  566.  
  567.                             // absorb (and ignore) C/C++ number suffixes
  568.  
  569.                             if (c == 'u' || c=='U')
  570.                                 c = lexgetc();
  571.  
  572.                             if (c == 'l' || c=='L')
  573.                                 c = lexgetc();
  574.  
  575.                             lexungetc(c);
  576.  
  577.                             g_intVal = v;
  578.                             return kTokenInteger;
  579.                         } else {
  580.                             lexungetc(c);
  581.                             c = '0';
  582.                         }
  583.                     }
  584.  
  585.                     // decimal constant
  586.  
  587.                     do {
  588.                         v = v*10 + (c - '0');
  589.  
  590.                         c = lexgetc();
  591.                     } while(iswdigit(c));
  592.  
  593.                     // absorb (and ignore) C/C++ number suffixes
  594.  
  595.                     if (c == 'u' || c=='U')
  596.                         c = lexgetc();
  597.  
  598.                     if (c == 'l' || c=='L')
  599.                         c = lexgetc();
  600.  
  601.                     lexungetc(c);
  602.  
  603.                     g_intVal = v;
  604.                     return kTokenInteger;
  605.                 }
  606.  
  607.                 // Not a number.  Constant?
  608.  
  609.                 if (((unsigned)c < 0x100 && isalpha(c)) || c=='_') {
  610.                     g_identifier.resize(0);
  611.  
  612.                     do {
  613.                         g_identifier += (wchar_t)c;
  614.                         c = lexgetc();
  615.                     } while(c=='_' || ((unsigned)c<0x100 && iswalnum(c)));
  616.  
  617.                     lexungetc(c);
  618.  
  619.                     // Check keywords.
  620.  
  621.                     for(int i=0; i<kKeywordCount; ++i)
  622.                         if (!_wcsicmp(g_identifier.c_str(), g_keywords[i].name))
  623.                             return g_keywords[i].token;
  624.  
  625.                     return kTokenIdentifier;
  626.                 }
  627.             }
  628.  
  629.             // Whoops.
  630.  
  631.             if (c < 0x100 && isprint(c))
  632.                 fatal("Unrecognized character '%c'", c);
  633.             else
  634.                 fatal("Unrecognized character \\u%04x", c);
  635.         }
  636.     }
  637. }
  638.  
  639. std::string lextokenname(int token, bool expand) {
  640.     if (token < 0)
  641.         return "end of file";
  642.  
  643.     switch(token) {
  644.     case kTokenInteger:        return "integer";
  645.     case kTokenString:        return "string literal";
  646.     case kTokenIdentifier:    return expand ? std::string("identifier '") + ANSIify(g_identifier) + "'" : "identifier";
  647.     case kTokenPlusPlus:    return "'++'";
  648.     case kTokenMinusMinus:    return "'--'";
  649.     case kTokenEQ:            return "'=='";
  650.     case kTokenNE:            return "'!='";
  651.     case kTokenLE:            return "'<='";
  652.     case kTokenGE:            return "'>='";
  653.     case kTokenLogicalAnd:    return "'&&'";
  654.     case kTokenLogicalOr:    return "'||'";
  655.     default:
  656.         {
  657.             for(int i=0; i<kKeywordCount; ++i)
  658.                 if (g_keywords[i].token == token)
  659.                     return std::string("keyword '") + g_keywords[i].ansi_name + '\'';
  660.         }
  661.         if (token >= 255)
  662.             fatal_internal(__FILE__, __LINE__);
  663.  
  664.         return std::string("'") + (char)token + '\'';
  665.     }
  666. }
  667.  
  668.