home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / ltk / ltkbuild.cc < prev    next >
C/C++ Source or Header  |  1998-11-27  |  10KB  |  473 lines

  1. //========================================================================
  2. //
  3. // ltkbuild.cc
  4. //
  5. // Read an LTKbuild file from stdin and write C++ window construction
  6. // function(s) to stdout.
  7. //
  8. // Copyright 1996 Derek B. Noonburg
  9. //
  10. //========================================================================
  11.  
  12. #define VERSION "0.80"
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stddef.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include <stdarg.h>
  20. #include "gtypes.h"
  21. #include "gmem.h"
  22. #include "GString.h"
  23.  
  24. enum ArgKind {
  25.   argVal,            // arg with value
  26.   argSel,            // selection arg
  27.   argLastSel            // last in list of selections
  28. };
  29.  
  30. struct ArgDesc {
  31.   char *tag;            // tag used in ltk file
  32.   ArgKind kind;            // kind of arg
  33.   GBool required;
  34.   char *val;            // default for argVal; value for argSel
  35. };
  36.  
  37. struct BlockDesc {
  38.   char *name;            // name used in ltk file
  39.   char *type;            // corresponding C++ type
  40.   ArgDesc *args;        // list of legal args
  41. };
  42.  
  43. struct Arg {
  44.   char s[256];
  45. };
  46.  
  47. struct Block {
  48.   char *name;
  49.   char *type;
  50.   Arg *args;
  51.   int numArgs;
  52. };
  53.  
  54. #include "ltkbuild-widgets.h"
  55.  
  56. static GBool readTopLevel();
  57. static GBool readWindow(Block *block);
  58. static void readBox(int indent);
  59. static void readWidget(int indent);
  60. static GBool readMenu(Block *block);
  61. static void readMenuItem(int indent);
  62. static Block *readBlock(BlockDesc *tab, char *err);
  63. static void freeBlock(Block *block);
  64. static void initLexer();
  65. static char *getToken();
  66. static GBool skipSpace();
  67. static GBool checkToken(char *s, char *msg = NULL);
  68. static void error(char *msg, ...);
  69.  
  70. static char line[256];
  71. static char *nextChar;
  72. static int lineNum;
  73. static char tokenBuf[256];
  74. static int numErrors;
  75.  
  76. //------------------------------------------------------------------------
  77.  
  78. int main(int argc, char *argv[]) {
  79.   initLexer();
  80.   printf("// This file was generated by ltkbuild %s\n\n", VERSION);
  81.   while (readTopLevel()) ;
  82.   if (numErrors > 0)
  83.     return 1;
  84.   return 0;
  85. }
  86.  
  87. //------------------------------------------------------------------------
  88.  
  89. static GBool readTopLevel() {
  90.   Block *block;
  91.   GBool ok;
  92.  
  93.   if (!(block = readBlock(topLevelTab, "top level block")))
  94.     return gFalse;
  95.   if (!strcmp(block->type, windowType)) {
  96.     ok = readWindow(block);
  97.   } else if (!strcmp(block->type, menuType)) {
  98.     ok = readMenu(block);
  99.   } else {
  100.     error("Internal: top-level is not Window or Menu");
  101.     freeBlock(block);
  102.     ok = gFalse;
  103.   }
  104.   return ok;
  105. }
  106.  
  107. static GBool readWindow(Block *block) {
  108.   int i;
  109.  
  110.   printf("%s *%s(LTKApp *app) {\n", block->type, block->args[0].s);
  111.   printf("  return new %s(app, ", block->type);
  112.   for (i = 1; i < block->numArgs; ++i) {
  113.     printf("%s,%c", block->args[i].s,
  114.        i < block->numArgs - 1 ? ' ' : '\n');
  115.   }
  116.   freeBlock(block);
  117.  
  118.   checkToken("{");
  119.   readBox(4);
  120.   checkToken("}");
  121.   printf("\n");
  122.  
  123.   printf("  );\n");
  124.   printf("}\n\n");
  125.  
  126.   return gTrue;
  127. }
  128.  
  129. static void readBox(int indent) {
  130.   Block *block;
  131.   int x, y;
  132.   int i, j;
  133.  
  134.   if (!(block = readBlock(boxTab, "box block")))
  135.     return;
  136.   x = atoi(block->args[boxArgX].s);
  137.   y = atoi(block->args[boxArgY].s);
  138.  
  139.   printf("%*snew %s(", indent, "", block->type);
  140.   for (i = 0; i < block->numArgs; ++i) {
  141.     printf("%s,%c", block->args[i].s,
  142.        i < block->numArgs - 1 ? ' ' : '\n');
  143.   }
  144.   freeBlock(block);
  145.  
  146.   checkToken("{");
  147.   for (i = 0; i < x; ++i) {
  148.     for (j = 0; j < y; ++j) {
  149.       readWidget(indent + 2);
  150.       if (i == x-1 && j == y-1)
  151.     printf("\n");
  152.       else
  153.     printf(",\n");
  154.     }
  155.   }
  156.   checkToken("}", "wrong box size?");
  157.   printf("%*s)", indent, "");
  158. }
  159.  
  160. static void readWidget(int indent) {
  161.   Block *block;
  162.   int x, y;
  163.   int i, j;
  164.  
  165.   if (!(block = readBlock(widgetTab, "widget block")))
  166.     return;
  167.  
  168.   printf("%*snew %s(", indent, "", block->type);
  169.   for (i = 0; i < block->numArgs; ++i) {
  170.     printf("%s%s", block->args[i].s,
  171.        i < block->numArgs - 1 ? ", " : "");
  172.   }
  173.  
  174.   if (!strcmp(block->type, boxType)) {
  175.     x = atoi(block->args[boxArgX].s);
  176.     y = atoi(block->args[boxArgY].s);
  177.     printf(",\n");
  178.     checkToken("{");
  179.     for (i = 0; i < x; ++i) {
  180.       for (j = 0; j < y; ++j) {
  181.     readWidget(indent + 2);
  182.     if (i == x-1 && j == y-1)
  183.       printf("\n");
  184.     else
  185.       printf(",\n");
  186.       }
  187.     }
  188.     checkToken("}", "wrong box size?");
  189.     printf("%*s)", indent, "");
  190.   } else {
  191.     printf(")");
  192.   }
  193.   freeBlock(block);
  194. }
  195.  
  196. static GBool readMenu(Block *block) {
  197.   int n, i;
  198.  
  199.   printf("%s *%s() {\n", block->type, block->args[0].s);
  200.   printf("  return new %s(", block->type);
  201.   for (i = 1; i < block->numArgs; ++i) {
  202.     printf("%s,%c", block->args[i].s,
  203.        i < block->numArgs - 1 ? ' ' : '\n');
  204.   }
  205.   n = atoi(block->args[menuArgN].s);
  206.   freeBlock(block);
  207.  
  208.   checkToken("{");
  209.   for (i = 0; i < n; ++i) {
  210.     readMenuItem(4);
  211.     if (i < n - 1)
  212.       printf(",\n");
  213.     else
  214.       printf("\n");
  215.   }
  216.   checkToken("}", "wrong menu size?");
  217.   printf("\n");
  218.  
  219.   printf("  );\n");
  220.   printf("}\n\n");
  221.  
  222.   return gTrue;
  223. }
  224.  
  225. static void readMenuItem(int indent) {
  226.   Block *block;
  227.   int n, i;
  228.  
  229.   if (!(block = readBlock(menuItemTab, "menu item block")))
  230.     return;
  231.  
  232.   printf("%*snew %s(", indent, "", block->type);
  233.   for (i = 1; i < block->numArgs; ++i) {
  234.     printf("%s,", block->args[i].s);
  235.     if (i < block->numArgs - 1)
  236.       printf(" ");
  237.   }
  238.   n = atoi(block->args[0].s);
  239.   freeBlock(block);
  240.  
  241.   if (n > 0) {
  242.     printf("\n");
  243.     printf("%*snew %s(NULL, %d,\n", indent + 2, "", menuType, n);
  244.     checkToken("{");
  245.     for (i = 0; i < n; ++i) {
  246.       readMenuItem(indent + 4);
  247.       if (i < n - 1)
  248.     printf(",\n");
  249.       else
  250.     printf("\n");
  251.     }
  252.     checkToken("}", "wrong menu size?");
  253.     printf("%*s)\n", indent + 2, "");
  254.     printf("%*s)", indent, "");
  255.  
  256.   } else {
  257.     printf(" NULL)");
  258.   }
  259. }
  260.  
  261. static Block *readBlock(BlockDesc *tab, char *err) {
  262.   Block *block;
  263.   char *name, *tag, *val;
  264.   BlockDesc *bd;
  265.   ArgDesc *ad;
  266.   int n;
  267.   GBool isVal;
  268.  
  269.   // get name and find block descriptor
  270.   if (!(name = getToken()))
  271.     return NULL;
  272.   for (bd = tab; bd->name; ++bd) {
  273.     if (!strcmp(name, bd->name))
  274.       break;
  275.   }
  276.   if (!bd->name) {
  277.     error("Expected %s, got '%s'", err, name);
  278.     return NULL;
  279.   }
  280.  
  281.   // skip paren
  282.   checkToken("(");
  283.  
  284.   // allocate block
  285.   block = (Block *)gmalloc(sizeof(Block));
  286.   block->name = bd->name;
  287.   block->type = bd->type;
  288.  
  289.   // count args and allocate array
  290.   block->numArgs = 0;
  291.   for (ad = bd->args; ad->tag; ++ad) {
  292.     if (ad->kind == argVal || ad->kind == argLastSel)
  293.       ++block->numArgs;
  294.   }
  295.   block->args = (Arg *)gmalloc(block->numArgs * sizeof(Arg));
  296.  
  297.   // initialize args to defaults
  298.   n = 0;
  299.   isVal = gTrue;
  300.   for (ad = bd->args; ad->tag; ++ad) {
  301.     if (ad->kind == argVal) {
  302.       strcpy(block->args[n++].s, ad->val);
  303.       isVal = gTrue;
  304.     } else if (isVal && ad->kind == argSel) {
  305.       strcpy(block->args[n++].s, ad->val);
  306.       isVal = gFalse;
  307.     } else if (ad->kind == argLastSel) {
  308.       isVal = gTrue;
  309.     }
  310.   }
  311.  
  312.   // read args
  313.   while (1) {
  314.     if (!(tag = getToken()))
  315.       break;
  316.     if (!strcmp(tag, ")"))
  317.       break;
  318.     n = strlen(tag);
  319.     if (tag[n-1] == ':') {
  320.       tag[n-1] = '\0';
  321.       isVal = gTrue;
  322.     } else {
  323.       isVal = gFalse;
  324.     }
  325.     n = 0;
  326.     for (ad = bd->args; ad->tag; ++ad) {
  327.       if (!strcmp(ad->tag, tag))
  328.     break;
  329.       if (ad->kind == argVal || ad->kind == argLastSel)
  330.     ++n;
  331.     }
  332.     if (ad->tag) {
  333.       if (isVal) {
  334.     val = getToken();
  335.     if (ad->kind != argVal)
  336.       error("Tag '%s' in '%s' block is not a value tag", tag, block->name);
  337.       } else {
  338.     val = ad->val;
  339.     if (ad->kind == argVal)
  340.       error("Tag '%s' in '%s' block is a value tag", tag, block->name);
  341.       }
  342.       strcpy(block->args[n].s, val);
  343.     } else {
  344.       error("Unknown tag '%s' in '%s' block", tag, block->name);
  345.       if (isVal)
  346.     getToken();
  347.     }
  348.   }
  349.   if (!tag)
  350.     error("Unclosed '%s' block", block->name);
  351.  
  352.   return block;
  353. }
  354.  
  355. static void freeBlock(Block *block) {
  356.   gfree(block->args);
  357.   gfree(block);
  358. }
  359.  
  360. //------------------------------------------------------------------------
  361.  
  362. static void initLexer() {
  363.   line[0] = '\0';
  364.   nextChar = line;
  365.   lineNum = 0;
  366.   numErrors = 0;
  367. }
  368.  
  369. static char *getToken() {
  370.   char *p;
  371.   int numBrackets;
  372.  
  373.   if (!skipSpace())
  374.     return NULL;
  375.  
  376.   p = tokenBuf;
  377.  
  378.   if (*nextChar == '(' || *nextChar == ')' ||
  379.       *nextChar == '{' || *nextChar == '}') {
  380.     *p++ = *nextChar++;
  381.     *p = '\0';
  382.  
  383.   } else if (*nextChar == '"') {
  384.     *p++ = *nextChar;
  385.     do {
  386.       ++nextChar;
  387.       if (!*nextChar)
  388.     break;
  389.       *p++ = *nextChar;
  390.     } while (!(*nextChar == '"' && nextChar[-1] != '\\'));
  391.     *p = '\0';
  392.     if (*nextChar == '"')
  393.       ++nextChar;
  394.     else
  395.       error("Unclosed quoted string");
  396.  
  397.   } else if (*nextChar == '[') {
  398.     numBrackets = 1;
  399.     while (1) {
  400.       ++nextChar;
  401.       if (!*nextChar)
  402.     break;
  403.       if (*nextChar == '[' && nextChar[-1] != '\\')
  404.     ++numBrackets;
  405.       else if (*nextChar == ']' && nextChar[-1] != '\\')
  406.     --numBrackets;
  407.       if (numBrackets == 0)
  408.     break;
  409.       *p++ = *nextChar;
  410.     }
  411.     *p = '\0';
  412.     if (*nextChar == ']')
  413.       ++nextChar;
  414.     else
  415.       error("Unclosed bracketed expression");
  416.  
  417.   } else {
  418.     while (!isspace(*nextChar) &&
  419.        *nextChar != '(' && *nextChar != ')' &&
  420.        *nextChar != '{' && *nextChar != '}' &&
  421.        *nextChar != ':' && *nextChar)
  422.       *p++ = *nextChar++;
  423.     if (*nextChar == ':')
  424.       *p++ = *nextChar++;
  425.     *p = '\0';
  426.   }
  427.  
  428.   return tokenBuf;
  429. }
  430.  
  431. static GBool skipSpace() {
  432.   while (1) {
  433.     if (!*nextChar || *nextChar == '#') {
  434.       if (!fgets(line, sizeof(line), stdin)) {
  435.     line[0] = '\0';
  436.     nextChar = line;
  437.     return gFalse;
  438.       }
  439.       ++lineNum;
  440.       nextChar = line;
  441.     } else if (isspace(*nextChar)) {
  442.       ++nextChar;
  443.     } else {
  444.       break;
  445.     }
  446.   }
  447.   return gTrue;
  448. }
  449.  
  450. static GBool checkToken(char *s, char *msg) {
  451.   char *tok;
  452.  
  453.   tok = getToken();
  454.   if (tok && !strcmp(tok, s))
  455.     return gTrue;
  456.   if (msg)
  457.     error("Expected '%s', got '%s' (%s)", s, tok, msg);
  458.   else
  459.     error("Expected '%s', got '%s'", s, tok);
  460.   return gFalse;
  461. }
  462.  
  463. static void error(char *msg, ...) {
  464.   va_list args;
  465.  
  466.   fprintf(stderr, "Error at line %d: ", lineNum);
  467.   va_start(args, msg);
  468.   vfprintf(stderr, msg, args);
  469.   va_end(args);
  470.   fprintf(stderr, "\n");
  471.   ++numErrors;
  472. }
  473.