home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / OS2 / DB02_SRC.ZIP / DSC.Y < prev    next >
Text File  |  1994-02-22  |  32KB  |  1,354 lines

  1. %{
  2. #define VERSION_NUMBER "0.1a"
  3.  
  4. /**************************************************************************
  5.  * Source Id :
  6.  *
  7.  * $Id: dsc.y,v 1.40 1993/11/03 10:04:46 kevinl Exp $
  8.  *-------------------------------------------------------------------------
  9.  * Project Notes :
  10.  *
  11.  *  Diamond Base
  12.  *  ============
  13.  *    A solid database implementation, spurred on by the continuing
  14.  *  Metal (Lead) Base saga.
  15.  *
  16.  *  Project Team :
  17.  *      A. Davison
  18.  *      K. Lentin
  19.  *      D. Platt
  20.  *
  21.  *    Project Commenced : 05-02-1993
  22.  *
  23.  *-------------------------------------------------------------------------
  24.  *  Module Notes :
  25.  *
  26.  *        Diamond Base Relation Compiler.
  27.  *
  28.  *            This creates the relation structure definitions and initialises
  29.  *    the database for that relation.
  30.  *
  31.  *  Original Author : Andy
  32.  *
  33.  *-------------------------------------------------------------------------
  34.  * Revision History:
  35.  *
  36.  * $Log: dsc.y,v $
  37.  * Revision 1.40  1993/11/03  10:04:46    kevinl
  38.  * Added ichar and utils.{h,cc}
  39.  *
  40.  * Revision 1.39  1993/11/02  03:41:35    davison
  41.  * Fixed clear() reference.
  42.  *
  43.  * Revision 1.38  1993/10/25  08:07:10    kevinl
  44.  * Let's try dbString constructors
  45.  *
  46.  * Revision 1.37  1993/10/24  15:35:24    kevinl
  47.  * Reveresed command line arguments
  48.  * Added -g
  49.  *
  50.  * Revision 1.36  1993/10/19  14:27:37    kevinl
  51.  * Fixed constructors/retrievers
  52.  *
  53.  * Revision 1.35  1993/10/19  11:50:27    kevinl
  54.  * Assignment/default values/constructors
  55.  *
  56.  * Revision 1.34  1993/10/19  08:27:23    davison
  57.  * Added assign token
  58.  *
  59.  * Revision 1.33  1993/10/18  08:01:41    kevinl
  60.  * Added constructors and fixed some probs
  61.  *
  62.  * Revision 1.32  1993/10/10  03:05:23    davison
  63.  * Added grammar prototypes for relational links
  64.  *
  65.  * Revision 1.31  1993/10/10  01:48:16    kevinl
  66.  * Fixed record length bug
  67.  *
  68.  * Revision 1.30  1993/09/26  06:40:32    kevinl
  69.  * Added dbData support
  70.  *
  71.  * Revision 1.29  1993/07/11  09:42:05    kevinl
  72.  * Changed String to dbString
  73.  *
  74.  * Revision 1.28  1993/06/23  05:21:22    kevinl
  75.  * Mallocs are now in angular brackets
  76.  *
  77.  * Revision 1.27  1993/06/20  13:43:57    kevinl
  78.  * Added some filename length/extension limitation support
  79.  * Added String support
  80.  *
  81.  * Revision 1.26  1993/05/26  00:59:16    kevinl
  82.  * moved 'delete output' to prevent file contention
  83.  * Fixed output of ULONG (although code is no longer used)
  84.  *
  85.  * Revision 1.25  1993/05/07  13:54:35    kevinl
  86.  * Added outputFieldList so fields were in correct order for alignment
  87.  *
  88.  * Revision 1.24  1993/05/03  01:35:24    kevinl
  89.  * Comparing chars to 0 now, not -1
  90.  *
  91.  * Revision 1.23  1993/04/28  11:31:40    kevinl
  92.  * Fixed up .ds extension
  93.  *
  94.  * Revision 1.22  1993/04/27  07:06:47    kevinl
  95.  * Removed some dead code
  96.  * Changed a static array to a new
  97.  * Comments
  98.  *
  99.  * Revision 1.21  1993/04/15  07:59:12    kevinl
  100.  * Removed malloc include
  101.  * Set ind btree to open, not closed
  102.  *
  103.  * Revision 1.20  1993/04/15  04:21:30    kevinl
  104.  * Added an extra delete output
  105.  * Moved malloc.h
  106.  *
  107.  * Revision 1.19  1993/04/01  05:39:59    kevinl
  108.  * Fixed filename stripping
  109.  * Fixed unused ind bTree
  110.  *
  111.  * Revision 1.18  1993/04/01  01:35:41    davison
  112.  * Updated usage() reporting.
  113.  *
  114.  * Revision 1.17  1993/04/01  00:52:02    davison
  115.  * A little more work on the error stuff finished.
  116.  *
  117.  * Revision 1.15  1993/03/30  10:04:55    davison
  118.  * Fixed the makeSource conditions.
  119.  *
  120.  * Revision 1.14  1993/03/30  07:56:27    davison
  121.  * Added -C option (generate source code only)
  122.  *     -D option (generate databases only)
  123.  *     -C -D option (parse only - no output)
  124.  *
  125.  * Revision 1.13  1993/03/30  06:52:48    kevinl
  126.  * Only one unique field allowed
  127.  *
  128.  * Revision 1.12  1993/03/28  05:19:42    root
  129.  * Fixed error codes.
  130.  *
  131.  * Revision 1.11  1993/03/26  10:01:24    davison
  132.  * Fixed field traversal in the index generation stuff.
  133.  *
  134.  * Revision 1.10  1993/03/25  22:19:06    davison
  135.  * Fixed last patch - needed a semicolon.
  136.  * Made structure constructor do nothing.
  137.  *
  138.  * Revision 1.9  1993/03/25  18:17:47  davison
  139.  * Make data members in generated structure public.ly accessible.
  140.  *
  141.  * Revision 1.8  1993/03/24  06:17:16  kevinl
  142.  * Added source path
  143.  * Adjusted struct, class and include file names
  144.  *
  145.  * Revision 1.7  1993/03/21  23:36:31  kevinl
  146.  * Changed index enum to start at -1
  147.  * Added in object class code generation
  148.  *
  149.  * Revision 1.6  1993/03/21  18:08:58  davison
  150.  * Fixed RECORD_SIZE increment problems.
  151.  *
  152.  * Revision 1.5  1993/03/21  05:30:34  kevinl
  153.  * Fixed linked list traversal in installIndex
  154.  *
  155.  * Revision 1.4  1993/03/21  01:10:39  davison
  156.  * Now closes the relation description correctly.
  157.  * Also fixes the "2-state file size" bug by calling the void constructor
  158.  * for recServer.
  159.  *
  160.  * Revision 1.3  1993/03/20  15:02:29  davison
  161.  * More changes to keep Daz happy...
  162.  *
  163.  * (i) Path specification for db files created.
  164.  * (ii) Path specification for schema files.
  165.  * (iii) -H flag to generate only the header files.
  166.  *
  167.  * Revision 1.2  1993/03/15  19:06:55  davison
  168.  * Implemented a few nice things, like more than 2 index fields, line number
  169.  * reporting on syntax errors, and usage reporting.
  170.  *
  171.  * Just for you, Daz :-)
  172.  *
  173.  * Revision 1.1  1993/03/15  19:02:32  davison
  174.  * Initial revision
  175.  *
  176.  **************************************************************************/
  177.  
  178. #include <stdio.h>
  179. #include <stdlib.h>
  180. #if !defined(MALLOC_H_MISSING) && !defined(MALLOC_H_INCLUDED)
  181. extern "C" {
  182. #include <malloc.h>
  183. }
  184. #define MALLOC_H_INCLUDED
  185. #endif
  186. #include <iostream.h>
  187. #include <string.h>
  188. #include <fstream.h>
  189. #ifdef __EMX__
  190. #include <strstrea.h>
  191. #else
  192. #include <strstream.h>
  193. #endif
  194.  
  195. #include <idxinfo.h>
  196. #include <d_types.h>
  197. #include <rserv.h>
  198. #include <btree.h>
  199. #include <generate.h>
  200. #include <mserv.h>
  201.  
  202. int RECORD_LENGTH = 0;
  203. const int BUCKET_SIZE    = 512;
  204.  
  205. // Lots and lots of globals . Don't you just love this daz ! :-)
  206.  
  207. ofstream* relDesc = 0;    // Output stream for the relation structure header.
  208. ofstream ofHead;        // Output stream for object header file.
  209. ofstream ofCode;        // Output stream for object code file.
  210. int    relCount = 0;        // The number of relations compiled
  211. int fldSize=0;            // The size for the current field.
  212. int fldType=0;            // The type of the current field.
  213. char fldName[300];        // The name of the current field.
  214. char** indexName=0;        // The names of all the indexes.
  215. char** defaults=0;        // The defaults for all the fields.
  216. dbString fldDef;        // The current field default;
  217. fieldList* fldList;        // The list of fields.
  218. indexList* idxList;        // The list of indicies.
  219. indexList* consList;    // The list of constructors
  220. int fldInfoSize=0;        // The size of the field data.
  221. int idxInfoSize=0;        // The size of the index data.
  222. int consListSize=0;        // The size of the constructor data.
  223. char relName[300];        // The name of the current relation.
  224. char fileName[100];        // The name of the current output file.
  225. char className[300];    // The name of the object.
  226. dbString base;            // -G strings
  227. dbString derive;
  228. dbString deriveName;
  229. bool deriveDone;        // Have we generated derived classes?
  230.  
  231. int idxType;            // The type of the current index.
  232. char idxNames[MAX_FIELDS_IN_INDEX][MAX_NAME_LENGTH];
  233.                         // The name of the current primary index.
  234. strstream* idxStr;        // The string to be constructed for the enumeration.
  235.  
  236. int linenum=1;            // The number of the line being parsed.
  237. int    fieldNum;            // Used to keep track of the number of fields used in
  238.                         // an index.
  239. int indexNum=0;         // The number of indexes.
  240. int unique;                // Do we have a unique field?
  241. int stringCount;        // How many string fields
  242.  
  243. int headersOnly=0;        // Should only the headers be produced ?
  244. int    makeSource=0;
  245. int makeDatabases=0;
  246. char outputPath[300];    // Output pathname.
  247. char sourcePath[300];    // Source pathname.
  248. char inputPath[300];    // Input pathname.
  249.  
  250. //------------------------------------------------
  251. // This creates a header for the structure headers
  252. // which basically plugs diamond base and gives
  253. // version number information.
  254.  
  255. void descHeader(ostream* s, char* name)
  256. {
  257.  
  258.     *s << "//" << endl << "//   Relation Structure Description for schema file " << name << endl;
  259.     *s << "//" << endl;
  260.     *s <<"// This file has been automatically generated using the Schema"<<endl;
  261.     *s << "// Compiler provided with the Diamond Base package." << endl;
  262.     *s << "//" << endl;
  263.     *s << "//    Diamond Base : Version " << VERSION_NUMBER << endl;
  264.     *s << endl;
  265.     *s << "#include <d_types.h>" << endl;
  266.     *s << endl << endl;
  267. }
  268.  
  269. //----------------------------------------------
  270. // This creates an empty file and puts in the header info for the relation.
  271. // This file will later be used by the recServer for the relation
  272.  
  273. void createEmptyRelation(char* fname, int overwrite)
  274. {
  275.     char theName[200];
  276.     recServer theRecServer;
  277.  
  278.     if (outputPath[0] != 0)
  279.         sprintf(theName,"%s%s",outputPath,fname);
  280.     else
  281.         sprintf(theName,"%s",fname);
  282.  
  283.     // This all makes sure we don't overwrite an old file by mistake.
  284.     // We it truncates files, it doesn't seem to do so properly. This seems
  285.     // to be a library fault.
  286.  
  287. #ifdef __BORLANDC__
  288.     ofstream *output = new ofstream(theName,ios::binary|ios::noreplace);
  289. #else
  290.     ofstream *output = new ofstream(theName,ios::noreplace);
  291.     delete output;
  292.     output = new ofstream(theName,ios::noreplace);
  293. #endif
  294.     if(!*output)
  295.     {
  296. #ifdef DEBUG
  297.         cout << "Didn't open output file first time." << endl;
  298. #endif
  299.         if (!overwrite)
  300.         {
  301.             cout <<"Error : relation file " << theName <<
  302.            "already exists. Use -i option to overwrite." << endl;
  303.             exit(1);
  304.         }
  305.         delete output;
  306. #ifdef __BORLANDC__
  307.         output = new ofstream(theName,ios::binary);
  308. #else
  309.         output = new ofstream(theName);
  310. #endif
  311.         if (!*output)
  312.         {
  313.             cout <<"Error writing to file "<<theName <<
  314.                    ". Aborting." << endl;
  315.             exit(1);
  316.         }
  317.     }
  318.     // Firstly figure out how long the header is for this file.
  319.     //
  320.     int headerLength =
  321.             sizeof(int) +        // Length of the header
  322.             2*sizeof(int) +     // The field list header
  323.             fldInfoSize +        // The field list info
  324.             2*sizeof(int) +     // The index list header
  325.             idxInfoSize;        // The index list size
  326.  
  327. #ifdef DEBUG
  328.     cout << "Header Length is " << headerLength << endl;
  329. #endif
  330.     output->write((char*) &headerLength,sizeof(int));
  331. #ifdef DEBUG
  332.     cout << "Writing field stuff." << endl;
  333. #endif
  334.     *output << *fldList;
  335. #ifdef DEBUG
  336.     cout << "Writing index stuff." << endl;
  337. #endif
  338.     *output << *idxList;
  339.  
  340.     // Close output here so we don't get access problems in recServer
  341.     delete output;
  342.  
  343.     // strip the extension from the filename.
  344.  
  345.     char *idxFName = new char[strlen(theName) + 10];
  346.     strcpy(idxFName,theName);
  347.     char* ext;
  348.     ext=strrchr(idxFName,'.');
  349.  
  350.     if (!ext) // If there is no extension
  351.         ext = idxFName + strlen(idxFName); // point after the filename
  352.  
  353. #ifdef FILENAMELEN
  354.     // We have a filename length problem (eg Minix file systems)
  355.     if (ext - idxFName > FILENAMELEN - 4) // do we have enough space for ext
  356.         ext = idxFName + FILENAMELEN - 4; // chop the filename off
  357. #endif
  358.  
  359.     *ext = '\0'; // Chop off the extension
  360.  
  361.     // Ok. Now put the stuff that daz wants into the .db file.
  362.  
  363.     dbError err;
  364.     err = theRecServer.createDb(theName, RECORD_LENGTH, headerLength);
  365.  
  366. /*    if (err != recServer::db_ok)
  367.     {
  368.         cerr << "Recserver failed to work." << endl;
  369.         //exit(1);
  370.     }
  371. */
  372.  
  373.     // Now let's sort out the memServer
  374.     if (stringCount)
  375.     {
  376.         char* stringName = new char[strlen(idxFName) + 5];
  377.         strcpy(stringName, idxFName);
  378.         strcat(stringName, ".str");
  379.         memServer m;
  380.         m.createMem(stringName);
  381.     }
  382.  
  383.     // and then create an index file for each index.
  384.  
  385.     indexInfo* current = idxList->indicies;
  386.  
  387.     int indNum = 0;
  388.     while(current)
  389.     {
  390.         int keyLength=0;
  391.         for(int i=0;i<MAX_FIELDS_IN_INDEX;i++)
  392.         {
  393.             fieldInfo* curFld=fldList->fields;
  394.             if (current->idxFields[i] != -1)
  395.             {
  396.                 for(int j=0;j<current->idxFields[i];j++)
  397.                     curFld=curFld->nextFld;
  398.                 keyLength+=curFld->fldSize;
  399.             }
  400.         }
  401.  
  402. #if defined(FIXEDEXTENSION) || defined(FILENAMELEN)
  403.         // We don't need to always do this for FILENAMELEN but we are
  404.         // guaranteed that there is space for these 4 characters no matter
  405.         // what so we might as well be safe. Such arbitrary filename lengths
  406.         // are ugly anyway. No worries making them uglier!
  407.  
  408.         sprintf(ext, ".i%s%d",(i<10)?"d":"",indNum);
  409. #else
  410.         sprintf(ext, ".id%d",indNum);
  411. #endif
  412.  
  413. #ifdef DEBUG
  414.     cout << "Filename is " << idxFName << "  Extension is " << ext << endl;
  415. #endif
  416.         bTree ind(idxFName,BUCKET_SIZE, keyLength, indNum++);
  417.  
  418.         // The next line is just to convince the compiler that ind is
  419.         // really used. The reason we never access ind is all we want to do is
  420.         // create the bTree, no more.
  421.         ind.isOpen = true;
  422.         current= current->nextIdx;
  423.     }
  424.     delete idxFName;
  425. }
  426.  
  427. // Convert the index field names to internal structures
  428.  
  429. void installIndex(char* s1, char* s2, int idxType, char indexNames[MAX_FIELDS_IN_INDEX][MAX_NAME_LENGTH], indexList* & list, int& size)
  430. {
  431.     static indexInfo*    currentIdx;
  432.  
  433. #ifdef DEBUG
  434. cout << "Installing index on " << indexNames[0] << endl;
  435. #endif
  436. //    int fldNum1=-1, fldNum2=-1;
  437.  
  438.     TIndicies indicies;
  439.  
  440.     for(int z=0;z<MAX_FIELDS_IN_INDEX;z++)
  441.         indicies[z] = -1;
  442.  
  443.     // First figure out the field numbers for the required
  444.     // index fields.
  445.  
  446.     for(int fNum=0; fNum<fieldNum; fNum++)
  447.     {
  448.         fieldInfo* currentField = fldList->fields;
  449.         int i=0;
  450.  
  451. #ifdef DEBUG
  452.         cout << "Locating " << indexNames[fNum] << endl;
  453. #endif
  454.         while (currentField)
  455.         {
  456.             if (strcmp(currentField->fldName,indexNames[fNum]))
  457.             {
  458.                 i++;
  459.                 currentField=currentField->nextFld;
  460.             }
  461.             else
  462.             {
  463.                 if (s1 && currentField->fldType == D_STRING || currentField->fldType == D_DATA)
  464.                 {
  465.                     cerr << "Variable length " << s1 << "s not supported. Field "
  466.                          << currentField->fldName
  467.                          << " can not be a " << s1 << " field." << endl;
  468.                     exit(1);
  469.                 }
  470.                 indicies[fNum] = i;
  471.                 break;
  472.             }
  473.         }
  474.         if (indicies[fNum] == -1)
  475.         {
  476.             cerr << "Error parsing " << s2 << " entry : field not found in relation"
  477.                 <<  " description." << endl;
  478.             exit(1);
  479.         }
  480.     }
  481.  
  482.     // Create and install the new index.
  483.  
  484.     indexInfo* temp = new indexInfo(idxType,indicies);
  485.  
  486.     if (list->indicies==0)
  487.         list->indicies= temp;
  488.     else
  489.         currentIdx->nextIdx= temp;
  490.     currentIdx = temp;
  491.     // And increase the size of the index info.
  492.     size+=sizeof(int)
  493.             +sizeof(int)*MAX_FIELDS_IN_INDEX
  494.             +sizeof(indexInfo*);
  495.     list->numIndicies++;
  496. }
  497.  
  498. void installField()
  499. {
  500.     static fieldInfo* currentFld;
  501.  
  502.     fieldInfo* temp = new fieldInfo(fldName, fldType, fldSize);
  503.  
  504.     if (fldList->fields == 0)
  505.         fldList->fields = temp;
  506.     else
  507.         currentFld->nextFld = temp;
  508.     currentFld = temp;
  509.     // Increase the size of the field info section.
  510.     fldInfoSize+= (4*sizeof(int)) + strlen(fldName) +1;
  511.  
  512.     fldList->numFields++;
  513.  
  514.     if (defaults)
  515.         defaults = (char**)realloc(defaults, sizeof(char*) * fldList->numFields);
  516.     else
  517.         defaults = new char*;
  518.     if (fldDef.len())
  519.     {
  520.         defaults[fldList->numFields-1] = new char[fldDef.len()+1];
  521.         strcpy(defaults[fldList->numFields-1], fldDef);
  522.     }
  523.     else
  524.         defaults[fldList->numFields-1] = 0;
  525. }
  526.  
  527. void outputFieldList(ostream& of, bool strings)
  528. {
  529.     for (int ch=0; ch<=1; ch++)
  530.     {
  531.         fieldInfo* f = fldList->fields;
  532.  
  533.         while (f)
  534.         {
  535.             if (ch ^ ((f->fldType != D_CHAR && f->fldType != D_ICHAR)?1:0))
  536.             {
  537.                 if (!strings || f->fldType == D_STRING || f->fldType == D_DATA)
  538.                 {
  539.                     of << "\t";
  540.                     if (!strings)
  541.                         of << typeName(f->fldType);
  542.                     else
  543.                         if (f->fldType == D_STRING)
  544.                             of << "dbString";
  545.                         else if (f->fldType == D_DATA)
  546.                             of << "dbData";
  547.                     of << "\t";
  548.                     if ((f->fldType == D_DATA || f->fldType == D_STRING) && !strings)
  549.                         of << "_off_";
  550.  
  551.                     of << f->fldName;
  552.  
  553.                     long l = f->fldSize / mySizeOf(f->fldType);
  554.                     if (l > 1)
  555.                         of << "[" << l << "]";
  556.                     of << ";" << endl;
  557.                 }
  558.             }
  559.             f = f->nextFld;
  560.         }
  561.     }
  562. }
  563.  
  564. long indNameToNumber(char* name)
  565. {
  566.     for (int i=0; i<indexNum; i++)
  567.         if (!strcmp(name, indexName[i]))
  568.             return i;
  569.  
  570.     return -1;
  571. }
  572.  
  573. %}
  574.  
  575. %token ASSIGN
  576. %token NEWLINE
  577. %token ON
  578. %token WITH
  579. %token WITHOUT
  580. %token DUP
  581. %token TCOMMENT
  582. %token COMMA
  583. %token INDEX
  584. %token BOTH
  585. %token NUM
  586. %token SEMI
  587. %token DIGIT
  588. %token ALPHA
  589. %token ALNUM
  590. %token IDENT
  591. %token SHORT
  592. %token USHORT
  593. %token LONG
  594. %token ULONG
  595. %token DOUBLE
  596. %token FLOAT
  597. %token MONEY
  598. %token DATE
  599. %token CHAR
  600. %token ICHAR
  601. %token STRING
  602. %token DATA
  603. %token LCBRACE
  604. %token RCBRACE
  605. %token LSBRACE
  606. %token RSBRACE
  607. %token RELATION
  608. %token TYPE
  609. %token FIELD
  610. %token TYPEDEF
  611. %token UNIQUE
  612. %token AND
  613. %token IS
  614. %token CALLED
  615. %token NUTHIN
  616. %token ORDER
  617. %token DOT
  618. %token TO
  619. %token LINK
  620. %token USING
  621. %token CONSTRUCT
  622.  
  623. %%
  624.  
  625. relationList: relationList element
  626.             |
  627.             ;
  628.  
  629. element :    relation
  630.         |    link
  631.         ;
  632.  
  633. link    :    linkT identT
  634.             {
  635.                 // Ok. This is the start of the link and we have the name.
  636.             }
  637.             identT
  638.             {
  639.                 // This is the name of the first linked relation.
  640.             }
  641.             dotT identT
  642.             {
  643.                 // The name of the field to be linked in the first relation.
  644.             }
  645.             linkNodeName
  646.             {
  647.                 // The name given to the node in the link structure.
  648.             }
  649.             toT identT
  650.             {
  651.                 // The name of the second linked relation
  652.             }
  653.             dotT identT
  654.             {
  655.                 // The name of the field to be linked in the second relation
  656.             }
  657.             linkNodeName
  658.             {
  659.                 // The name given to the second link node
  660.             }
  661.             linkOrder
  662.         ;
  663.  
  664.  
  665. linkNodeName    : is called identT
  666.                   {
  667.                     // This is the name we want to give to the node.
  668.                   }
  669.                 | {
  670.                     // If no name is specified, use the field name
  671.                     // prefixed by two underlines.
  672.                   }
  673.                 ;
  674.  
  675. linkOrder    : is ORDER
  676.               {
  677.                 // If they specify that the link is to be ordered,
  678.                 // we need to generate an extra "order" field.
  679.               }
  680.             |
  681.             ;
  682.  
  683. relation    : relationT identT
  684.               {
  685.                 // Open the relation description.
  686.  
  687.                 idxStr = new strstream;
  688.                 *idxStr << "dbIdx_seq=-1";
  689.                 strcpy(fileName,yytext);
  690.  
  691.                 strcpy(relName,yytext);
  692.                 strcpy(className, yytext);
  693.  
  694.                 // Ok. now create new list structures.
  695.  
  696.                 idxList = new indexList;
  697.                 fldList = new fieldList;
  698.                 consList = new indexList;
  699.                 unique = 0;
  700.                 stringCount = 0;
  701.                 indexName = 0;
  702.               }
  703.               structName
  704.               {
  705.                 // If the relation name and class name are the same then
  706.                 // add "Str" onto the end of the name of the struct.
  707.                 if (!strcmp(relName, className))
  708.                     strcat(relName, "Str");
  709.                 *relDesc << "class "<<relName<<endl // ": public diaRel"<<endl
  710.                      << "{" << endl
  711.                          << "public:" << endl
  712.                      << "//------" << endl;
  713.                 RECORD_LENGTH = 0;
  714.               }
  715.           fieldList
  716.           {
  717.                 *idxStr << ends;
  718.                 *relDesc << "\tenum {"
  719.                      << idxStr->str()
  720.                      << "};" << endl;
  721.                 *relDesc << "\t" << relName << "(){};" << endl;
  722.                 *relDesc << "};" << endl;
  723.  
  724.                 if (stringCount)
  725.                 {
  726.                     *relDesc << endl << "struct _Strings_" << relName << endl
  727.                              << "{" << endl;
  728.                     outputFieldList(*relDesc, true);
  729.                     *relDesc << "\tvirtual ~_Strings_" << relName << "() {};" << endl;
  730.                     *relDesc << "};" << endl;
  731.                 }
  732.  
  733.                 relCount++;
  734. #ifdef DEBUG
  735.                 cout << *fldList;
  736.                 cout << *idxList;
  737. #endif
  738.  
  739.                 strcat(fileName,".db");
  740.                 if (makeDatabases)
  741.                     createEmptyRelation(fileName,1);
  742.  
  743.                 *relDesc << endl
  744.                     << "//---------------------------------------------"
  745.                     << endl << endl;
  746.  
  747.                 if (makeSource)
  748.                 {
  749.                     if (!generateClass(ofHead, ofCode, RECORD_LENGTH, idxList, fldList, relName, className, stringCount, consList, defaults))
  750.                     {
  751.                         cerr << "Unable to generate class " << className << endl;
  752.                         exit(1);
  753.                     }
  754.                 }
  755.                 if (base.len() != 0)
  756.                 {
  757.                     // Make a derived class?
  758.                     if (base == className) {
  759.                         if (deriveDone) {
  760.                             cerr << "Already generated one set of derived classes." << endl;
  761.                             exit (1);
  762.                         }
  763.                         if (generateDerived(base, derive, deriveName, fldList, consList))
  764.                         {
  765.                             deriveDone = true;
  766.                         }
  767.                         else
  768.                         {
  769.                             cerr << "Unable to derive class " << derive << endl;
  770.                             exit(1);
  771.                         }
  772.                     }
  773.                 }
  774.                 delete fldList; //
  775.                 delete idxList; // Close the list structures.
  776.                 delete idxStr;
  777.                 delete consList;
  778.                 delete[] indexName;
  779.               }
  780.             ;
  781. structName  : is called identT
  782.           {
  783.                 // An explicit name for the relation
  784.         strcpy(relName,yytext);
  785.           }
  786.         |
  787.         ;
  788.  
  789. is            : IS
  790.             |
  791.             ;
  792. called        : CALLED
  793.             ;
  794.  
  795. fieldList    : LCBRACE fieldList1
  796.               {
  797.                 outputFieldList(*relDesc, false);
  798.                 indexNum = 0;
  799.               }
  800.               indexList
  801.               constructList
  802.               RCBRACE
  803.             ;
  804.  
  805. fieldList1    : fieldList1 fieldLine
  806.             |
  807.         ;
  808.  
  809. fieldLine   : fieldDef semi
  810.             ;
  811.  
  812. semi        : SEMI
  813.             | error
  814.               {
  815.                 yyerror(" Syntax Error. Missing semicolon.\n");
  816.               }
  817.             ;
  818.  
  819. fieldDef    : type identT
  820.               {
  821.                 // *relDesc << yytext;
  822.                 strcpy(fldName,yytext);
  823.               }
  824.               size
  825.               {
  826.                 // *relDesc << ";" << endl;
  827.                 RECORD_LENGTH+=fldSize;
  828.                 fldDef.clr();
  829.               }
  830.               defValue
  831.               {
  832.                 installField();
  833.               }
  834.             ;
  835.  
  836.  
  837. defValue    : ASSIGN
  838.               {
  839.                 yyGetToSemi();
  840.                 fldDef = yytext;
  841.               }
  842.             |
  843.             ;
  844.  
  845. type        : SHORT
  846.               {
  847.                 // All the different types are handled here
  848.  
  849.                 // *relDesc << "\tshort\t";
  850.                 fldSize = sizeof(short);
  851.                 fldType = D_SHORT;
  852.               }
  853.             | USHORT
  854.               {
  855.                 // *relDesc << "\tunsigned short\t";
  856.                 fldSize = sizeof(unsigned short);
  857.                 fldType = D_USHORT;
  858.               }
  859.             | LONG
  860.               {
  861.                 // *relDesc << "\tlong\t";
  862.                 fldSize = sizeof(long);
  863.                 fldType = D_LONG;
  864.               }
  865.             | ULONG
  866.               {
  867.                 // *relDesc << "\tunsigned long\t";
  868.                 fldSize = sizeof(unsigned long);
  869.                 fldType = D_ULONG;
  870.               }
  871.             | DOUBLE
  872.               {
  873.                 // *relDesc << "\tdouble\t";
  874.                 fldSize = sizeof(double);
  875.                 fldType = D_DOUBLE;
  876.               }
  877.             | FLOAT
  878.               {
  879.                 // *relDesc << "\tfloat\t";
  880.                 fldSize = sizeof(float);
  881.                 fldType = D_FLOAT;
  882.               }
  883.             | MONEY
  884.               {
  885.                 // *relDesc << "\tmoneyType\t";
  886.                 fldSize = sizeof(moneyType);
  887.                 fldType = D_MONEY;
  888.               }
  889.             | DATE
  890.               {
  891.                 // *relDesc << "\tdateType\t";
  892.                 fldSize = sizeof(dateType);
  893.                 fldType = D_DATE;
  894.               }
  895.             | ICHAR
  896.               {
  897.                 // *relDesc << "\tchar\t";
  898.                 fldSize = sizeof(char);
  899.                 fldType = D_ICHAR;
  900.               }
  901.             | CHAR
  902.               {
  903.                 // *relDesc << "\tchar\t";
  904.                 fldSize = sizeof(char);
  905.                 fldType = D_CHAR;
  906.               }
  907.             | STRING
  908.               {
  909.                 fldSize = sizeof(long);
  910.                 fldType = D_STRING;
  911.                 stringCount++;
  912.               }
  913.             | DATA
  914.               {
  915.                 fldSize = sizeof(long);
  916.                 fldType = D_DATA;
  917.                 stringCount++;
  918.               }
  919.             | UNIQUE
  920.               {
  921.                 if (unique)
  922.                 {
  923.                     cerr << "Only one unique field allowed per relation" << endl;
  924.                     exit (1);
  925.                 }
  926.                 // *relDesc << "\tuniqueType\t";
  927.                 fldSize = sizeof(uniqueType);
  928.                 fldType = D_UNIQUE;
  929.                 unique = 1;
  930.               }
  931.             | IDENT
  932.               {
  933.                 yyerror(" Syntax Error. Expecting a type.\n");
  934.               }
  935.  
  936.             ;
  937.  
  938. size        : LSBRACE
  939.                 {
  940.                     if (fldType == D_STRING || fldType == D_DATA)
  941.                     {
  942.                         cerr << "We're not doing arrays of dbString or dbData yet.  Please come back later" << endl;
  943.                         exit(1);
  944.                     }
  945.                     // Handle arrays
  946.                     // *relDesc << "[";
  947.                 }
  948.               numT
  949.               {
  950.                 // *relDesc << yytext ;
  951.                 int size;
  952.                 sscanf(yytext,"%d",&size);
  953.                 fldSize*=size;
  954.               }
  955.               RSBRACE
  956.                 {
  957.                     // *relDesc << "]";
  958.                 }
  959.             |
  960.             ;
  961.  
  962. constructList    : constructList constructSpec
  963.               {
  964.                 installIndex(0, "paramater", idxType, idxNames, consList, consListSize);
  965.               }
  966.             |
  967.             ;
  968.  
  969. constructSpec    :    CONSTRUCT using
  970.                     {
  971.                         fieldNum=0;
  972.                         idxType = -1;
  973.                     }
  974.                     consFieldList
  975.                     consIndex
  976.                     semi
  977.             ;
  978.  
  979. consIndex    :    INDEX
  980.                 identT
  981.                 {
  982.                     int i = indNameToNumber(yytext);
  983.                     if (i == -1) {
  984.                         cerr << "Index " << yytext << " was not defined." << endl;
  985.                         exit(1);
  986.                     }
  987.                 idxType = i;
  988.                 }
  989.             |
  990.             ;
  991.  
  992. using    : USING
  993.         |
  994.         ;
  995.  
  996. consFieldList    :    consFieldList1
  997.                 |
  998.                 ;
  999.  
  1000. consFieldList1    :    consFieldList1 comma consField
  1001.                 |    consField
  1002.  
  1003. consField        :    identT
  1004.                     {
  1005.                         strcpy(idxNames[fieldNum++], yytext);
  1006.                     }
  1007.                 ;
  1008.  
  1009. indexList    : indexList indexSpec semi
  1010.               {
  1011.                 installIndex("key", "index", idxType, idxNames, idxList, idxInfoSize);
  1012.               }
  1013.             |
  1014.             ;
  1015.  
  1016.  
  1017. indexSpec    : INDEX identT
  1018.           {
  1019.         fieldNum=0;    // reset the number of fields count
  1020.         *idxStr << ", dbIdx_" << yytext;
  1021.                 if (indexName)
  1022.                     indexName = (char**)realloc(indexName, (indexNum+1)*sizeof(char*));
  1023.                 else
  1024.                     indexName = new char*;
  1025.                 indexName[indexNum]=new char[strlen(yytext)+2];
  1026.                 strcpy(indexName[indexNum++], yytext);
  1027.           }
  1028.           on identT
  1029.           {
  1030.         strcpy(idxNames[0],yytext);
  1031.         fieldNum++;
  1032.         idxType = IDX_SINGLE;
  1033.           }
  1034.           indexSpec2
  1035.         ;
  1036.  
  1037.  
  1038. indexSpec2    : indexSpec2 comma identT
  1039.               {
  1040.                 strcpy(idxNames[fieldNum],yytext);
  1041.                 fieldNum++;
  1042.                 idxType = IDX_MULTIPLE;
  1043.               }
  1044.             |
  1045.             ;
  1046.  
  1047. comma        : COMMA
  1048.             ;
  1049.  
  1050. on            : ON
  1051.             | IDENT {yyerror(" Syntax Error. Expecting \"on\".\n");}
  1052.             ;
  1053.  
  1054. /* Removed the error below so that links can be identified */
  1055.  
  1056. relationT    : RELATION
  1057.             ;
  1058. identT        : IDENT
  1059.             | error {yyerror(" Syntax Error. Expecting identifier.\n");}
  1060.             ;
  1061. numT        : NUM
  1062.             | IDENT {yyerror(" Syntax Error. Expecting integer constant.\n");}
  1063.             ;
  1064. toT            : TO
  1065.             |
  1066.             ;
  1067. linkT        : LINK
  1068.             |
  1069.             ;
  1070. dotT        : DOT
  1071.             | IDENT {yyerror(" Syntax Error. Expecting \".\"\n");}
  1072.             ;
  1073. %%
  1074.  
  1075. #include "lex.yy.c"
  1076.  
  1077. void yyerror(char* str)
  1078. {
  1079.     cout << "Line " << linenum << ":" ;
  1080.     cout << str << endl;
  1081.     exit(1);
  1082.  
  1083. }
  1084.  
  1085. int yyparse();
  1086.  
  1087. void usage(void)
  1088. {
  1089.     cerr << "Usage : dsc [-C] [-D] [-I <path>] [-O <path>] [-S <path>] [-G base derived filebase] <schema name[.ds]> " << endl;
  1090.     cerr << endl;
  1091.     cerr << "\t -D    : generate the database files." << endl;
  1092.     cerr << "\t -C    : generate the source code." << endl;
  1093.     cerr << "\t -C -D : generate both." << endl;
  1094.     cerr << "\t <none>: just parse." << endl;
  1095.     cerr << endl;
  1096.     cerr << "\t -G    : generate a derived class from base in files filebase.{h,cc}" << endl;
  1097.     cerr << endl;
  1098.     cerr << "\t -I : specify the path to search for schema files." << endl;
  1099.     cerr << "\t -O : specify the path to place database files in." << endl;
  1100.     cerr << "\t -S : specify the path to place source code in." << endl;
  1101.     exit(1);
  1102. }
  1103.  
  1104. int getName(char* name)
  1105. {
  1106.     FILE* inFile;
  1107.     char fname[200];
  1108. #ifdef DEBUG
  1109.     cout << "Looking for " << name << endl;
  1110. #endif
  1111.     if ((inFile = fopen(name,"r")) != 0)
  1112.     {
  1113.         fclose(inFile);
  1114.         return 1;
  1115.     }
  1116.     if (inputPath[0] == 0)
  1117.         return 0;
  1118.     strcpy(fname,inputPath);
  1119.     strcat(fname,name);
  1120. #ifdef DEBUG
  1121.     cout << "Looking for " << fname << endl;
  1122. #endif
  1123.     if((inFile = fopen(fname,"r")) == 0)
  1124.         return 0;
  1125.     fclose(inFile);
  1126.     strcpy(name,fname);
  1127.     return 1;
  1128. }
  1129.  
  1130. main(int argc, char* argv[])
  1131. {
  1132.     char fname[100][200];
  1133.     int     files=0;
  1134.     char bname[200];
  1135.  
  1136.     outputPath[0]=0;
  1137.     inputPath[0]=0;
  1138.     sourcePath[0]=0;
  1139.  
  1140.     if (argc == 1)
  1141.     {
  1142.         usage();
  1143.     }
  1144.  
  1145.     // Parse the command line args
  1146.     for(int i=1;i<argc;i++)
  1147.     {
  1148.         if (!strcasecmp(argv[i],"-G")) {
  1149.             if (argc-i < 3)
  1150.             {
  1151.                 cerr << "Wrong number of arguments to -G." << endl;
  1152.                 usage();
  1153.             }
  1154.             if (base.len())
  1155.             {
  1156.                 cerr << "Only one -G allowed per run." << endl;
  1157.                 usage();
  1158.             }
  1159.             // Usage is -d base derived file
  1160.             base = argv[i+1];
  1161.             derive = argv[i+2];
  1162.             deriveName = argv[i+3];
  1163.             deriveDone = false;
  1164.             i+=3;
  1165.         }
  1166.         else
  1167.         if (!strcasecmp(argv[i],"-C"))
  1168.         {
  1169.             makeSource=1;
  1170.             //headersOnly=1;
  1171.         }
  1172.         else
  1173.         if (!strcasecmp(argv[i],"-D"))
  1174.         {
  1175.             makeDatabases=1;
  1176.         }
  1177.         else
  1178.         if (!strcasecmp(argv[i],"-O"))
  1179.         {
  1180.             if (outputPath[0] != 0)
  1181.             {
  1182.                 cerr << "Output path already specified." << endl;
  1183.                 usage();
  1184.             }
  1185.             if ((argc < i+1) || (argv[i+1] == 0))
  1186.                 usage();
  1187.             strcpy(outputPath,argv[i+1]);
  1188.             if(outputPath[strlen(outputPath)-1] != '/')
  1189.                 strcat(outputPath,"/");
  1190.             i++;
  1191.  
  1192.         }
  1193.         else
  1194.         if (!strcasecmp(argv[i],"-S"))
  1195.         {
  1196.             if (sourcePath[0] != 0)
  1197.             {
  1198.                 cerr << "Source path already specified." << endl;
  1199.                 usage();
  1200.             }
  1201.             if ((argc < i+1) || (argv[i+1] == 0))
  1202.                 usage();
  1203.             strcpy(sourcePath,argv[i+1]);
  1204.             if(outputPath[strlen(sourcePath)-1] != '/')
  1205.                 strcat(sourcePath,"/");
  1206.             i++;
  1207.  
  1208.         }
  1209.         else
  1210.         if (!strcasecmp(argv[i],"-I"))
  1211.         {
  1212.             if (inputPath[0] != 0)
  1213.             {
  1214.                 cerr << "Input path already specified." << endl;
  1215.                 usage();
  1216.             }
  1217.             if ((argc < i+1) || (argv[i+1] == 0))
  1218.                 usage();
  1219.             strcpy(inputPath,argv[i+1]);
  1220.             if(inputPath[strlen(inputPath)-1] != '/')
  1221.                 strcat(inputPath,"/");
  1222.             i++;
  1223.         }
  1224.         else
  1225.         {
  1226.             if (argv[i][0] == '-')
  1227.             {
  1228.                 cerr << "Invalid option." << endl;
  1229.                 usage();
  1230.             }
  1231.             if (files !=0)
  1232.             {
  1233.                 cerr << "Multiple file compilation not supported." << endl;
  1234.                 usage();
  1235.             }
  1236. //            fname[files] = new char[strlen(argv[i])+1];
  1237.             strcpy(fname[files++],argv[i]);
  1238.         }
  1239.     }
  1240.  
  1241. #ifdef DEBUG
  1242.     if((!makeSource)&&(!makeDatabases))
  1243.         cout << "Parsing schema's only." << endl;
  1244.     if (makeSource)
  1245.         cout << "Outputting source code." << endl;
  1246.     if (makeDatabases)
  1247.         cout << "Outputing databases." << endl;
  1248.     if (outputPath[0] != 0)
  1249.         cout << "Dumping output to " << outputPath << endl;
  1250.     if (sourcePath[0] != 0)
  1251.         cout << "Creating source in " << sourcePath << endl;
  1252.     cout <<"Creating databases for :" << endl;
  1253.     for(i=0;i<files;i++)
  1254.         cout << fname[i] << endl;
  1255. #endif
  1256.  
  1257.  
  1258.     cout << "Diamond Base Schema Compiler" << endl;
  1259.  
  1260.     for(i=0;i<files;i++)
  1261.     {
  1262.         char* p;
  1263.         char* lastslash;
  1264.         char* lastdot;
  1265.         char* lastbslash;
  1266.  
  1267.         // Let's analyse this path
  1268.         lastslash = strrchr(fname[i], '/');
  1269.         lastbslash = strrchr(fname[i], '\\');
  1270.         lastdot = strrchr(fname[i], '.');
  1271.  
  1272.         // Find the last directory delimeter
  1273.         if (lastbslash > lastslash)
  1274.             lastslash = lastbslash;
  1275.  
  1276.         // Does the filename component (after the last delimeter) have a dot
  1277.         // If not add a suffix
  1278.         if (!lastdot || lastslash > lastdot)
  1279.             strcat(fname[i],".ds");
  1280.  
  1281.         // Find the base name, without extension
  1282.         strcpy(bname,fname[i]);
  1283.         p=strrchr(bname, '.');
  1284.         *p = 0;
  1285.  
  1286.         cout << "Building relations from schema file " << fname[i] << endl;
  1287.  
  1288.  
  1289.         if (!getName(fname[i]))
  1290.         {
  1291.             cerr << "Schema Description file \"" << fname[i] << "\" not found." << endl;
  1292.             exit(1);
  1293.         }
  1294.  
  1295.         yyin = fopen(fname[i],"r");
  1296.         if (yyin == 0)
  1297.         {
  1298.             cout << "Schema description file \""<<fname[i]<<"\" not found." << endl;
  1299.             cout << "Aborting." << endl;
  1300.             exit(1);
  1301.         }
  1302.  
  1303.     // Open the relation description.
  1304.  
  1305.         char *str = new char[strlen(sourcePath) + strlen(bname) + 10];
  1306.  
  1307.         if(makeSource)
  1308.         {
  1309.             if (sourcePath[0] != 0)
  1310.                 sprintf(str,"%s%s",sourcePath,bname);
  1311.             else
  1312.                 sprintf(str,"%s",bname);
  1313.             if (!generateStart(ofHead, ofCode, str))
  1314.             {
  1315.                 cerr << "Unable to create source code files for class" << endl;
  1316.                 exit(1);
  1317.             }
  1318.  
  1319. #ifdef FILENAMELEN
  1320.             // We have a filename length problem (eg Minix file systems)
  1321.             long extra = strlen(bname) - FILENAMELEN + 4;
  1322.             if (extra > 0) // do we have enough space
  1323.                 *(str + strlen(str) - extra)=0; // chop the filename off
  1324. #endif
  1325.  
  1326.             strcat(str, "_s.h");
  1327.             relDesc = new ofstream(str);
  1328.  
  1329.             if (relDesc == 0)
  1330.             {
  1331.                 cerr<<"Error opening relation description file "<<str<<endl;
  1332.                 cerr<<"Aborting." << endl;
  1333.             }
  1334.         }
  1335.         else
  1336.         {
  1337.             relDesc = new ofstream("/dev/null");
  1338.         }
  1339.         descHeader(relDesc,fname[i]);
  1340.         yyparse();
  1341.         cout << relCount << " relations successfully compiled." << endl;
  1342.         relCount = 0;
  1343.         fclose(yyin);
  1344.         if(makeSource)
  1345.             generateEnd(ofHead, ofCode);
  1346.         delete relDesc;
  1347.         delete str;
  1348.         if (base.len() && !deriveDone)
  1349.             cerr << "WARNING: Derived class was not generated, " << base << "not found." << endl;
  1350.     }
  1351.  
  1352.     return 0;
  1353. }
  1354.