home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR9 / WIZTOO.ZIP / CHNLSPEC.CPP < prev    next >
C/C++ Source or Header  |  1993-09-20  |  11KB  |  332 lines

  1. //  Module: CHNLSPEC.CPP
  2.  
  3. //                                                   September 20, 1993
  4. //                                                   Fairfield, Iowa
  5.  
  6. //          Aerosoft  (R)  Broadcast Channel Wizard   Version 1.0
  7. //          Copyright (c)  Aerosoft 1993     All rights reserved.
  8.  
  9. //          This software source code is FREEWARE.  You may be use the
  10. //          source code or redistribute the source code free of charge.
  11. //          However, you cannot sell this source code or any alteration of
  12. //          the source code.
  13.  
  14. //  This module implements the member functions of the ArgumentList and ChannelSpecs
  15. //  classes.  See file BCWIZ.TXT for more details.
  16.  
  17. #include    <stdio.h>
  18. #include    <string.h>
  19. #include    <process.h>
  20. #include    <ctype.h>
  21. #include    <malloc.h>
  22.  
  23. #include    "CHNLSPEC.H"
  24.  
  25. void ArgumentList::Add (char *cp, int iLen)
  26. {
  27.     if (iNumInList >= MAXARGS)
  28.     {
  29.         printf("*** Execution error: (%d:%d)  Too many arguments.***\n",
  30.                 opInStream->Line(), opInStream->Column());
  31.         exit(0);
  32.     }
  33.  
  34.     oArgument[iNumInList].cpString = cp;
  35.     oArgument[iNumInList].iLen = iLen;
  36.  
  37.     iNumInList++;
  38. }
  39.  
  40. static void MakeString (char **cpNew, char *cpString, int iLen)
  41. {
  42.     if ((*cpNew=(char *)malloc(iLen+1))==NULL)        // add 1 for null terminator
  43.     {
  44.         printf("*** Execution error: Dynamic memory capacity exceeded. ***\n");
  45.         exit(0);
  46.     }
  47.  
  48.     char *cpTemp = *cpNew;
  49.     for (int i=0; *cpString && i<iLen; i++) *cpTemp++ = *cpString++;
  50.     *cpTemp = '\0';
  51. }
  52.  
  53. static void AppendStringWithChar (char *cpString, char c)
  54. {
  55.     int i = strlen(cpString);
  56.     cpString[i] = c;
  57.     cpString[i+1] = '\0';
  58. }
  59.  
  60. static int IsReturnType (char *cpString)
  61. {
  62.     if (strcmp(cpString, "int") == 0) return 1;
  63.     if (strcmp(cpString, "long") == 0) return 1;
  64.     if (strcmp(cpString, "float") == 0) return 1;
  65.     if (strcmp(cpString, "double") == 0) return 1;
  66.     if (strcmp(cpString, "void") == 0) return 1;
  67.     return 0;
  68. }
  69.  
  70. static int FirstOfLabel (char c)
  71. {
  72.     if (isalpha(c)) return 1;
  73.     if (c == '_') return 1;
  74.     return 0;
  75. }
  76.  
  77. static char caVoid[]="void";
  78. static void EliminateVoid (char *cpString, int &iLen)
  79. {
  80.     if (iLen != (int)strlen(caVoid)) return;
  81.     for (int i=0; i<iLen; i++) if (*cpString++ != caVoid[i]) return;
  82.     iLen = 0;
  83.     return;
  84. }
  85.  
  86. void ChannelSpecs::SyntaxError (char *cpMsg)
  87. {
  88.     printf("*** Syntax error: (%d:%d) %s. ***\n",
  89.                 opInStream->Line(), opInStream->Column(), cpMsg);
  90.     exit(0);
  91. }
  92.  
  93. //  Trap syntax errors--when parsing forward I should always find something.
  94. char *ChannelSpecs::ParseForward (int &iLen)
  95. {   
  96.     char *cp;
  97.     if ((cp=opInStream->ParseForward(iLen))==NULL)
  98.         SyntaxError("Unexpected end-of-file");
  99.     return cp;
  100. }
  101.  
  102. //  Trap syntax errors--when parsing forward I should always find something.
  103. char *ChannelSpecs::ParseNumber (int &iLen)
  104. {   
  105.     char *cp;
  106.     if ((cp=opInStream->ParseNumber(iLen))==NULL)
  107.         SyntaxError("Unexpected end-of-file");
  108.     return cp;
  109. }
  110.  
  111. char *ChannelSpecs::ParseBackward (int &iLen)
  112. {
  113.     return opInStream->ParseBackward(iLen);
  114. }
  115.  
  116. // Copy the exact length and return the pointer to one past the
  117. // end of the new string.
  118. static char *CopyString (char *cpOut, char *cpIn, int iLen)
  119. {
  120.     for (int i=0; i<iLen; i++) *cpOut++ = *cpIn++;
  121.     return cpOut;
  122. }
  123.  
  124. void ChannelSpecs::MakeArgList (ArgumentList &oArgList)
  125. {
  126.     int      i, iTotalLen;
  127.     Argument *opArg;
  128.  
  129.     // Determine how much space will be needed for this list.
  130.     for (i=0,
  131.          iTotalLen=0,
  132.          opArg=oArgList.oArgument; i<oArgList.iNumInList; i++,opArg++)
  133.         iTotalLen += opArg->iLen;
  134.     
  135.     // Create a memory buffer for the list and start it with '('
  136.     // Leave space for ", " between arguments and "()" plus a null-terminator.
  137.     MakeString(&opCurrentSpec->cpArgList,
  138.                "(", iTotalLen+(oArgList.iNumInList*2)+3);
  139.     
  140.     // Start building the argument list immediately following the '('
  141.     char *cp = opCurrentSpec->cpArgList+1;
  142.     
  143.     // Build the list by posting the first argument and adding every
  144.     // other argument prefix with a comma.
  145.     
  146.     opArg=oArgList.oArgument;
  147.     if (oArgList.iNumInList > 0)
  148.         cp = CopyString(cp, opArg->cpString, opArg->iLen);
  149.  
  150.     for (i=1,opArg++; i<oArgList.iNumInList; i++,opArg++)
  151.     {
  152.         cp = CopyString(cp, ", ", 2);
  153.         cp = CopyString(cp, opArg->cpString, opArg->iLen);
  154.     }
  155.     
  156.     // Close the argument list with ')' and a null-terminator.
  157.     
  158.     cp = CopyString(cp, ")", 1);
  159.     *cp = '\0';
  160. }
  161.  
  162. int ChannelSpecs::GetNextChannelSpec (InStream &oInStream)
  163. {
  164.     char    *cpString;
  165.     int     iLen;
  166.  
  167.     if (iNumSpecs >= MAXCHANNELS)
  168.     {
  169.         printf("*** Execution error: Maximum number of channels exceeded. ***\n");
  170.         exit(0);
  171.     }
  172.  
  173.     // opCurrentSpec and opInStream are temporary values used here and by other
  174.     // member functions called by GetNextChannelSpec
  175.     opCurrentSpec = &oChannelSpec[iNumSpecs];
  176.     opInStream = &oInStream;
  177.  
  178.     opInStream->ResetParsing();      
  179.     
  180.     // The beginning of an entry can be either an optional return type specifier
  181.     // or the function's name.
  182.     // NOTE: I don't use ChannelSpecs::ParseForward because it traps end-of-file
  183.     //       as a syntax error.  Here at the beginning of an entry it just means
  184.     //       I'm all done.
  185.     if ((cpString=oInStream.ParseForward(iLen))==NULL) return 0;
  186.     
  187.     // I assume that the first label is a return type.  If not, it will later
  188.     // be moved to the function name. 
  189.     MakeString(&opCurrentSpec->cpReturnType, cpString, iLen);
  190.  
  191.     // Determine whether the first label is a return type.
  192.     if (IsReturnType(opCurrentSpec->cpReturnType))
  193.     {
  194.         cpString = ParseForward(iLen);
  195.  
  196.         // Delimiters '&' and '*' are part of the return type.
  197.         if ((*cpString=='&') || (*cpString=='*'))
  198.         {
  199.             AppendStringWithChar(opCurrentSpec->cpReturnType, *cpString);
  200.             cpString = ParseForward(iLen);
  201.         }
  202.         
  203.         // I should be at the function name now.  If I'm not at a label
  204.         // then something's wrong.
  205.         if (!FirstOfLabel(*cpString))
  206.             SyntaxError("Can't find function name.");
  207.  
  208.         MakeString(&opCurrentSpec->cpFuncName, cpString, iLen);
  209.     }
  210.     else
  211.     {
  212.         // I should be at the function name now.  If I'm not at a label
  213.         // then something's wrong.
  214.         if (!FirstOfLabel(*cpString))
  215.             SyntaxError("Can't find function name.");
  216.             
  217.         // There was no return type specified.  It was the function name label
  218.         // I found first.  Move it to the function name holder and create the
  219.         // default return type.
  220.         opCurrentSpec->cpFuncName = opCurrentSpec->cpReturnType;
  221.         MakeString(&opCurrentSpec->cpReturnType,
  222.                    DEFAULT_RETURN_TYPE, strlen(DEFAULT_RETURN_TYPE));
  223.     }
  224.     
  225.     // I'm now looking for the argument list.  I'm going to do two things with it:
  226.     // 1) I will mark the beginning and end of the list so that I can save it as
  227.     //    the "ProtoList" .. that's the argument list with each argument's type
  228.     //    specifier.
  229.     // 2) I will extract the argument names without their type specifiers so that
  230.     //    I can later build a list of arguments to be used to call the function.
  231.     
  232.     cpString = ParseForward(iLen);
  233.  
  234.     if (*cpString != '(') SyntaxError("Expected '('.");
  235.  
  236.     char *cpBOL = cpString;                     // mark list beginning
  237.  
  238.     ArgumentList oArgumentList(opInStream);        // a database to hold the argument names
  239.  
  240.     cpString = ParseForward(iLen);
  241.     while (*cpString != ')')                    // skip loop if list is empty
  242.     {
  243.         // Argument names must always be followed by a comma or the closing
  244.         // list parenthesis ')'.
  245.         // NOTE: the InStream parsing function automatically eliminates any
  246.         //       nested parenthesis that might be used in a type specifier to
  247.         //       an argument.  Therefore, once I find a ')' here I now that it's
  248.         //       the last ')' closing the list.
  249.         
  250.         while ((*cpString != ')') && (*cpString != ',')) cpString = ParseForward(iLen);
  251.         
  252.         if (*cpString == ')') break;            // loop 'til end-of-list
  253.         
  254.         // The argument name is the label just ahead of the comma.
  255.         
  256.         cpString = ParseBackward(iLen);
  257.         if (iLen == 0) SyntaxError("Invalid argument name.");
  258.         oArgumentList.Add(cpString, iLen);
  259.         
  260.         // Move past this last comma.
  261.         cpString = ParseForward(iLen);
  262.     }
  263.  
  264.     char *cpEOL = cpString;                        // mark list end
  265.     
  266.     // I'm now looking for the last argument in the list, if not the only
  267.     // argument.
  268.     
  269.     cpString = ParseBackward(iLen);
  270.     
  271.     // If there's a "void" keyword to indicate an empty list, then eliminate it
  272.     // by setting iLen=0.
  273.     EliminateVoid(cpString, iLen);
  274.     
  275.     // Add the last argument to the list.  If there are no arguments, or if the
  276.     // "void" keyword was found, then leave the list empty.  If the list is not
  277.     // empty but the last argument is null, then this is an error.
  278.     
  279.     if (iLen != 0)
  280.         oArgumentList.Add(cpString, iLen);
  281.     else if (!oArgumentList.Empty())
  282.         SyntaxError("Invalid argument name.");
  283.     
  284.     // Save the argument list with its argument type specifiers as the "ProtoList".
  285.     MakeString(&opCurrentSpec->cpProtoList, cpBOL, cpEOL-cpBOL+1);
  286.     
  287.     // Make an argument list without the argument type specifiers.  The argument
  288.     // name database is used to do this.
  289.     MakeArgList(oArgumentList);
  290.  
  291.     // I'm now looking for optional parameters and the end of this entry.
  292.     
  293.     cpString = ParseForward(iLen);
  294.  
  295.     // Look for optional return default value in brackets -- [XX]
  296.     if (*cpString == '[')
  297.     {
  298.         cpString = ParseNumber(iLen);            // parse for number, not a label
  299.         if (iLen == 0) SyntaxError("[] has no argument");
  300.         MakeString(&opCurrentSpec->cpReturnDefaultValue, cpString, iLen);
  301.         cpString = ParseForward(iLen);
  302.         if (*cpString != ']') SyntaxError("Expected ]");
  303.         cpString = ParseForward(iLen);
  304.     }
  305.     else
  306.         MakeString(&opCurrentSpec->cpReturnDefaultValue,
  307.                         DEFAULT_RETURN_DEFAULT, strlen(DEFAULT_RETURN_DEFAULT));
  308.     
  309.     // Look for optional max receivers in braces -- {XX}
  310.     if (*cpString == '{')
  311.     {
  312.         cpString = ParseNumber(iLen);            // parse for number, not a label
  313.         if (iLen == 0) SyntaxError("{} has no argument");
  314.         MakeString(&opCurrentSpec->cpMaxReceivers, cpString, iLen);
  315.         cpString = ParseForward(iLen);
  316.         if (*cpString != '}') SyntaxError("Expected }");
  317.         cpString = ParseForward(iLen);
  318.     }
  319.     else
  320.         MakeString(&opCurrentSpec->cpMaxReceivers,
  321.                    DEFAULT_MAX_RECEIVERS, strlen(DEFAULT_MAX_RECEIVERS));
  322.     
  323.     // Make sure this entry is terminated properly
  324.     if (*cpString != ';') SyntaxError("Expected ;");
  325.  
  326.     // Advance to next channel spec entry.
  327.     iNumSpecs++;
  328.  
  329.     return 1;
  330. }
  331.  
  332.