home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
High Voltage Shareware
/
high1.zip
/
high1
/
DIR9
/
WIZTOO.ZIP
/
CHNLSPEC.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-20
|
11KB
|
332 lines
// Module: CHNLSPEC.CPP
// September 20, 1993
// Fairfield, Iowa
// Aerosoft (R) Broadcast Channel Wizard Version 1.0
// Copyright (c) Aerosoft 1993 All rights reserved.
// This software source code is FREEWARE. You may be use the
// source code or redistribute the source code free of charge.
// However, you cannot sell this source code or any alteration of
// the source code.
// This module implements the member functions of the ArgumentList and ChannelSpecs
// classes. See file BCWIZ.TXT for more details.
#include <stdio.h>
#include <string.h>
#include <process.h>
#include <ctype.h>
#include <malloc.h>
#include "CHNLSPEC.H"
void ArgumentList::Add (char *cp, int iLen)
{
if (iNumInList >= MAXARGS)
{
printf("*** Execution error: (%d:%d) Too many arguments.***\n",
opInStream->Line(), opInStream->Column());
exit(0);
}
oArgument[iNumInList].cpString = cp;
oArgument[iNumInList].iLen = iLen;
iNumInList++;
}
static void MakeString (char **cpNew, char *cpString, int iLen)
{
if ((*cpNew=(char *)malloc(iLen+1))==NULL) // add 1 for null terminator
{
printf("*** Execution error: Dynamic memory capacity exceeded. ***\n");
exit(0);
}
char *cpTemp = *cpNew;
for (int i=0; *cpString && i<iLen; i++) *cpTemp++ = *cpString++;
*cpTemp = '\0';
}
static void AppendStringWithChar (char *cpString, char c)
{
int i = strlen(cpString);
cpString[i] = c;
cpString[i+1] = '\0';
}
static int IsReturnType (char *cpString)
{
if (strcmp(cpString, "int") == 0) return 1;
if (strcmp(cpString, "long") == 0) return 1;
if (strcmp(cpString, "float") == 0) return 1;
if (strcmp(cpString, "double") == 0) return 1;
if (strcmp(cpString, "void") == 0) return 1;
return 0;
}
static int FirstOfLabel (char c)
{
if (isalpha(c)) return 1;
if (c == '_') return 1;
return 0;
}
static char caVoid[]="void";
static void EliminateVoid (char *cpString, int &iLen)
{
if (iLen != (int)strlen(caVoid)) return;
for (int i=0; i<iLen; i++) if (*cpString++ != caVoid[i]) return;
iLen = 0;
return;
}
void ChannelSpecs::SyntaxError (char *cpMsg)
{
printf("*** Syntax error: (%d:%d) %s. ***\n",
opInStream->Line(), opInStream->Column(), cpMsg);
exit(0);
}
// Trap syntax errors--when parsing forward I should always find something.
char *ChannelSpecs::ParseForward (int &iLen)
{
char *cp;
if ((cp=opInStream->ParseForward(iLen))==NULL)
SyntaxError("Unexpected end-of-file");
return cp;
}
// Trap syntax errors--when parsing forward I should always find something.
char *ChannelSpecs::ParseNumber (int &iLen)
{
char *cp;
if ((cp=opInStream->ParseNumber(iLen))==NULL)
SyntaxError("Unexpected end-of-file");
return cp;
}
char *ChannelSpecs::ParseBackward (int &iLen)
{
return opInStream->ParseBackward(iLen);
}
// Copy the exact length and return the pointer to one past the
// end of the new string.
static char *CopyString (char *cpOut, char *cpIn, int iLen)
{
for (int i=0; i<iLen; i++) *cpOut++ = *cpIn++;
return cpOut;
}
void ChannelSpecs::MakeArgList (ArgumentList &oArgList)
{
int i, iTotalLen;
Argument *opArg;
// Determine how much space will be needed for this list.
for (i=0,
iTotalLen=0,
opArg=oArgList.oArgument; i<oArgList.iNumInList; i++,opArg++)
iTotalLen += opArg->iLen;
// Create a memory buffer for the list and start it with '('
// Leave space for ", " between arguments and "()" plus a null-terminator.
MakeString(&opCurrentSpec->cpArgList,
"(", iTotalLen+(oArgList.iNumInList*2)+3);
// Start building the argument list immediately following the '('
char *cp = opCurrentSpec->cpArgList+1;
// Build the list by posting the first argument and adding every
// other argument prefix with a comma.
opArg=oArgList.oArgument;
if (oArgList.iNumInList > 0)
cp = CopyString(cp, opArg->cpString, opArg->iLen);
for (i=1,opArg++; i<oArgList.iNumInList; i++,opArg++)
{
cp = CopyString(cp, ", ", 2);
cp = CopyString(cp, opArg->cpString, opArg->iLen);
}
// Close the argument list with ')' and a null-terminator.
cp = CopyString(cp, ")", 1);
*cp = '\0';
}
int ChannelSpecs::GetNextChannelSpec (InStream &oInStream)
{
char *cpString;
int iLen;
if (iNumSpecs >= MAXCHANNELS)
{
printf("*** Execution error: Maximum number of channels exceeded. ***\n");
exit(0);
}
// opCurrentSpec and opInStream are temporary values used here and by other
// member functions called by GetNextChannelSpec
opCurrentSpec = &oChannelSpec[iNumSpecs];
opInStream = &oInStream;
opInStream->ResetParsing();
// The beginning of an entry can be either an optional return type specifier
// or the function's name.
// NOTE: I don't use ChannelSpecs::ParseForward because it traps end-of-file
// as a syntax error. Here at the beginning of an entry it just means
// I'm all done.
if ((cpString=oInStream.ParseForward(iLen))==NULL) return 0;
// I assume that the first label is a return type. If not, it will later
// be moved to the function name.
MakeString(&opCurrentSpec->cpReturnType, cpString, iLen);
// Determine whether the first label is a return type.
if (IsReturnType(opCurrentSpec->cpReturnType))
{
cpString = ParseForward(iLen);
// Delimiters '&' and '*' are part of the return type.
if ((*cpString=='&') || (*cpString=='*'))
{
AppendStringWithChar(opCurrentSpec->cpReturnType, *cpString);
cpString = ParseForward(iLen);
}
// I should be at the function name now. If I'm not at a label
// then something's wrong.
if (!FirstOfLabel(*cpString))
SyntaxError("Can't find function name.");
MakeString(&opCurrentSpec->cpFuncName, cpString, iLen);
}
else
{
// I should be at the function name now. If I'm not at a label
// then something's wrong.
if (!FirstOfLabel(*cpString))
SyntaxError("Can't find function name.");
// There was no return type specified. It was the function name label
// I found first. Move it to the function name holder and create the
// default return type.
opCurrentSpec->cpFuncName = opCurrentSpec->cpReturnType;
MakeString(&opCurrentSpec->cpReturnType,
DEFAULT_RETURN_TYPE, strlen(DEFAULT_RETURN_TYPE));
}
// I'm now looking for the argument list. I'm going to do two things with it:
// 1) I will mark the beginning and end of the list so that I can save it as
// the "ProtoList" .. that's the argument list with each argument's type
// specifier.
// 2) I will extract the argument names without their type specifiers so that
// I can later build a list of arguments to be used to call the function.
cpString = ParseForward(iLen);
if (*cpString != '(') SyntaxError("Expected '('.");
char *cpBOL = cpString; // mark list beginning
ArgumentList oArgumentList(opInStream); // a database to hold the argument names
cpString = ParseForward(iLen);
while (*cpString != ')') // skip loop if list is empty
{
// Argument names must always be followed by a comma or the closing
// list parenthesis ')'.
// NOTE: the InStream parsing function automatically eliminates any
// nested parenthesis that might be used in a type specifier to
// an argument. Therefore, once I find a ')' here I now that it's
// the last ')' closing the list.
while ((*cpString != ')') && (*cpString != ',')) cpString = ParseForward(iLen);
if (*cpString == ')') break; // loop 'til end-of-list
// The argument name is the label just ahead of the comma.
cpString = ParseBackward(iLen);
if (iLen == 0) SyntaxError("Invalid argument name.");
oArgumentList.Add(cpString, iLen);
// Move past this last comma.
cpString = ParseForward(iLen);
}
char *cpEOL = cpString; // mark list end
// I'm now looking for the last argument in the list, if not the only
// argument.
cpString = ParseBackward(iLen);
// If there's a "void" keyword to indicate an empty list, then eliminate it
// by setting iLen=0.
EliminateVoid(cpString, iLen);
// Add the last argument to the list. If there are no arguments, or if the
// "void" keyword was found, then leave the list empty. If the list is not
// empty but the last argument is null, then this is an error.
if (iLen != 0)
oArgumentList.Add(cpString, iLen);
else if (!oArgumentList.Empty())
SyntaxError("Invalid argument name.");
// Save the argument list with its argument type specifiers as the "ProtoList".
MakeString(&opCurrentSpec->cpProtoList, cpBOL, cpEOL-cpBOL+1);
// Make an argument list without the argument type specifiers. The argument
// name database is used to do this.
MakeArgList(oArgumentList);
// I'm now looking for optional parameters and the end of this entry.
cpString = ParseForward(iLen);
// Look for optional return default value in brackets -- [XX]
if (*cpString == '[')
{
cpString = ParseNumber(iLen); // parse for number, not a label
if (iLen == 0) SyntaxError("[] has no argument");
MakeString(&opCurrentSpec->cpReturnDefaultValue, cpString, iLen);
cpString = ParseForward(iLen);
if (*cpString != ']') SyntaxError("Expected ]");
cpString = ParseForward(iLen);
}
else
MakeString(&opCurrentSpec->cpReturnDefaultValue,
DEFAULT_RETURN_DEFAULT, strlen(DEFAULT_RETURN_DEFAULT));
// Look for optional max receivers in braces -- {XX}
if (*cpString == '{')
{
cpString = ParseNumber(iLen); // parse for number, not a label
if (iLen == 0) SyntaxError("{} has no argument");
MakeString(&opCurrentSpec->cpMaxReceivers, cpString, iLen);
cpString = ParseForward(iLen);
if (*cpString != '}') SyntaxError("Expected }");
cpString = ParseForward(iLen);
}
else
MakeString(&opCurrentSpec->cpMaxReceivers,
DEFAULT_MAX_RECEIVERS, strlen(DEFAULT_MAX_RECEIVERS));
// Make sure this entry is terminated properly
if (*cpString != ';') SyntaxError("Expected ;");
// Advance to next channel spec entry.
iNumSpecs++;
return 1;
}