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 / main.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  29.9 KB  |  1,346 lines

  1. #pragma warning(disable: 4786)        // shut up
  2.  
  3. #include <stdio.h>
  4. #include <stdarg.h>
  5. #include <ctype.h>
  6. #include <string>
  7. #include <vector>
  8. #include <map>
  9. #include <list>
  10. #include <utility>
  11.  
  12. #include "bytecode.h"
  13. #include "lexer.h"
  14. #include "utils.h"
  15. #include <vd2/system/vdstl.h>
  16. #include <vd2/Dita/interface.h>
  17.  
  18. using namespace nsVDUI;
  19. using namespace nsVDDitaBytecode;
  20.  
  21. ///////////////////////////////////////////////////////////////////////////
  22. //
  23. //    globals
  24. //
  25. ///////////////////////////////////////////////////////////////////////////
  26.  
  27.  
  28. ///////////////////////////////////////////////////////////////////////////
  29. //
  30. //    parser globals
  31. //
  32. ///////////////////////////////////////////////////////////////////////////
  33.  
  34. typedef std::map<int, std::wstring> tStringSet;
  35. typedef std::map<int, tStringSet> tStringResource;
  36. typedef std::map<std::wstring, int> tVarList;
  37. typedef std::list<tVarList> tScopeList;
  38. typedef std::vector<unsigned char> tDialogScript;
  39. typedef std::map<int, tDialogScript> tDialogList;
  40. typedef std::map<int, tDialogScript> tTemplateList;
  41.  
  42. tStringResource g_stringResource;
  43. tScopeList        g_scopes;
  44. tDialogList        g_dialogs;
  45. tTemplateList    g_templates;
  46. int                g_enableExprs;
  47.  
  48. ///////////////////////////////////////////////////////////////////////////
  49. //
  50. //    parser
  51. //
  52. ///////////////////////////////////////////////////////////////////////////
  53.  
  54. void expect(int found, int expected) {
  55.     if (found != expected)
  56.         fatal("Expected %s, found %s", lextokenname(expected, false).c_str(), lextokenname(found).c_str());
  57. }
  58.  
  59. void expect(int token) {
  60.     expect(lex(), token);
  61. }
  62.  
  63. void reject(int token) {
  64.     fatal("Unexpected %s", lextokenname(token).c_str());
  65. }
  66.  
  67. void unexpected(int token, const char *expected) {
  68.     fatal("Expected %s, found %s", expected, lextokenname(token).c_str());
  69. }
  70.  
  71. void parse_push_scope() {
  72.     g_scopes.push_front(tVarList());
  73. }
  74.  
  75. void parse_pop_scope() {
  76.     if (g_scopes.empty())
  77.         fatal_internal(__FILE__, __LINE__);
  78.  
  79.     g_scopes.pop_front();
  80. }
  81.  
  82. int parse_expression();
  83.  
  84. int *parse_lvalue_expression() {
  85.     int t = lex();
  86.  
  87.     if (t != kTokenIdentifier) {
  88.         fatal("Expected expression, found %s", lextokenname(t).c_str());
  89.     }
  90.  
  91.     tScopeList::iterator it = g_scopes.begin(), itEnd = g_scopes.end();
  92.     const std::wstring& ident = lexident();
  93.  
  94.     for(; it!=itEnd; ++it) {
  95.         tVarList& varlist = *it;
  96.         tVarList::iterator itV = varlist.find(ident);
  97.  
  98.         if (itV != varlist.end()) {
  99.             return &(*itV).second;
  100.         }
  101.     }
  102.  
  103.     fatal("Undeclared identifier '%s'", ANSIify(ident).c_str());
  104. }
  105.  
  106. int parse_prefix_expression() {
  107.     int t = lex();
  108.  
  109.     switch(t) {
  110.     case '(':
  111.         {
  112.             int v = parse_expression();
  113.             expect(')');
  114.             return v;
  115.         }
  116.         
  117.     case '+':
  118.         return parse_prefix_expression();
  119.     case '-':
  120.         return -parse_prefix_expression();
  121.     case '~':
  122.         return ~parse_prefix_expression();
  123.     case kTokenInteger:
  124.         return lexint();
  125.     case kTokenPlusPlus:
  126.         {
  127.             int *p = parse_lvalue_expression();
  128.  
  129.             return ++*p;
  130.         }
  131.     case kTokenMinusMinus:
  132.         {
  133.             int *p = parse_lvalue_expression();
  134.  
  135.             return --*p;
  136.         }
  137.     case kTokenLeft:
  138.     case kTokenTop:
  139.         return 1;
  140.     case kTokenCenter:
  141.         return 2;
  142.     case kTokenBottom:
  143.     case kTokenRight:
  144.         return 3;
  145.     case kTokenFill:
  146.         return 4;
  147.     case kTokenExpand:
  148.         return 0x100;
  149.     default:
  150.         lexpush(t);
  151.         return *parse_lvalue_expression();
  152.     }
  153.  
  154.     // shouldn't happen
  155.     return 0;
  156. }
  157.  
  158. // This is such a dirty hack.
  159.  
  160. int parse_postfix_expression() {
  161.     int t = lex();
  162.  
  163.     if (t == kTokenIdentifier) {
  164.         lexpush(t);
  165.         int *p = parse_lvalue_expression();
  166.  
  167.         t = lex();
  168.  
  169.         if (t == kTokenPlusPlus)
  170.             return (*p)++;
  171.         else if (t == kTokenMinusMinus)
  172.             return (*p)--;
  173.  
  174.         lexpush(t);
  175.         return *p;
  176.     }
  177.  
  178.     lexpush(t);
  179.  
  180.     return parse_prefix_expression();
  181. }
  182.  
  183. int parse_multiplicative_expression() {
  184.     int x = parse_postfix_expression();
  185.  
  186.     for(;;) {
  187.         int t = lex();
  188.  
  189.         if (t == '*') {
  190.             int y = parse_prefix_expression();
  191.  
  192.             x *= y;
  193.         } else if (t == '/') {
  194.             int y = parse_prefix_expression();
  195.  
  196.             if (!y)
  197.                 fatal("Divide by zero");
  198.  
  199.             x /= y;
  200.         } else {
  201.             lexpush(t);
  202.  
  203.             return x;
  204.         }
  205.     }
  206. }
  207.  
  208. int parse_additive_expression() {
  209.     int x = parse_multiplicative_expression();
  210.  
  211.     for(;;) {
  212.         int t = lex();
  213.  
  214.         if (t == '+') {
  215.             int y = parse_multiplicative_expression();
  216.  
  217.             x += y;
  218.         } else if (t == '-') {
  219.             int y = parse_multiplicative_expression();
  220.  
  221.             x -= y;
  222.         } else {
  223.             lexpush(t);
  224.  
  225.             return x;
  226.         }
  227.     }
  228. }
  229.  
  230.  
  231. int parse_expression() {
  232.     return parse_additive_expression();
  233. }
  234.  
  235. std::wstring parse_string_expression() {
  236.     expect(kTokenString);
  237.  
  238.     std::wstring text(lexident());
  239.  
  240.     for(;;) {
  241.         int t = lex();
  242.  
  243.         if (t == kTokenString)
  244.             text += lexident();
  245.         else {
  246.             lexpush(t);
  247.             return text;
  248.         }
  249.     }
  250. }
  251.  
  252. void parse_let() {
  253.     std::wstring name;
  254.  
  255.     expect(kTokenIdentifier);
  256.     name = lexident();
  257.     expect('=');
  258.     int v = parse_expression();
  259.     expect(';');
  260.  
  261.     tVarList& varlist = g_scopes.front();
  262.  
  263.     varlist[name] = v;
  264. }
  265.  
  266. void parse_declare() {
  267.     std::wstring name;
  268.  
  269.     expect(kTokenIdentifier);
  270.     name = lexident();
  271.     expect('=');
  272.     int v = parse_expression();
  273.     expect(';');
  274.  
  275.     tVarList& varlist = g_scopes.front();
  276.     tVarList::iterator it = varlist.find(name);
  277.  
  278.     // only err if the second declaration is different
  279.  
  280.     if (it != varlist.end()) {
  281.         if ((*it).second != v)
  282.             fatal("Variable %s already declared with value %d", ANSIify(name).c_str(), (*it).second);
  283.  
  284.         return;
  285.     }
  286.  
  287.     varlist[name] = v;
  288. }
  289.  
  290. void parse_enum() {
  291.     int eval = 0;
  292.     int t = lex();
  293.  
  294.     if (t != kTokenIdentifier)
  295.         lexpush(t);
  296.  
  297.     expect('{');
  298.  
  299.     for(;;) {
  300.         int v;
  301.  
  302.         expect(kTokenIdentifier);
  303.         std::wstring name(lexident());
  304.  
  305.         t = lex();
  306.  
  307.         if (t == '=') {
  308.             v = eval = parse_expression();
  309.         } else {
  310.             v = eval++;
  311.             lexpush(t);
  312.         }
  313.  
  314.         tVarList& varlist = g_scopes.front();
  315.         tVarList::iterator it = varlist.find(name);
  316.  
  317.         if (it != varlist.end()) {
  318.             if ((*it).second != v)
  319.                 fatal("Variable %s already declared with value %d", ANSIify(name).c_str(), (*it).second);
  320.         }
  321.         
  322.         varlist[name] = v;
  323.  
  324.         t = lex();
  325.  
  326.         if (t == '}')
  327.             break;
  328.  
  329.         lexpush(t);
  330.         expect(',');
  331.     }
  332.  
  333.     expect(';');
  334. }
  335.  
  336. void parse_common(int t) {
  337.     switch(t) {
  338.     case ';':
  339.         break;
  340.     case kTokenLet:
  341.         parse_let();
  342.         break;
  343.     case kTokenDeclare:
  344.         parse_declare();
  345.         break;
  346.     case kTokenEnum:
  347.         parse_enum();
  348.         break;
  349.     default:
  350.         fatal("Expected statement, found %s", lextokenname(t).c_str());
  351.     }
  352. }
  353.  
  354. void parse_message(tStringSet& set, int setid) {
  355.     int t = lex();
  356.     bool bAllowOverrides = false;
  357.  
  358.     if (t == kTokenOverride)
  359.         bAllowOverrides = true;
  360.     else
  361.         lexpush(t);
  362.  
  363.     int id = parse_expression();
  364.  
  365.     if (id < 0 || id > 65535)
  366.         fatal("String ID '%d' is not between 0 and 65535", id);
  367.  
  368.     if (!bAllowOverrides) {
  369.         tStringSet::iterator it = set.find(id);
  370.  
  371.         if (it != set.end())
  372.             warning("String set %d already has a string with ID %d", setid, id);
  373.     }
  374.  
  375.     expect(',');
  376.  
  377.     std::wstring msg = parse_string_expression();
  378.  
  379.     set[id] = msg;
  380.  
  381.     expect(';');
  382. }
  383.  
  384. void parse_stringSet() {
  385.     int setID = parse_expression();
  386.  
  387.     if (setID == 65535)
  388.         fatal("String set ID 65535 is reserved");
  389.  
  390.     if (setID < 0 || setID > 65535)
  391.         fatal("String set ID '%d' is not between 0 and 65535", setID);
  392.  
  393.     expect('{');
  394.     parse_push_scope();
  395.  
  396.     tStringSet& strset = g_stringResource[setID];
  397.     for(;;) {
  398.         int t = lex();
  399.  
  400.         if (t < 0)
  401.             fatal("Unterminated string set declaration");
  402.  
  403.         switch(t) {
  404.         case '}':
  405.             parse_pop_scope();
  406.             return;
  407.  
  408.         case kTokenMessage:
  409.             parse_message(strset, setID);
  410.             break;
  411.  
  412.         default:
  413.             parse_common(t);
  414.         }
  415.     }
  416. }
  417.  
  418. void parse_dialog_common(int dlgID, tDialogScript& script, int t);
  419.  
  420. void dialog_int(tDialogScript& script, int v) {
  421.     if (!v)
  422.         script.push_back(kBC_Zero);
  423.     else if (v == 1)
  424.         script.push_back(kBC_One);
  425.     else if (v == (signed char)v) {
  426.         script.push_back(kBC_Int8);
  427.         script.push_back(0xff & v);
  428.     } else {
  429.         script.push_back(kBC_Int32);
  430.         script.push_back(v & 0xff);
  431.         script.push_back((v>>8) & 0xff);
  432.         script.push_back((v>>16) & 0xff);
  433.         script.push_back((v>>24) & 0xff);
  434.     }
  435. }
  436.  
  437. void dialog_string(tDialogScript& script, int table, int id) {
  438.     if (table == 0xffff) {
  439.         script.push_back(kBC_StringShort);
  440.         script.push_back(id&0xff);
  441.         script.push_back((id>>8)&0xff);
  442.     } else {
  443.         script.push_back(kBC_String);
  444.         script.push_back(table&0xff);
  445.         script.push_back((table>>8)&0xff);
  446.         script.push_back(id&0xff);
  447.         script.push_back((id>>8)&0xff);
  448.     }
  449. }
  450.  
  451. // This is very expensive but I don't care
  452.  
  453. void dialog_string(tDialogScript& script, std::wstring str) {
  454.     tStringSet& strset = g_stringResource[65535];
  455.     tStringSet::iterator it = strset.begin(), itEnd = strset.end();
  456.     int count = 0;
  457.  
  458.     for(; it!=itEnd; ++it, ++count) {
  459.         if ((*it).second == str) {
  460.             dialog_string(script, 0xffff, (*it).first);
  461.             return;
  462.         }
  463.     }
  464.  
  465.     strset[count] = str;
  466.     dialog_string(script, 0xffff, count);
  467. }
  468.  
  469. void parse_dialog_string(int dialogID, tDialogScript& script) {
  470.     int t = lex();
  471.  
  472.     if (t == kTokenString) {
  473.         std::wstring s(lexident());
  474.  
  475.         for(;;) {
  476.             t = lex();
  477.             if (t != kTokenString) {
  478.                 lexpush(t);
  479.                 break;
  480.             }
  481.             s += lexident();
  482.         }
  483.  
  484.         dialog_string(script, s);
  485.     } else if (t == '[') {
  486.         int group = parse_expression();
  487.         int id;
  488.  
  489.         t = lex();
  490.         if (t == ',') {
  491.             id = parse_expression();
  492.             expect(']');
  493.         } else if (t == ']') {
  494.             id = group;
  495.             group = dialogID;
  496.         } else
  497.             expect(t, ']');
  498.  
  499.         dialog_string(script, group, id);
  500.     } else
  501.         fatal("expected string expression, found %s", lextokenname(t).c_str());
  502. }
  503.  
  504. int get_runtime_op_mode(int op) {
  505.     switch(op) {
  506.     case kBCE_OpNegate:        return 0x501;
  507.     case kBCE_OpNot:        return 0x501;
  508.     case kBCE_OpMul:        return 0x400;
  509.     case kBCE_OpDiv:        return 0x400;
  510.     case kBCE_OpAdd:        return 0x300;
  511.     case kBCE_OpSub:        return 0x300;
  512.     case kBCE_OpEQ:            return 0x200;
  513.     case kBCE_OpNE:            return 0x200;
  514.     case kBCE_OpLT:            return 0x200;
  515.     case kBCE_OpLE:            return 0x200;
  516.     case kBCE_OpGT:            return 0x200;
  517.     case kBCE_OpGE:            return 0x200;
  518.     case kBCE_OpLogicalAnd:    return 0x100;
  519.     case kBCE_OpLogicalOr:    return 0x100;
  520.     default:
  521.         return 0;
  522.     }
  523. }
  524.  
  525. typedef vdfastvector<unsigned char> tREBytecode;
  526.  
  527. void emit_runtime_int(tREBytecode& bytecode, int n) {
  528.     if (!n)
  529.         bytecode.push_back(kBCE_Zero);
  530.     else if (n == 1)
  531.         bytecode.push_back(kBCE_One);
  532.     else if ((signed char)n == n) {
  533.         bytecode.push_back(kBCE_Int8);
  534.         bytecode.push_back((unsigned char)n);
  535.     } else {
  536.         bytecode.push_back(kBCE_Int32);
  537.         bytecode.push_back((unsigned char)(n    ));
  538.         bytecode.push_back((unsigned char)(n>> 8));
  539.         bytecode.push_back((unsigned char)(n>>16));
  540.         bytecode.push_back((unsigned char)(n>>24));
  541.     }
  542. }
  543.  
  544. void parse_runtime_expression(tREBytecode& bytecode) {
  545.     std::vector<int> ops;
  546.     std::vector<sint32> winrefs;
  547.     bool expect_value = true;
  548.     int parens = 0;
  549.     int t;
  550.  
  551.     for(;;) {
  552.         t = lex();
  553.  
  554.         if (expect_value) {
  555.             switch(t) {
  556.             case '(':
  557.                 ++parens;
  558.                 break;
  559.             case '@':
  560.                 {
  561.                     int id = parse_prefix_expression();
  562.  
  563.                     std::vector<int>::const_iterator it(std::find(winrefs.begin(), winrefs.end(), id));
  564.                     bytecode.push_back(kBCE_GetValue);
  565.                     bytecode.push_back(it - winrefs.begin());
  566.                     if (it == winrefs.end()) {
  567.                         winrefs.push_back(id);
  568.                         if (winrefs.size() > 255)
  569.                             fatal("too many window references in runtime expression");
  570.                     }
  571.                 }
  572.                 expect_value = false;
  573.                 break;
  574.             case kTokenInteger:
  575.                 emit_runtime_int(bytecode, lexint());
  576.                 expect_value = false;
  577.                 break;
  578.             case '-':
  579.                 ops.push_back(kBCE_OpNegate + (parens<<16));
  580.                 break;
  581.             case '!':
  582.                 ops.push_back(kBCE_OpNot + (parens<<16));
  583.                 break;
  584.             default:
  585.                 unexpected(t, "value");
  586.                 break;
  587.             }
  588.         } else {
  589.             if (t == ')' && parens) {
  590.                 --parens;
  591.  
  592.                 while(!ops.empty() && (ops.back() >> 16) > parens) {
  593.                     bytecode.push_back(ops.back() & 0xffff);
  594.                     ops.pop_back();
  595.                 }
  596.                 continue;
  597.             }
  598.  
  599.             int rop = 0;
  600.             switch(t) {
  601.             case '+':        rop = kBCE_OpAdd; break;
  602.             case '-':        rop = kBCE_OpSub; break;
  603.             case '*':        rop = kBCE_OpMul; break;
  604.             case '/':        rop = kBCE_OpDiv; break;
  605.             case kTokenEQ:    rop = kBCE_OpEQ; break;
  606.             case kTokenNE:    rop = kBCE_OpNE; break;
  607.             case '<':        rop = kBCE_OpLT; break;
  608.             case kTokenLE:    rop = kBCE_OpLE; break;
  609.             case '>':        rop = kBCE_OpGT; break;
  610.             case kTokenGE:    rop = kBCE_OpGE; break;
  611.             case kTokenLogicalAnd:    rop = kBCE_OpLogicalAnd; break;
  612.             case kTokenLogicalOr:    rop = kBCE_OpLogicalOr; break;
  613.             }
  614.  
  615.             int opprec = get_runtime_op_mode(rop) + (parens<<16);
  616.  
  617.             while(!ops.empty()) {
  618.                 int stackop = ops.back();
  619.  
  620.                 if (opprec > get_runtime_op_mode(stackop&0xffff) + (stackop&~0xffff))
  621.                     break;
  622.  
  623.                 bytecode.push_back(stackop & 0xffff);
  624.                 ops.pop_back();
  625.             }
  626.  
  627.             if (!rop)
  628.                 break;
  629.  
  630.             ops.push_back(rop + (parens<<16));
  631.             expect_value = true;
  632.         }
  633.     }
  634.  
  635.     if (parens)
  636.         unexpected(t, "operator");
  637.  
  638.     lexpush(t);
  639.  
  640.     if (bytecode.size() > 65534)
  641.         fatal("runtime expression too complex");
  642.  
  643.     // too lazy to do this correctly
  644.     const unsigned bytes = bytecode.size();
  645.     const uint8 sizehdr[2]={ (uint8)bytes, (uint8)(bytes >> 8) };
  646.  
  647.     bytecode.insert(bytecode.begin(), sizehdr, sizehdr+2);
  648.     bytecode.insert(bytecode.begin(), (const unsigned char *)&winrefs[0], (const unsigned char *)&winrefs[0] + winrefs.size()*sizeof(winrefs[0]));
  649.     bytecode.insert(bytecode.begin(), (uint8)winrefs.size());
  650.  
  651.     bytecode.push_back(0);
  652. }
  653.  
  654. void parse_runtime_expressions(tREBytecode& bytecode) {
  655.     int expressions = 0;
  656.  
  657.     expect('{');
  658.  
  659.     for(;;) {
  660.         parse_runtime_expression(bytecode);
  661.         ++expressions;
  662.         int t = lex();
  663.         if (t != ',') {
  664.             lexpush(t);
  665.             break;
  666.         }
  667.     }
  668.  
  669.     expect('}');
  670.  
  671.     if (expressions > 255)
  672.         fatal("too many link expressions (max 255)");
  673.  
  674.     bytecode.insert(bytecode.begin(), expressions);
  675. }
  676.  
  677. void parse_parameterB(uint32 propid, tDialogScript& script) {
  678.     dialog_int(script, propid);
  679.     dialog_int(script, 1);
  680.     script.push_back(kBC_SetParameterB);
  681. }
  682.  
  683. void parse_parameterI(uint32 propid, tDialogScript& script) {
  684.     expect('=');
  685.     dialog_int(script, propid);
  686.     dialog_int(script, parse_expression());
  687.     script.push_back(kBC_SetParameterI);
  688. }
  689.  
  690. void parse_parameterF(uint32 propid, tDialogScript& script) {
  691.     expect('=');
  692.     dialog_int(script, propid);
  693.     union { float v; int i; } conv = {parse_expression() / 100.0f};
  694.     script.push_back(kBC_Float32);
  695.     script.push_back( conv.i       & 0xff);
  696.     script.push_back((conv.i >>  8) & 0xff);
  697.     script.push_back((conv.i >> 16) & 0xff);
  698.     script.push_back((conv.i >> 24) & 0xff);
  699.     script.push_back(kBC_SetParameterF);
  700. }
  701.  
  702. void parse_parameters(tDialogScript& script) {
  703.     for(;;) {
  704.         int t = lex();
  705.  
  706.         switch(t) {
  707.         case kTokenMarginL:        parse_parameterI(kUIParam_MarginL, script);    break;
  708.         case kTokenMarginT:        parse_parameterI(kUIParam_MarginT, script);    break;
  709.         case kTokenMarginR:        parse_parameterI(kUIParam_MarginR, script);    break;
  710.         case kTokenMarginB:        parse_parameterI(kUIParam_MarginB, script);    break;
  711.         case kTokenPadL:        parse_parameterI(kUIParam_PadL, script);    break;
  712.         case kTokenPadT:        parse_parameterI(kUIParam_PadT, script);    break;
  713.         case kTokenPadR:        parse_parameterI(kUIParam_PadR, script);    break;
  714.         case kTokenPadB:        parse_parameterI(kUIParam_PadB, script);    break;
  715.         case kTokenMinW:        parse_parameterI(kUIParam_MinW, script);    break;
  716.         case kTokenMinH:        parse_parameterI(kUIParam_MinH, script);    break;
  717.         case kTokenMaxW:        parse_parameterI(kUIParam_MaxW, script);    break;
  718.         case kTokenMaxH:        parse_parameterI(kUIParam_MaxH, script);    break;
  719.         case kTokenAlign:        parse_parameterI(kUIParam_Align, script);    break;
  720.         case kTokenVAlign:        parse_parameterI(kUIParam_VAlign, script);    break;
  721.         case kTokenSpacing:        parse_parameterI(kUIParam_Spacing, script);    break;
  722.         case kTokenAffinity:    parse_parameterI(kUIParam_Affinity, script);    break;
  723.         case kTokenAspect:        parse_parameterF(kUIParam_Aspect, script);    break;
  724.  
  725.         case kTokenRow:            parse_parameterI(kUIParam_Row, script);    break;
  726.         case kTokenColumn:        parse_parameterI(kUIParam_Col, script);    break;
  727.         case kTokenRowSpan:        parse_parameterI(kUIParam_RowSpan, script);    break;
  728.         case kTokenColSpan:        parse_parameterI(kUIParam_ColSpan, script);    break;
  729.  
  730.         case kTokenFill:
  731.             dialog_int(script, kUIParam_Align);
  732.             dialog_int(script, nsVDUI::kFill);
  733.             script.push_back(kBC_SetParameterI);
  734.             dialog_int(script, kUIParam_VAlign);
  735.             dialog_int(script, nsVDUI::kFill);
  736.             script.push_back(kBC_SetParameterI);
  737.             break;
  738.         case kTokenVertical:    parse_parameterB(kUIParam_IsVertical, script); break;
  739.         case kTokenRaised:        parse_parameterB(kUIParam_Raised, script); break;
  740.         case kTokenSunken:        parse_parameterB(kUIParam_Sunken, script); break;
  741.         case kTokenChild:        parse_parameterB(kUIParam_Child, script); break;
  742.         case kTokenMultiline:    parse_parameterB(kUIParam_Multiline, script); break;
  743.         case kTokenReadonly:    parse_parameterB(kUIParam_Readonly, script); break;
  744.         case kTokenCheckable:    parse_parameterB(kUIParam_Checkable, script); break;
  745.         case kTokenNoHeader:    parse_parameterB(kUIParam_NoHeader, script); break;
  746.         case kTokenDefault:        parse_parameterB(kUIParam_Default, script); break;
  747.  
  748.         case kTokenEnable:
  749.         case kTokenValue:
  750.             {
  751.                 expect('=');
  752.  
  753.                 tREBytecode bytecode;
  754.                 parse_runtime_expressions(bytecode);
  755.  
  756.                 if (bytecode.size() >= 65536)
  757.                     fatal("runtime expression too complex");
  758.  
  759.                 script.push_back(kBC_SetLinkExpr);
  760.                 script.push_back(bytecode.size() & 255);
  761.                 script.push_back(bytecode.size() >> 8);
  762.  
  763.                 script.insert(script.end(), bytecode.begin(), bytecode.end());
  764.  
  765.                 dialog_int(script, t == kTokenEnable ? kUIParam_EnableLinkExpr : kUIParam_ValueLinkExpr);
  766.                 dialog_int(script, g_enableExprs++);
  767.                 script.push_back(kBC_SetParameterI);
  768.             }
  769.             break;
  770.  
  771.         default:
  772.             fatal("expected parameter name, found %s", lextokenname(t).c_str());
  773.         }
  774.  
  775.         t = lex();
  776.         if (t != ',') {
  777.             lexpush(t);
  778.             break;
  779.         }
  780.     }
  781. }
  782.  
  783. bool parse_optional_parameters(tDialogScript& script, bool autoscope) {
  784.     int t = lex();
  785.  
  786.     if (t == ':') {
  787.         if (autoscope)
  788.             script.push_back(kBC_PushParameters);
  789.         parse_parameters(script);
  790.         return true;
  791.     }
  792.  
  793.     lexpush(t);
  794.     return false;
  795. }
  796.  
  797. void parse_dialog_common(int dlgID, tDialogScript& script, int t);
  798.  
  799. void parse_dialog_control(int dlgID, tDialogScript& script, unsigned char create_bc) {
  800.     int t = lex();
  801.  
  802.     if (create_bc == kBC_CreateChildDialog) {
  803.         lexpush(t);
  804.         dialog_int(script, parse_expression());
  805.         expect(',');
  806.         dialog_int(script, parse_expression());
  807.         bool popparms = parse_optional_parameters(script, true);
  808.         script.push_back(create_bc);
  809.         if (popparms)
  810.             script.push_back(kBC_PopParameters);
  811.  
  812.         t = lex();
  813.     } else if (create_bc == kBC_CreateCustom) {        // customWindow id, clsid [,caption] [: parms...]
  814.         lexpush(t);
  815.         dialog_int(script, parse_expression());
  816.         expect(',');
  817.         dialog_int(script, parse_expression());
  818.         t = lex();
  819.         if (t == ',') {
  820.             parse_dialog_string(dlgID, script);
  821.         } else {
  822.             script.push_back(kBC_StringNull);
  823.             lexpush(t);
  824.         }
  825.         bool popparms = parse_optional_parameters(script, true);
  826.         script.push_back(create_bc);
  827.         if (popparms)
  828.             script.push_back(kBC_PopParameters);
  829.  
  830.         t = lex();
  831.     } else if (t == '{') {
  832.         dialog_int(script, 0);
  833.         script.push_back(kBC_StringNull);
  834.     } else {
  835.         lexpush(t);
  836.         dialog_int(script, parse_expression());
  837.         t = lex();
  838.         if (t == ',') {
  839.             parse_dialog_string(dlgID, script);
  840.         } else {
  841.             script.push_back(kBC_StringNull);
  842.             lexpush(t);
  843.         }
  844.         bool popparms = parse_optional_parameters(script, true);
  845.         script.push_back(create_bc);
  846.         if (popparms)
  847.             script.push_back(kBC_PopParameters);
  848.  
  849.         t = lex();
  850.     }
  851.  
  852.     if (t == '{') {
  853.         script.push_back(kBC_BeginChildren);
  854.         script.push_back(kBC_PushParameters);
  855.         for(;;) {
  856.             t = lex();
  857.             if (t == '}')
  858.                 break;
  859.  
  860.             parse_dialog_common(dlgID, script, t);
  861.         }
  862.         script.push_back(kBC_PopParameters);
  863.         script.push_back(kBC_EndChildren);
  864.     } else {
  865.         lexpush(t);
  866.         expect(';');
  867.     }
  868. }
  869.  
  870. void parse_dialog_item(int dlgID, tDialogScript& script, unsigned char create_bc) {
  871.     int t = lex();
  872.  
  873.     lexpush(t);
  874.     dialog_int(script, parse_expression());
  875.  
  876.     bool popparms = parse_optional_parameters(script, true);
  877.     script.push_back(create_bc);
  878.     if (popparms)
  879.         script.push_back(kBC_PopParameters);
  880.  
  881.     expect(';');
  882. }
  883.  
  884. void parse_dialog_common(int dlgID, tDialogScript& script, int t) {
  885.  
  886.     switch(t) {
  887.     case kTokenLabel:
  888.         parse_dialog_control(dlgID, script, kBC_CreateLabel);
  889.         break;
  890.     case kTokenEdit:
  891.         parse_dialog_control(dlgID, script, kBC_CreateEdit);
  892.         break;
  893.     case kTokenButton:
  894.         parse_dialog_control(dlgID, script, kBC_CreateButton);
  895.         break;
  896.     case kTokenCheckBox:
  897.         parse_dialog_control(dlgID, script, kBC_CreateCheckBox);
  898.         break;
  899.     case kTokenListBox:
  900.         parse_dialog_control(dlgID, script, kBC_CreateListBox);
  901.         break;
  902.     case kTokenComboBox:
  903.         parse_dialog_control(dlgID, script, kBC_CreateComboBox);
  904.         break;
  905.     case kTokenListView:
  906.         parse_dialog_control(dlgID, script, kBC_CreateListView);
  907.         break;
  908.     case kTokenTrackbar:
  909.         parse_dialog_control(dlgID, script, kBC_CreateTrackbar);
  910.         break;
  911.     case kTokenOption:
  912.         parse_dialog_control(dlgID, script, kBC_CreateOption);
  913.         break;
  914.     case kTokenSplitter:
  915.         parse_dialog_control(dlgID, script, kBC_CreateSplitter);
  916.         break;
  917.     case kTokenSet:
  918.         parse_dialog_control(dlgID, script, kBC_CreateSet);
  919.         break;
  920.     case kTokenPageSet:
  921.         parse_dialog_control(dlgID, script, kBC_CreatePageSet);
  922.         break;
  923.     case kTokenGrid:
  924.         parse_dialog_control(dlgID, script, kBC_CreateGrid);
  925.         break;
  926.     case kTokenTextEdit:
  927.         parse_dialog_control(dlgID, script, kBC_CreateTextEdit);
  928.         break;
  929.     case kTokenTextArea:
  930.         parse_dialog_control(dlgID, script, kBC_CreateTextArea);
  931.         break;
  932.     case kTokenGroup:
  933.         parse_dialog_control(dlgID, script, kBC_CreateGroup);
  934.         break;
  935.     case kTokenDialog:
  936.         parse_dialog_control(dlgID, script, kBC_CreateChildDialog);
  937.         break;
  938.     case kTokenHotkey:
  939.         parse_dialog_control(dlgID, script, kBC_CreateHotkey);
  940.         break;
  941.     case kTokenCustomWindow:
  942.         parse_dialog_control(dlgID, script, kBC_CreateCustom);
  943.         break;
  944.  
  945.     case kTokenListItem:
  946.         parse_dialog_string(dlgID, script);
  947.         script.push_back(kBC_AddListItem);
  948.         expect(';');
  949.         break;
  950.  
  951.     case kTokenPage:
  952.         dialog_int(script, parse_expression());
  953.         script.push_back(kBC_AddPage);
  954.         expect(';');
  955.         break;
  956.  
  957.     case kTokenNow:
  958.         parse_parameters(script);
  959.         expect(';');
  960.         break;
  961.  
  962.     case kTokenUsing:
  963.         script.push_back(kBC_PushParameters);
  964.         parse_parameters(script);
  965.         expect('{');
  966.         for(;;) {
  967.             t = lex();
  968.             if (t < 0)
  969.                 fatal("unterminated using block");
  970.             if (t == '}')
  971.                 break;
  972.             parse_dialog_common(dlgID, script, t);
  973.         }
  974.         script.push_back(kBC_PopParameters);
  975.         break;
  976.  
  977.     case kTokenInclude:
  978.         t = lex();
  979.         if (t == kTokenTemplate) {
  980.             int v = parse_expression();
  981.  
  982.             tTemplateList::iterator it = g_templates.find(v);
  983.  
  984.             if (it == g_templates.end())
  985.                 fatal("Template '%d' not defined", v);
  986.  
  987.             script.push_back(kBC_InvokeTemplate);
  988.             script.push_back(v & 0xff);
  989.             script.push_back((v>>8) & 0xff);
  990.             break;
  991.         }
  992.         lexpush(t);
  993.         parse_common(kTokenInclude);
  994.         break;
  995.  
  996.     case kTokenColumn:
  997.         parse_dialog_item(dlgID, script, kBC_SetColumn);
  998.         break;
  999.  
  1000.     case kTokenRow:
  1001.         parse_dialog_item(dlgID, script, kBC_SetRow);
  1002.         break;
  1003.  
  1004.     case kTokenNextRow:
  1005.         script.push_back(kBC_NextRow);
  1006.         break;
  1007.  
  1008.     default:
  1009.         parse_common(t);
  1010.     }
  1011. }
  1012.  
  1013. void parse_template() {
  1014.     int t = lex();
  1015.     bool bAllowOverride = false;
  1016.  
  1017.     if (t == kTokenOverride)
  1018.         bAllowOverride = true;
  1019.     else
  1020.         lexpush(t);
  1021.  
  1022.     int tmplID = parse_expression();
  1023.  
  1024.     if (tmplID < 0 || tmplID > 65535)
  1025.         fatal("Template ID '%d' is not within 0 to 65535", tmplID);
  1026.  
  1027.     if (g_templates.find(tmplID) != g_templates.end()) {
  1028.         if (!bAllowOverride)
  1029.             fatal("Dialog template '%d' has already been defined (use 'override' if intentional)", tmplID);
  1030.  
  1031.         g_templates[tmplID].clear();
  1032.     }
  1033.  
  1034.     tDialogScript& script = g_templates[tmplID];
  1035.  
  1036.     g_enableExprs = 0;
  1037.  
  1038.     expect('{');
  1039.     parse_push_scope();
  1040.  
  1041.     for(;;) {
  1042.         t = lex();
  1043.  
  1044.         if (t < 0)
  1045.             fatal("Unterminated template declaration");
  1046.  
  1047.         switch(t) {
  1048.         case '}':
  1049.             parse_pop_scope();
  1050.             script.push_back(0);
  1051.             return;
  1052.  
  1053.         default:
  1054.             parse_dialog_common(tmplID, script,t);
  1055.         }
  1056.     }
  1057. }
  1058.  
  1059. void parse_dialog() {
  1060.     int t = lex();
  1061.     bool bAllowOverride = false;
  1062.  
  1063.     if (t == kTokenOverride)
  1064.         bAllowOverride = true;
  1065.     else
  1066.         lexpush(t);
  1067.  
  1068.     expect(kTokenInteger);
  1069.     int dialogID = lexint();
  1070.  
  1071.     if (dialogID < 0 || dialogID > 65535)
  1072.         fatal("Dialog ID '%d' is not between 0 and 65535", dialogID);
  1073.  
  1074.     if (g_dialogs.find(dialogID) != g_dialogs.end()) {
  1075.         if (!bAllowOverride)
  1076.             fatal("Dialog ID '%d' has already been defined (use 'override' if intentional)", dialogID);
  1077.  
  1078.         g_dialogs[dialogID].clear();
  1079.     }
  1080.  
  1081.     tDialogScript& script = g_dialogs[dialogID];
  1082.  
  1083.     g_enableExprs = 0;
  1084.  
  1085.     expect(',');
  1086.     dialog_int(script, dialogID);
  1087.     parse_dialog_string(dialogID, script);
  1088.  
  1089.     bool autoscoped = parse_optional_parameters(script, true);
  1090.     script.push_back(kBC_CreateDialog);
  1091.     if (autoscoped)
  1092.         script.push_back(kBC_PopParameters);
  1093.  
  1094.     script.push_back(kBC_BeginChildren);
  1095.  
  1096.     expect('{');
  1097.     parse_push_scope();
  1098.  
  1099.     for(;;) {
  1100.         t = lex();
  1101.  
  1102.         if (t < 0)
  1103.             fatal("Unterminated dialog declaration");
  1104.  
  1105.         switch(t) {
  1106.         case '}':
  1107.             parse_pop_scope();
  1108.             script.push_back(kBC_EndChildren);
  1109.             script.push_back(kBC_End);
  1110.             return;
  1111.  
  1112.         default:
  1113.             parse_dialog_common(dialogID, script,t);
  1114.         }
  1115.     }
  1116. }
  1117.  
  1118. void parse() {
  1119.  
  1120.     parse_push_scope();
  1121.  
  1122.     for(;;) {
  1123.         int t = lex();
  1124.  
  1125.         if (t < 0)
  1126.             break;
  1127.  
  1128.         switch(t) {
  1129.         case kTokenStringSet:
  1130.             parse_stringSet();
  1131.             break;
  1132.  
  1133.         case kTokenDialog:
  1134.             parse_dialog();
  1135.             break;
  1136.  
  1137.         case kTokenTemplate:
  1138.             parse_template();
  1139.             break;
  1140.  
  1141.         case kTokenInclude:
  1142.             {
  1143.                 expect(kTokenString);
  1144.                 std::string filename(ANSIify(lexident()));
  1145.                 expect(';');
  1146.  
  1147.                 lexinclude(filename);
  1148.             }
  1149.             break;
  1150.  
  1151.         default:
  1152.             parse_common(t);
  1153.         }
  1154.     }
  1155.  
  1156.     parse_pop_scope();
  1157.  
  1158.     if (!g_scopes.empty())
  1159.         fatal_internal(__FILE__, __LINE__);
  1160. }
  1161.  
  1162. ///////////////////////////////////////////////////////////////////////////
  1163. //
  1164. //    writeout
  1165. //
  1166. ///////////////////////////////////////////////////////////////////////////
  1167.  
  1168. typedef unsigned Fourcc;
  1169.  
  1170. #define MAKE_FCC(a,b,c,d) (((unsigned char)(d) << 24) + ((unsigned char)(c) << 16) + ((unsigned char)(b) << 8) + (unsigned char)(a))
  1171.  
  1172. enum {
  1173.     kFourcc_StringSets        = MAKE_FCC('S','T','R','S'),
  1174.     kFourcc_Dialogs            = MAKE_FCC('D','L','G','S'),
  1175.     kFourcc_Templates        = MAKE_FCC('D','T','P','S')
  1176. };
  1177.  
  1178. typedef std::list<long> tFileScopeList;
  1179.  
  1180. tFileScopeList g_fileScopes;
  1181. FILE *g_fileOut;
  1182.  
  1183. void write_begin_scope(Fourcc fcc) {
  1184.     fwrite(&fcc, 4, 1, g_fileOut);
  1185.     fwrite(&fcc, 4, 1, g_fileOut);    // reserve space for size
  1186.  
  1187.     g_fileScopes.push_front(ftell(g_fileOut));
  1188. }
  1189.  
  1190. void write_end_scope() {
  1191.     if (g_fileScopes.empty())
  1192.         fatal_internal(__FILE__, __LINE__);
  1193.  
  1194.     long fp = ftell(g_fileOut);
  1195.     int pad = (-fp)&3;
  1196.  
  1197.     fwrite("\0\0\0", pad, 1, g_fileOut);
  1198.     fp += pad;
  1199.  
  1200.     long fp_scope = g_fileScopes.front();
  1201.     long siz = fp - fp_scope;
  1202.  
  1203.     g_fileScopes.pop_front();
  1204.  
  1205.     fseek(g_fileOut, fp_scope-4, SEEK_SET);
  1206.     fwrite(&siz, 4, 1, g_fileOut);
  1207.     fseek(g_fileOut, fp, SEEK_SET);
  1208. }
  1209.  
  1210. void write_short(int i) {
  1211.     short s = (short)i;
  1212.  
  1213.     fwrite(&s, 2, 1, g_fileOut);
  1214. }
  1215.  
  1216. int writeout(FILE *f) {
  1217.     char header[64]="[01|01] VirtualDub language resource file\r\n\x1A";
  1218.  
  1219.     g_fileOut = f;
  1220.  
  1221.     fwrite(header, sizeof header, 1, f);
  1222.  
  1223.     // write stringsets
  1224.  
  1225.     write_begin_scope(kFourcc_StringSets);
  1226.     {
  1227.         tStringResource::iterator it = g_stringResource.begin(), itEnd = g_stringResource.end();
  1228.  
  1229.         write_short(g_stringResource.size());
  1230.  
  1231.         for(; it!=itEnd; ++it) {
  1232.             tStringSet& strset = (*it).second;
  1233.             tStringSet::iterator itStr = strset.begin(), itStrEnd = strset.end();
  1234.  
  1235.             write_short((*it).first);
  1236.             write_short(strset.size());
  1237.  
  1238.             for(; itStr != itStrEnd; ++itStr) {
  1239.                 std::wstring& wstr = (*itStr).second;
  1240.                 write_short((*itStr).first);
  1241.  
  1242.                 std::basic_string<unsigned char> scsu_encoded = ConvertToSCSU(wstr);
  1243.  
  1244.                 int s = scsu_encoded.size();
  1245.  
  1246.                 if (s <= 0x7f) {
  1247.                     putc(s, f);
  1248.                 } else if (s <= 0x3fff) {
  1249.                     putc((s>>7)|0x80, f);
  1250.                     putc((s&0x7f), f);
  1251.                 } else
  1252.                     fatal_internal(__FILE__, __LINE__);
  1253.  
  1254.                 fwrite(scsu_encoded.data(), scsu_encoded.size(), 1, f);
  1255.             }
  1256.         }
  1257.     }
  1258.     write_end_scope();
  1259.  
  1260.     // write dialogs
  1261.  
  1262.     write_begin_scope(kFourcc_Dialogs);
  1263.     {
  1264.         tDialogList::iterator it = g_dialogs.begin(), itEnd = g_dialogs.end();
  1265.  
  1266.         write_short(g_dialogs.size());
  1267.         for(; it!=itEnd; ++it) {
  1268.             tDialogScript& scr = (*it).second;
  1269.             int siz = scr.size();
  1270.             write_short((*it).first);
  1271.  
  1272.             if (siz >= 65535)
  1273.                 fatal("Dialog %d is too big (%d > 65535 bytes)", (*it).first, siz);
  1274.  
  1275.             write_short(siz);
  1276.  
  1277.             fwrite(&scr[0], siz, 1, f);
  1278.         }
  1279.     }
  1280.     write_end_scope();
  1281.  
  1282.     // write templates
  1283.  
  1284.     write_begin_scope(kFourcc_Templates);
  1285.     {
  1286.         tTemplateList::iterator it = g_templates.begin(), itEnd = g_templates.end();
  1287.  
  1288.         write_short(g_templates.size());
  1289.         for(; it!=itEnd; ++it) {
  1290.             tDialogScript& scr = (*it).second;
  1291.             int siz = scr.size();
  1292.             write_short((*it).first);
  1293.  
  1294.             if (siz >= 65535)
  1295.                 fatal("Template %d is too big (%d > 65535 bytes)", (*it).first, siz);
  1296.  
  1297.             write_short(siz);
  1298.  
  1299.             fwrite(&scr[0], siz, 1, f);
  1300.         }
  1301.     }
  1302.     write_end_scope();
  1303.  
  1304.     return ftell(f);
  1305. }
  1306.  
  1307. ///////////////////////////////////////////////////////////////////////////
  1308. //
  1309. //    main
  1310. //
  1311. ///////////////////////////////////////////////////////////////////////////
  1312.  
  1313. int main(int argc, char **argv) {
  1314.     if (argc < 3) {
  1315.         printf(
  1316.             "Ami - Language resource compiler for VirtualDub, version 1.0\n"
  1317.             "\n"
  1318.             "Usage: ami <input-file.ami> <output-file.vlr>\n"
  1319.             );
  1320.         return 5;
  1321.     }
  1322.  
  1323.     // open input file
  1324.  
  1325.     lexopen(argv[1]);
  1326.     printf("Ami: Compiling %s (%s) -> %s\n", argv[1], lexisunicode() ? "Unicode" : "ANSI", argv[2]);
  1327.  
  1328.     // process
  1329.  
  1330.     parse();
  1331.  
  1332.     FILE *f = fopen(argv[2], "wb");
  1333.  
  1334.     if (!f)
  1335.         fatal("Cannot open output file");
  1336.  
  1337.     int bytes = writeout(f);
  1338.  
  1339.     if (ferror(f) || fclose(f))
  1340.         fatal("Write error creating output file");
  1341.  
  1342.     printf("Ami: Compile successful -- %d string tables, %d bytes\n", g_stringResource.size(), bytes);
  1343.  
  1344.     return 0;
  1345. }
  1346.