Files
firestorm/Gameleap/code/mw4/Code/MW4/Ablrtn.cpp
T
Cyd 2b8ca921cb Initial full mirror of c:\VWE (source + assets + toolchain + outputs) via Git LFS
Complete disaster-recovery snapshot: engine/game source, game data assets,
VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive.
Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false,
no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2026-06-24 21:28:16 -05:00

2004 lines
58 KiB
C++

//***************************************************************************
//
// ABLRTN.CPP
//
//***************************************************************************
#include "MW4Headers.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <setjmp.h>
#pragma warning (disable:4284)
#pragma warning (push)
#include <stlport\string>
#pragma warning (pop)
#ifndef ABLGEN_H
#include "ablgen.h"
#endif
#ifndef ABLERR_H
#include "ablerr.h"
#endif
#ifndef ABLSCAN_H
#include "ablscan.h"
#endif
#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif
#ifndef ABLPARSE_H
#include "ablparse.h"
#endif
#ifndef ABLEXEC_H
#include "ablexec.h"
#endif
#ifndef ABLENV_H
#include "ablenv.h"
#endif
#ifndef ABL_H
#include "abl.h"
#endif
#ifndef ABLDBUG_H
#include "abldbug.h"
#endif
#ifndef ABLHEAP_H
#include "ablheap.h"
#endif
#include "AblProfiler.hpp"
#include "ablfuncs.hpp"
#include "ABLFile.h"
// MC-specific...
#ifdef USE_OBJECTS
#ifndef GROUP_H
#include "group.h"
#endif
#endif
//#ifndef IFACE_H
//#include "iface.h"
//#endif
//***************************************************************************
namespace ABL
{
extern ABLError *ablError;
extern jmp_buf abl_jmp_buf;
extern long MaxBreaks;
extern long MaxWatches;
extern DebuggerPtr debugger;
extern long NumModules;
extern ModuleEntryPtr ModuleRegistry;
extern ABLModulePtr* ModuleInstanceRegistry;
extern long MaxModules;
extern ABLModulePtr* LibraryInstanceRegistry;
extern long MaxLibraries;
extern long NumModulesRegistered;
extern long NumModuleInstances;
extern long MaxWatchesPerModule;
extern long MaxBreakPointsPerModule;
extern long MaxCodeBufferSize;
extern ABLModulePtr CurModule;
extern ABLModulePtr CurLibrary;
extern char* codeBuffer;
extern char* codeBufferPtr;
extern char* codeSegmentPtr;
extern char* codeSegmentLimit;
extern char* statementStartPtr;
extern StackItem* stack;
extern StackItemPtr tos;
extern StackItemPtr stackFrameBasePtr;
extern StackItemPtr StaticDataPtr;
extern long* StaticVariablesSizes;
extern long* EternalVariablesSizes;
extern long MaxEternalVariables;
extern long eternalOffset;
extern long MaxStaticVariables;
extern long NumStaticVariables;
extern long CurModuleHandle;
extern bool CallModuleInit;
extern bool InOrdersBlock;
extern long MaxLoopIterations;
extern bool AssertEnabled;
extern bool IncludeDebugInfo;
extern bool ProfileABL;
extern bool Crunch;
extern long level;
extern long FSMLevel;
extern long lineNumber;
extern long FileNumber;
extern FilePtr sourceFile;
extern bool printFlag;
extern bool blockFlag;
extern BlockType blockType;
extern SymTableNodePtr CurModuleIdPtr;
extern SymTableNodePtr CurRoutineIdPtr;
extern bool DumbGetCharOn;
extern long NumOpenFiles;
extern long NumSourceFiles;
extern long NumLibrariesUsed;
extern ABLModulePtr LibrariesUsed[MAX_LIBRARIES_USED];
extern long bufferOffset;
extern char* bufferp;
extern char* tokenp;
extern long digitCount;
extern bool countError;
extern long pageNumber;
extern long lineCount;
// std::string currentParamList; // TODO: use this implementation or remove it
// std::string currentScriptSuffix;
#ifdef USE_OBJECTS
extern bool IsUnitOrder;
#else
bool IsUnitOrder = false;
#endif
#ifdef USE_OBJECTS
extern bool TacOrderOrigin;
extern MoverGroupPtr CurGroup;
extern GameObjectPtr CurObject;
extern long CurObjectClass;
extern MechWarriorPtr CurWarrior;
extern GameObjectPtr CurContact;
#endif
extern long CurAlarm;
extern bool eofFlag;
extern bool ExitWithReturn;
extern bool ExitFromTacOrder;
extern long dummyCount;
extern long lineNumber;
extern long FileNumber;
extern long errorCount;
extern long execStatementCount;
extern long NumSourceFiles;
extern char SourceFiles[MAX_SOURCE_FILES][MAXLEN_FILENAME];
extern TokenCodeType curToken;
extern char wordString[];
extern SymTableNodePtr symTableDisplay[];
extern long level;
extern bool blockFlag;
extern BlockType blockType;
extern bool printFlag;
extern SymTableNodePtr CurRoutineIdPtr;
extern Type DummyType;
extern StackItem* stack;
//extern StackItem* eternalStack;
extern StackItemPtr tos;
extern StackItemPtr stackFrameBasePtr;
extern long eternalOffset;
extern TokenCodeType statementStartList[];
extern TokenCodeType statementEndList[];
extern TokenCodeType declarationStartList[];
extern char tokenString[MAXLEN_TOKENSTRING];
extern CharCodeType charTable[256];
extern char sourceBuffer[MAXLEN_SOURCELINE];
extern long bufferOffset;
extern char* bufferp;
extern char* tokenp;
extern long digitCount;
extern bool countError;
extern bool eofFlag;
extern long pageNumber;
extern UserHeapPtr systemHeap;
extern UserHeapPtr AblSymTableHeap;
extern UserHeapPtr AblStackHeap;
extern UserHeapPtr AblCodeHeap;
extern SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL];
extern TypePtr IntegerTypePtr;
extern TypePtr RealTypePtr;
extern TypePtr BooleanTypePtr;
extern StackItemPtr StaticDataPtr;
extern StackItem returnValue;
extern ModuleEntryPtr ModuleRegistry;
extern long MaxModules;
extern long NumModulesRegistered;
extern long* StaticVariablesSizes;
extern long MaxStaticVariables;
extern long NumStaticVariables;
extern long NumSourceFiles;
extern bool IncludeDebugInfo;
extern bool AssertEnabled;
extern bool PrintEnabled;
extern bool StringFunctionsEnabled;
extern bool DebugCodeEnabled;
extern DebuggerPtr debugger;
extern bool parsingFSM;
bool ABLenabled = false;
bool g_ABLCreated = false;
char buffer[MAXLEN_PRINTLINE];
extern long CallStackLevel;
long numLibrariesLoaded = 0;
long NumExecutions = 0;
Profiler* g_Profiler = 0;
//***************************************************************************
TokenCodeType followHeaderList[] = {
TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType followModuleIdList[] = {
TKN_LPAREN,
TKN_COLON,
TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType followFunctionIdList[] = {
TKN_LPAREN,
TKN_COLON,
TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType followParamsList[] = {
TKN_RPAREN,
TKN_COMMA, //TKN_SEMICOLON,
TKN_EOF,
TKN_NONE
};
TokenCodeType followParamList[] = {
TKN_COMMA,
TKN_RPAREN,
TKN_NONE
};
TokenCodeType followModuleDeclsList[] = {
TKN_SEMICOLON,
TKN_CODE,
TKN_EOF,
TKN_NONE
};
TokenCodeType followRoutineDeclsList[] = {
TKN_SEMICOLON,
TKN_CODE,
TKN_EOF,
TKN_NONE
};
TokenCodeType followDeclsList[] = {
TKN_SEMICOLON,
//TKN_BEGIN,
TKN_EOF,
TKN_NONE
};
void ABL_CloseProfileLog (void);
void ABL_OpenProfileLog (void);
void ABL_AddToProfileLog (char* profileString);
//***************************************************************************
// ABL library interface routines
//***************************************************************************
void ABLi_init (unsigned long symTableHeapSize,
unsigned long stackHeapSize,
unsigned long codeHeapSize,
unsigned long runtimeStackSize,
unsigned long maxCodeBufferSize,
unsigned long maxRegisteredModules,
unsigned long maxStaticVariables,
void (*callback)(char* s),
bool debugInfo,
bool debug,
bool profile)
{
// HACK, for testing...
#ifdef _DEBUG
profile = true;
#endif
//
//-------------------------------------------------------------------
// Let's make sure we have not created too many built-in ABL routines
// for the lovely user...
g_ABLFunctions = new stlport::vector<ABLRoutineTableEntry *>;
g_ABLFunctions->assign (NUM_ABL_ROUTINES,NULL);
// if (NUM_ABL_ROUTINES > 254)
// ABL_Fatal(0, " MAJOR ABL ERROR: Too Many ABL Routines ");
ablError = NULL;
ABLenabled = true;
MaxBreaks = 50;
MaxWatches = 50;
debugger = NULL;
NumModules = 0;
ModuleRegistry = NULL;
ModuleInstanceRegistry = NULL;
LibraryInstanceRegistry = NULL;
MaxModules = 0;
MaxLibraries = 0;
NumModulesRegistered = 0;
NumModuleInstances = 0;
MaxWatchesPerModule = 20;
MaxBreakPointsPerModule = 20;
CurModule = NULL;
errorCount = 0;
codeBuffer = NULL;
codeBufferPtr = NULL;
codeSegmentPtr = NULL;
codeSegmentLimit = NULL;
statementStartPtr = NULL;
execStatementCount = 0;
stack = NULL;
tos = NULL;
stackFrameBasePtr = NULL;
StaticDataPtr = NULL;
StaticVariablesSizes = NULL;
EternalVariablesSizes = NULL;
MaxEternalVariables = 5000;
eternalOffset = 0;
MaxStaticVariables = 0;
NumStaticVariables = 0;
CurModuleHandle = 0;
CallModuleInit = false;
InOrdersBlock = false;
MaxLoopIterations = 100001;
AssertEnabled = false;
PrintEnabled = false;
StringFunctionsEnabled = true;
IncludeDebugInfo = true;
ProfileABL = profile;
Crunch = true;
AblSymTableHeap = NULL;
AblStackHeap = NULL;
AblCodeHeap = NULL;
level = 0;
lineNumber = 0;
FileNumber = 0;
sourceFile = NULL;
printFlag = true;
blockFlag = false;
blockType = BLOCK_MODULE;
CurModuleIdPtr = NULL;
CurRoutineIdPtr = NULL;
DumbGetCharOn = false;
NumOpenFiles = 0;
NumSourceFiles = 0;
bufferOffset = 0;
bufferp = sourceBuffer;
tokenp = tokenString;
digitCount = 0;
countError = false;
pageNumber = 0;
lineCount = MAX_LINES_PER_PAGE;
IsUnitOrder = false;
#ifdef USE_OBJECTS
TacOrderOrigin = ORDER_ORIGIN_COMMANDER;
#endif
eofFlag = false;
ExitWithReturn = false;
ExitFromTacOrder = false;
dummyCount = 0;
numLibrariesLoaded = 0;
AblSymTableHeap = new UserHeap;
long heapErr = AblSymTableHeap->init(symTableHeapSize,"ABL symbol table");
if (heapErr != NO_ERR)
{
//systemHeap->MemoryDump();
STOP(("unable to create ABL symbol table heap"));
}
AblStackHeap = new UserHeap;
heapErr = AblStackHeap->init(stackHeapSize,"ABL stack");
if (heapErr != NO_ERR)
{
//systemHeap->MemoryDump();
STOP(("unable to create ABL stack heap"));
}
AblCodeHeap = new UserHeap;
heapErr = AblCodeHeap->init(codeHeapSize,"ABL code");
if (heapErr != NO_ERR)
{
//systemHeap->MemoryDump();
STOP(("unable to create ABL code heap"));
}
//----------------------------------
// Initialize the character table...
for (long curCh = 0; curCh < 256; curCh++)
charTable[curCh] = CHR_SPECIAL;
for (curCh = '0'; curCh <= '9'; curCh++)
charTable[curCh] = CHR_DIGIT;
for (curCh = 'A'; curCh <= 'Z'; curCh++)
charTable[curCh] = CHR_LETTER;
for (curCh = 'a'; curCh <= 'z'; curCh++)
charTable[curCh] = CHR_LETTER;
charTable['\"'] = CHR_DQUOTE;
charTable[CHAR_EOF] = CHR_EOF;
//--------------------------------------------------------------------
// Allocate the code buffer used during pre-processing/interpreting...
MaxCodeBufferSize = maxCodeBufferSize;
codeBuffer = (char*)AblCodeHeap->Malloc(maxCodeBufferSize);
if (!codeBuffer)
ABL_Fatal(0, " ABL: Unable to AblCodeHeap->malloc preprocess code buffer ");
//----------------------------------------------------------------------
// Alloc the static variable data block. Ultimately, we may want to just
// implement the static data construction with a linked list, rather
// than a set max size...
MaxStaticVariables = maxStaticVariables;
NumStaticVariables = 0;
StaticDataPtr = NULL;
StaticVariablesSizes = NULL;
if (MaxStaticVariables > 0)
{
StaticVariablesSizes = (long*)AblStackHeap->Malloc(sizeof(long) * MaxStaticVariables);
if (!StaticVariablesSizes)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc StaticVariablesSizes ");
}
//------------------------------
// Allocate the runtime stack...
stack = (StackItemPtr)AblStackHeap->Malloc(sizeof(StackItem) * (runtimeStackSize / sizeof(StackItem)));
if (!stack)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc stack ");
//-----------------------------------
// Allocate Eternal Vars Size List...
if (MaxEternalVariables > 0)
{
EternalVariablesSizes = (long*)AblStackHeap->Malloc(sizeof(long) * MaxEternalVariables);
if (!EternalVariablesSizes)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc EternalVariablesSizes ");
}
//-------------------------
// Prep the symbol table...
initSymTable();
initModuleRegistry(maxRegisteredModules);
initLibraryRegistry(10);
//--------------------------------
// Init the debugger, if needed...
IncludeDebugInfo = debugInfo;
if (debug)
{
IncludeDebugInfo = true;
debugger = new Debugger;
if (!debugger)
ABL_Fatal(0, " Unable to initialize ABL Debugger. ");
debugger->init(callback, NULL);
}
//blurt UserFile::setup();
if (ProfileABL)
ABL_OpenProfileLog();
if (g_Profiler == 0)
{
g_Profiler = new Profiler;
}
g_ABLCreated = true;
//---------------------
// MC-specific stuff...
#ifdef USE_OBJECTS
CurGroup = NULL;
CurObject = NULL;
CurObjectClass = 0;
CurWarrior = NULL;
CurContact = NULL;
#endif
}
//***************************************************************************
void ABLi_VerifyStates (SymTableNodePtr node)
{
if (!node)
return;
ABLi_VerifyStates (node->left);
if ((node->defn.key == DFN_STATE) && (node->defn.info.routine.key==RTN_FORWARD))
syntaxError (ABL_ERR_SYNTAX_FORWARDED_STATE_NOT_DECLARED);
ABLi_VerifyStates (node->right);
}
//***************************************************************************
long ABLi_preProcess (char* sourceFileName, ABLError *err,long* numErrors, long* numLinesProcessed, long* numFilesProcessed, bool printLines)
{
//--------------------------------------------------------------------------------
// First, check if this module has already been registered into the environment...
for (long i = 0; i < NumModulesRegistered; i++)
if (strcmp(strlwr(sourceFileName), ModuleRegistry[i].fileName) == 0)
return(i);
ablError = err;
//---------------------------------
// Init some important variables...
parsingFSM = false;
level = 0;
lineNumber = 0;
FileNumber = 0;
AssertEnabled = (debugger != NULL);
PrintEnabled = (debugger != NULL);
StringFunctionsEnabled = true;
DebugCodeEnabled = (debugger != NULL);
NumSourceFiles = 0;
NumLibrariesUsed = 0;
sourceFile = NULL;
printFlag = printLines;
blockFlag = false;
blockType = BLOCK_MODULE;
bufferOffset = 0;
bufferp = sourceBuffer;
tokenp = tokenString;
digitCount = 0;
countError = false;
pageNumber = 0;
errorCount = 0;
execStatementCount = 0;
eofFlag = false;
NumStaticVariables = 0;
if (numErrors)
*numErrors = 0;
if (numLinesProcessed)
*numLinesProcessed = 0;
//---------------------------------------
// Now, let's open the ABL source file...
long openErr = NO_ERR;
if ((openErr = openSourceFile(sourceFileName)) != NO_ERR)
{
if (ablError)
{
ablError->String ("Unable to open file");
ablError->File (sourceFileName);
ablError->Line (0);
ablError->Code (openErr);
}
ablError = NULL;
return(openErr);
}
#pragma warning (disable:4611)
if (ablError)
{
if (setjmp (abl_jmp_buf))
{
closeSourceFile ();
ablError = NULL;
return -1;
}
}
#pragma warning (default:4611)
//------------------------
// Set up the code buffer.
codeBufferPtr = codeBuffer;
//------------------
// Get it rolling...
getToken();
SymTableNodePtr moduleIdPtr = moduleHeader();
CurModuleIdPtr = moduleIdPtr;
CurRoutineIdPtr = moduleIdPtr;
//---------------------
// Error synchronize...
synchronize(followHeaderList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
//-------------------------------------------------------------
// Parse the module's block. Use to call block(), now we do the
// stuff right here...
//block(moduleIdPtr);
declarations(moduleIdPtr, 1,parsingFSM ? 1: 0);
if (!parsingFSM)
{
synchronize(followModuleDeclsList, NULL, NULL);
if ((curToken != TKN_CODE) && (parsingFSM == false))
syntaxError(ABL_ERR_SYNTAX_MISSING_CODE);
else if ((curToken != TKN_STATE) && (parsingFSM == true))
syntaxError(ABL_ERR_SYNTAX_CODE_OUTSIDE_STATE_BLOCK);
crunchToken();
blockType = BLOCK_MODULE;
blockFlag = true;
getToken();
}
TokenCodeType endToken;
if (parsingFSM)
endToken = TKN_END_FSM;
else
endToken = ((CurLibrary == NULL) ? TKN_END_MODULE : TKN_END_LIBRARY);
if (curToken != endToken)
do
{
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == endToken)
break;
//------------------------------------
// Synchronize after possible error...
synchronize(statementStartList, NULL, NULL);
} while (tokenIn(statementStartList));
if (CurLibrary)
ifTokenGetElseError(TKN_END_LIBRARY, ABL_ERR_SYNTAX_MISSING_END_LIBRARY);
else if (parsingFSM)
ifTokenGetElseError(TKN_END_FSM, ABL_ERR_SYNTAX_MISSING_END_MODULE);
else
ifTokenGetElseError(TKN_END_MODULE, ABL_ERR_SYNTAX_MISSING_END_MODULE);
blockFlag = false;
moduleIdPtr->defn.info.routine.localSymTable = exitScope();
moduleIdPtr->defn.info.routine.codeSegment = createCodeSegment(moduleIdPtr->defn.info.routine.codeSegmentSize);
analyzeBlock(moduleIdPtr->defn.info.routine.codeSegment);
ifTokenGetElseError(TKN_PERIOD, ABL_ERR_SYNTAX_MISSING_PERIOD);
while (curToken != TKN_EOF)
{
syntaxError(ABL_ERR_SYNTAX_UNEXPECTED_TOKEN);
getToken();
}
//------------------------------------------
// Done with the source file, so close it...
closeSourceFile();
//------------------------------------------
// Verify that all states were declared
if (parsingFSM)
ABLi_VerifyStates (moduleIdPtr->defn.info.routine.localSymTable);
//extractSymTable(&SymTableDisplay[0], moduleIdPtr);
//--------------------------------------------------
// Register the new module in the ABL environment...
ModuleRegistry[NumModulesRegistered].fileName = (char*)AblStackHeap->Malloc(strlen(sourceFileName) + 1);
if (!ModuleRegistry[NumModulesRegistered].fileName)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module filename ");
strcpy(ModuleRegistry[NumModulesRegistered].fileName, strlwr(sourceFileName));
ModuleRegistry[NumModulesRegistered].moduleIdPtr = moduleIdPtr;
ModuleRegistry[NumModulesRegistered].numSourceFiles = NumSourceFiles;
ModuleRegistry[NumModulesRegistered].sourceFiles = (char**)AblStackHeap->Malloc(NumSourceFiles * sizeof(char*));
if (!ModuleRegistry[NumModulesRegistered].sourceFiles)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc sourceFiles ");
for (i = 0; i < NumSourceFiles; i++)
{
ModuleRegistry[NumModulesRegistered].sourceFiles[i] = (char*)AblStackHeap->Malloc(strlen(SourceFiles[i]) + 1);
strcpy(ModuleRegistry[NumModulesRegistered].sourceFiles[i], SourceFiles[i]);
}
if (NumLibrariesUsed > 0)
{
ModuleRegistry[NumModulesRegistered].numLibrariesUsed = NumLibrariesUsed;
ModuleRegistry[NumModulesRegistered].librariesUsed = (ABLModulePtr*)AblStackHeap->Malloc(NumLibrariesUsed * sizeof(SymTableNodePtr));
if (!ModuleRegistry[NumModulesRegistered].librariesUsed)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc librariesUsed ");
for (i = 0; i < NumLibrariesUsed; i++)
ModuleRegistry[NumModulesRegistered].librariesUsed[i] = LibrariesUsed[i];
}
ModuleRegistry[NumModulesRegistered].numStaticVars = NumStaticVariables;
ModuleRegistry[NumModulesRegistered].sizeStaticVars = NULL;
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = 0;
if (NumStaticVariables)
{
ModuleRegistry[NumModulesRegistered].sizeStaticVars = (long*)AblStackHeap->Malloc(sizeof(long) * NumStaticVariables);
if (!ModuleRegistry[NumModulesRegistered].sizeStaticVars)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module sizeStaticVars ");
memcpy(ModuleRegistry[NumModulesRegistered].sizeStaticVars, StaticVariablesSizes, sizeof(long) * NumStaticVariables);
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = sizeof(long) * NumStaticVariables;
for (long i = 0; i < ModuleRegistry[NumModulesRegistered].numStaticVars; i++)
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars += ModuleRegistry[NumModulesRegistered].sizeStaticVars[i];
}
ModuleRegistry[NumModulesRegistered].numInstances = 0;
NumModulesRegistered++;
//---------------------------------------------------------------
// Now, exit with the number of source lines processed, if any...
if (numLinesProcessed)
*numLinesProcessed = lineNumber;
if (numFilesProcessed)
*numFilesProcessed = FileNumber;
if (numErrors)
*numErrors = errorCount;
ablError = NULL;
return(NumModulesRegistered - 1);
}
//***************************************************************************
/*
long ABLi_preProcessFromParams(const std::string& params, const std::string& script_suffix)
{
ablError = 0;
//---------------------------------
// Init some important variables...
parsingFSM = false;
level = 0;
lineNumber = 0;
FileNumber = 0;
AssertEnabled = (debugger != NULL);
PrintEnabled = (debugger != NULL);
StringFunctionsEnabled = true;
DebugCodeEnabled = (debugger != NULL);
NumSourceFiles = 0;
NumLibrariesUsed = 0;
sourceFile = NULL;
blockFlag = false;
blockType = BLOCK_MODULE;
bufferOffset = 0;
bufferp = sourceBuffer;
tokenp = tokenString;
digitCount = 0;
countError = false;
pageNumber = 0;
errorCount = 0;
execStatementCount = 0;
eofFlag = false;
NumStaticVariables = 0;
std::string params_copy(params);
std::string source_file_name("Content\\ABLScripts\\GenericScripts\\");
while (params_copy[0] != ',')
{
source_file_name += params_copy[0];
params_copy.erase(0,1);
}
params_copy.erase(0,1);
//---------------------------------------
// Now, let's open the ABL source file...
long openErr = NO_ERR;
currentParamList = params_copy;
currentScriptSuffix = script_suffix;
if ((openErr = openSourceFile((char*)source_file_name.c_str())) != NO_ERR)
{
if (ablError)
{
ablError->String ("Unable to open file");
ablError->File (source_file_name.c_str());
ablError->Line (0);
ablError->Code (openErr);
}
ablError = NULL;
currentParamList.erase(currentParamList.begin(),currentParamList.end());
currentScriptSuffix.erase(currentScriptSuffix.begin(),currentScriptSuffix.end());
return(openErr);
}
currentParamList.erase(currentParamList.begin(),currentParamList.end());
currentScriptSuffix.erase(currentScriptSuffix.begin(),currentScriptSuffix.end());
#pragma warning (disable:4611)
if (ablError)
{
if (setjmp (abl_jmp_buf))
{
closeSourceFile ();
ablError = NULL;
return -1;
}
}
#pragma warning (default:4611)
//------------------------
// Set up the code buffer.
codeBufferPtr = codeBuffer;
//------------------
// Get it rolling...
getToken();
SymTableNodePtr moduleIdPtr = moduleHeader();
CurModuleIdPtr = moduleIdPtr;
CurRoutineIdPtr = moduleIdPtr;
//---------------------
// Error synchronize...
synchronize(followHeaderList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
//-------------------------------------------------------------
// Parse the module's block. Use to call block(), now we do the
// stuff right here...
//block(moduleIdPtr);
declarations(moduleIdPtr, 1,parsingFSM ? 1: 0);
if (!parsingFSM)
{
synchronize(followModuleDeclsList, NULL, NULL);
if ((curToken != TKN_CODE) && (parsingFSM == false))
syntaxError(ABL_ERR_SYNTAX_MISSING_CODE);
else if ((curToken != TKN_STATE) && (parsingFSM == true))
syntaxError(ABL_ERR_SYNTAX_CODE_OUTSIDE_STATE_BLOCK);
crunchToken();
blockType = BLOCK_MODULE;
blockFlag = true;
getToken();
}
TokenCodeType endToken;
if (parsingFSM)
endToken = TKN_END_FSM;
else
endToken = ((CurLibrary == NULL) ? TKN_END_MODULE : TKN_END_LIBRARY);
if (curToken != endToken)
do
{
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == endToken)
break;
//------------------------------------
// Synchronize after possible error...
synchronize(statementStartList, NULL, NULL);
} while (tokenIn(statementStartList));
if (CurLibrary)
ifTokenGetElseError(TKN_END_LIBRARY, ABL_ERR_SYNTAX_MISSING_END_LIBRARY);
else if (parsingFSM)
ifTokenGetElseError(TKN_END_FSM, ABL_ERR_SYNTAX_MISSING_END_MODULE);
else
ifTokenGetElseError(TKN_END_MODULE, ABL_ERR_SYNTAX_MISSING_END_MODULE);
blockFlag = false;
moduleIdPtr->defn.info.routine.localSymTable = exitScope();
moduleIdPtr->defn.info.routine.codeSegment = createCodeSegment(moduleIdPtr->defn.info.routine.codeSegmentSize);
analyzeBlock(moduleIdPtr->defn.info.routine.codeSegment);
ifTokenGetElseError(TKN_PERIOD, ABL_ERR_SYNTAX_MISSING_PERIOD);
// while (curToken != TKN_EOF)
// {
// syntaxError(ABL_ERR_SYNTAX_UNEXPECTED_TOKEN);
// getToken();
// }
//------------------------------------------
// Done with the source file, so close it...
closeSourceFile();
//------------------------------------------
// Verify that all states were declared
if (parsingFSM)
ABLi_VerifyStates (moduleIdPtr->defn.info.routine.localSymTable);
//extractSymTable(&SymTableDisplay[0], moduleIdPtr);
//--------------------------------------------------
// Register the new module in the ABL environment...
ModuleRegistry[NumModulesRegistered].fileName = (char*)AblStackHeap->Malloc(strlen((char*)source_file_name.c_str()) + 1);
if (!ModuleRegistry[NumModulesRegistered].fileName)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module filename ");
strcpy(ModuleRegistry[NumModulesRegistered].fileName, strlwr((char*)source_file_name.c_str()));
ModuleRegistry[NumModulesRegistered].moduleIdPtr = moduleIdPtr;
ModuleRegistry[NumModulesRegistered].numSourceFiles = NumSourceFiles;
ModuleRegistry[NumModulesRegistered].sourceFiles = (char**)AblStackHeap->Malloc(NumSourceFiles * sizeof(char*));
if (!ModuleRegistry[NumModulesRegistered].sourceFiles)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc sourceFiles ");
for (long i = 0; i < NumSourceFiles; i++)
{
ModuleRegistry[NumModulesRegistered].sourceFiles[i] = (char*)AblStackHeap->Malloc(strlen(SourceFiles[i]) + 1);
strcpy(ModuleRegistry[NumModulesRegistered].sourceFiles[i], SourceFiles[i]);
}
if (NumLibrariesUsed > 0)
{
ModuleRegistry[NumModulesRegistered].numLibrariesUsed = NumLibrariesUsed;
ModuleRegistry[NumModulesRegistered].librariesUsed = (ABLModulePtr*)AblStackHeap->Malloc(NumLibrariesUsed * sizeof(SymTableNodePtr));
if (!ModuleRegistry[NumModulesRegistered].librariesUsed)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc librariesUsed ");
for (i = 0; i < NumLibrariesUsed; i++)
ModuleRegistry[NumModulesRegistered].librariesUsed[i] = LibrariesUsed[i];
}
ModuleRegistry[NumModulesRegistered].numStaticVars = NumStaticVariables;
ModuleRegistry[NumModulesRegistered].sizeStaticVars = NULL;
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = 0;
if (NumStaticVariables)
{
ModuleRegistry[NumModulesRegistered].sizeStaticVars = (long*)AblStackHeap->Malloc(sizeof(long) * NumStaticVariables);
if (!ModuleRegistry[NumModulesRegistered].sizeStaticVars)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module sizeStaticVars ");
memcpy(ModuleRegistry[NumModulesRegistered].sizeStaticVars, StaticVariablesSizes, sizeof(long) * NumStaticVariables);
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars = sizeof(long) * NumStaticVariables;
for (long i = 0; i < ModuleRegistry[NumModulesRegistered].numStaticVars; i++)
ModuleRegistry[NumModulesRegistered].totalSizeStaticVars += ModuleRegistry[NumModulesRegistered].sizeStaticVars[i];
}
ModuleRegistry[NumModulesRegistered].numInstances = 0;
NumModulesRegistered++;
ablError = NULL;
return(NumModulesRegistered - 1);
}
*/
//***************************************************************************
long ABLi_execute (SymTableNodePtr moduleIdPtr, SymTableNodePtr functionIdPtr, ABLParamPtr paramList, StackItemPtr returnVal)
{
//insertSymTable(&SymTableDisplay[0], moduleIdPtr);
//--------------------------
// Execute the ABL module...
//----------------------------------------------------------------------------------
// NOTE: Ultimately, we want the ABL virtual machine to be set up once, and then
// ABL modules/routines can be called multiple times from within a program. For now,
// to test, let's just assume every time we run a module, it is a self-contained
// ABL program.
//---------------------------------
// Init some important variables...
//lineNumber = 0;
//printFlag = true;
//blockFlag = false;
//blockType = BLOCK_MODULE;
CurModuleIdPtr = NULL;
CurRoutineIdPtr = NULL;
//bufferOffset = 0;
//bufferp = sourceBuffer;
//tokenp = tokenString;
//digitCount = 0;
//countError = false;
errorCount = 0;
execStatementCount = 0;
NumExecutions++;
//------------------
// Init the stack...
stackFrameBasePtr = tos = (stack + eternalOffset);
//---------------------------------------
// Initialize the module's stack frame...
level = 1;
CallStackLevel = 0;
stackFrameBasePtr = tos + 1;
//-------------------------
// Function return value...
pushInteger(0);
//---------------
// Static Link...
pushAddress(NULL);
//----------------
// Dynamic Link...
pushAddress(NULL);
//------------------
// Return Address...
pushAddress(NULL);
//initDebugger();
//----------
// Run it...
if (paramList)
{
//------------------------------------------------------------------------------
// NOTE: Currently, parameter passing of arrays is not functioning. This MUST be
// done...
long curParam = 0;
for (SymTableNodePtr formalIdPtr = (SymTableNodePtr)(moduleIdPtr->defn.info.routine.params);
formalIdPtr != NULL;
formalIdPtr = formalIdPtr->next)
{
TypePtr formalTypePtr = (TypePtr)(formalIdPtr->typePtr);
if (formalIdPtr->defn.key == DFN_VALPARAM)
{
if (formalTypePtr == RealTypePtr)
{
if (paramList[curParam].type == ABL_PARAM_INTEGER)
{
//---------------------------------------------
// Real formal parameter, but integer actual...
pushReal((float)(paramList[curParam].integer));
}
else if (paramList[curParam].type == ABL_PARAM_REAL)
pushReal(paramList[curParam].real);
}
else if (formalTypePtr == IntegerTypePtr)
{
if (paramList[curParam].type== ABL_PARAM_INTEGER)
pushInteger(paramList[curParam].integer);
else
return(0);
}
//----------------------------------------------------------
// Formal parameter is an array or record, so make a copy...
if ((formalTypePtr->form == FRM_ARRAY)/* || (formalTypePtr->form == FRM_RECORD)*/)
{
//------------------------------------------------------------------------------
// The following is a little inefficient, but is kept this way to keep it clear.
// Once it's verified to work, optimize...
long size = formalTypePtr->size;
char* dest = (char*)AblStackHeap->Malloc((size_t)size);
if (!dest)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc module formal array param ");
char* src = tos->address;
char* savePtr = dest;
memcpy(dest, src, size);
tos->address = savePtr;
}
}
else
{
//-------------------------------
// pass by reference parameter...
if (formalTypePtr == RealTypePtr)
pushAddress((Address)&(paramList[curParam].real));
else if (formalTypePtr == IntegerTypePtr)
pushAddress((Address)&(paramList[curParam].integer));
else
return(0);
//SymTableNodePtr idPtr = getCodeSymTableNodePtr();
//execVariable(idPtr, USE_REFPARAM);
}
curParam++;
}
}
execute(moduleIdPtr);
if (returnVal)
memcpy(returnVal, &returnValue, sizeof(StackItem));
//extractSymTable(&SymTableDisplay[0], moduleIdPtr);
//-----------
// Summary...
return(execStatementCount);
}
//***************************************************************************
long ABLi_deleteModule (SymTableNodePtr moduleIdPtr)
{
return(NO_ERR);
}
//***************************************************************************
void ABLi_close (void)
{
if (!g_ABLCreated)
return;
if (g_Profiler != 0)
{
delete g_Profiler;
g_Profiler = 0;
}
//blurt UserFile::cleanup();
destroyModuleRegistry();
destroyLibraryRegistry();
stlport::vector<ABLRoutineTableEntry *>::iterator iter;
for (iter = g_ABLFunctions->begin ();iter < g_ABLFunctions->end ();iter++)
{
delete (*iter);
}
delete g_ABLFunctions;
if (StaticVariablesSizes)
{
AblStackHeap->Free(StaticVariablesSizes);
StaticVariablesSizes = NULL;
}
if (EternalVariablesSizes)
{
AblStackHeap->Free(EternalVariablesSizes);
EternalVariablesSizes = NULL;
}
if (codeBuffer)
{
AblCodeHeap->Free(codeBuffer);
codeBuffer = NULL;
}
if (stack)
{
AblStackHeap->Free(stack);
stack = NULL;
}
if (debugger)
{
delete debugger;
debugger = NULL;
}
if (AblSymTableHeap)
{
delete AblSymTableHeap;
AblSymTableHeap = NULL;
}
if (AblStackHeap)
{
delete AblStackHeap;
AblStackHeap = NULL;
}
if (AblCodeHeap)
{
delete AblCodeHeap;
AblCodeHeap = NULL;
}
ABL_CloseProfileLog();
ABLenabled = false;
g_ABLCreated = false;
}
//***************************************************************************
long ABLi_loadLibrary (char* sourceFileName, ABLError *ablerr, long* numErrors, long* numLinesProcessed, long* numFilesProcessed, bool printLines)
{
//--------------------------------------------------------------------
// Create an instance of it so it may be used from other modules. Note
// that we need this when preprocessing since all identifiers in the
// library should point to this module...
ABLModulePtr library = new ABLModule;
if (!library)
return(-2/*NO_RAM_FOR_ABL*/);
CurLibrary = library;
//-------------------------------------------------------------
// Preprocess the library. Note that a library should be loaded
// just once.
long libraryHandle = ABLi_preProcess(sourceFileName, ablerr,numErrors, numLinesProcessed, numFilesProcessed, printLines);
if (libraryHandle < (NumModulesRegistered - 1))
{
//------------------
// Already loaded...
delete library;
library = NULL;
CurLibrary = NULL;
return(-1);
}
long err = library->init(libraryHandle);
ABL_Assert(err == NO_ERR, err, " Error Loading ABL Library ");
library->setName(sourceFileName);
CurLibrary = NULL;
LibraryInstanceRegistry[numLibrariesLoaded] = library;
numLibrariesLoaded++;
ablError = NULL;
return(NO_ERR);
}
//***************************************************************************
ABLParamPtr ABLi_createParamList (long numParameters)
{
if (numParameters)
{
ABLParamPtr paramList = (ABLParamPtr)AblStackHeap->Malloc(sizeof(ABLParam) * (numParameters + 1));
if (!paramList)
ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc paramList ");
memset(paramList, 0, sizeof(ABLParam) * (numParameters + 1));
return(paramList);
}
return(NULL);
}
//***************************************************************************
void ABLi_setIntegerParam (ABLParamPtr paramList, long index, long value)
{
if (paramList)
{
paramList[index].type = ABL_PARAM_INTEGER;
paramList[index].integer = value;
}
}
//***************************************************************************
void ABLi_setRealParam (ABLParamPtr paramList, long index, float value)
{
if (paramList)
{
paramList[index].type = ABL_PARAM_REAL;
paramList[index].real = value;
}
}
//***************************************************************************
void ABLi_deleteParamList (ABLParamPtr paramList)
{
if (paramList)
AblStackHeap->Free(paramList);
}
//***************************************************************************
ABLModulePtr ABLi_getModule (long id)
{
if ((id >= 0) && (id < NumModules))
return(ModuleInstanceRegistry[id]);
return(NULL);
}
//***************************************************************************
bool ABLi_enabled (void)
{
return(ABLenabled);
}
//***************************************************************************
// MODULE routines
//***************************************************************************
SymTableNodePtr moduleHeader (void)
{
SymTableNodePtr moduleIdPtr = NULL;
if (CurLibrary)
ifTokenGetElseError(TKN_LIBRARY, ABL_ERR_SYNTAX_MISSING_LIBRARY);
else
{
if (curToken == TKN_MODULE)
{
parsingFSM = false;
getToken ();
}
else if (curToken == TKN_FSM)
{
parsingFSM = true;
getToken ();
}
else
{
syntaxError(ABL_ERR_SYNTAX_MISSING_MODULE);
}
}
//------------------------------------------------------------
// NOTE: If a module is a library, its library pointer will be
// non-NULL.
if (curToken == TKN_IDENTIFIER)
{
searchAndEnterLocalSymTable(moduleIdPtr);
if (parsingFSM)
moduleIdPtr->defn.key = DFN_FSM;
else
moduleIdPtr->defn.key = DFN_MODULE;
moduleIdPtr->defn.info.routine.key = RTN_DECLARED;
moduleIdPtr->defn.info.routine.paramCount = 0;
moduleIdPtr->defn.info.routine.totalParamSize = 0;
moduleIdPtr->defn.info.routine.totalLocalSize = 0;
moduleIdPtr->defn.info.routine.params = NULL;
moduleIdPtr->defn.info.routine.locals = NULL;
moduleIdPtr->defn.info.routine.localSymTable = NULL;
moduleIdPtr->defn.info.routine.codeSegment = NULL;
moduleIdPtr->library = CurLibrary;
moduleIdPtr->typePtr = &DummyType;
moduleIdPtr->labelIndex = 0;
getToken();
}
else
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
//--------------------------------------------
// For now, modules do not have param lists...
synchronize(followModuleIdList, declarationStartList, statementStartList);
enterScope(NULL);
if (parsingFSM)
{
FSMLevel = level;
}
if (curToken == TKN_LPAREN)
{
long paramCount;
long totalParamSize;
SymTableNodePtr paramListPtr = formalParamList(&paramCount, &totalParamSize);
//if (forwardFlag)
// syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED);
//else {
moduleIdPtr->defn.info.routine.paramCount = (unsigned char) paramCount;
moduleIdPtr->defn.info.routine.totalParamSize = (unsigned char) totalParamSize;
moduleIdPtr->defn.info.routine.params = paramListPtr;
//}
}
//else if (!forwardFlag) {
// functionIdPtr->defn.info.routine.paramCount = 0;
// functionIdPtr->defn.info.routine.totalParamSize = 0;
// functionIdPtr->defn.info.routine.params = NULL;
//}
//-----------------------------
// Now, check if return type...
moduleIdPtr->typePtr = NULL;
SymTableNodePtr typeIdPtr = NULL;
if (curToken == TKN_COLON)
{
getToken();
if (curToken == TKN_IDENTIFIER)
{
searchAndFindAllSymTables(typeIdPtr);
if (typeIdPtr->defn.key != DFN_TYPE)
syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE);
//if (!forwardFlag)
moduleIdPtr->typePtr = typeIdPtr->typePtr;
getToken();
}
else
{
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
moduleIdPtr->typePtr = &DummyType;
}
//if (forwardFlag)
// syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED);
}
return(moduleIdPtr);
}
//***************************************************************************
// ROUTINE/FUNCTION routines
//***************************************************************************
void routine (void)
{
SymTableNodePtr routineIdPtr = NULL;
//------------------------------------------------------------------------
// Do we want to have "procedures", or do functions handle both cases (with
// and without return values)? For now, functions handle both...
routineIdPtr = functionHeader();
//------------------------------------------------------------------
// We need to save a pointer to the current routine we're parsing...
SymTableNodePtr prevRoutineIdPtr = CurRoutineIdPtr;
CurRoutineIdPtr = routineIdPtr;
//---------------------
// Error synchronize...
synchronize(followHeaderList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
if ((strcmp(wordString, "forward") != 0) && (strcmp(wordString, "extern") != 0))
{
routineIdPtr->defn.info.routine.key = RTN_DECLARED;
//analyzeRoutineHeader(routineIdPtr);
routineIdPtr->defn.info.routine.locals = NULL;
//--------------------------------------------------------------
// Parse the routine's block. Use to call block(), now we do the
// stuff right here...
//block(routineIdPtr);
declarations(routineIdPtr, 0, 0);
synchronize(followRoutineDeclsList, NULL, NULL);
if (curToken != TKN_CODE)
syntaxError(ABL_ERR_SYNTAX_MISSING_CODE);
crunchToken();
blockType = BLOCK_ROUTINE;
blockFlag = true;
//compoundStatement();
getToken();
if (curToken != TKN_END_FUNCTION)
do
{
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_FUNCTION)
break;
//------------------------------------
// Synchronize after possible error...
synchronize(statementStartList, NULL, NULL);
} while (tokenIn(statementStartList));
ifTokenGetElseError(TKN_END_FUNCTION, ABL_ERR_SYNTAX_MISSING_END_FUNCTION);
blockFlag = false;
ABL::TokenCodeType ttoken = curToken;
curToken = TKN_NONE;
crunchToken ();
curToken = ttoken;
routineIdPtr->defn.info.routine.codeSegment = createCodeSegment(routineIdPtr->defn.info.routine.codeSegmentSize);
analyzeBlock(routineIdPtr->defn.info.routine.codeSegment);
}
else if (strcmp (wordString,"forward") == 0)
{
getToken();
routineIdPtr->defn.info.routine.key = RTN_FORWARD;
analyzeRoutineHeader(routineIdPtr);
}
else
{
getToken();
routineIdPtr->defn.info.routine.key = RTN_EXTERN;
analyzeRoutineHeader(routineIdPtr);
}
routineIdPtr->defn.info.routine.localSymTable = exitScope();
CurRoutineIdPtr = prevRoutineIdPtr;
}
//***************************************************************************
SymTableNodePtr functionHeader (void)
{
getToken();
SymTableNodePtr functionIdPtr = NULL;
SymTableNodePtr typeIdPtr = NULL;
bool forwardFlag = false;
if (curToken == TKN_IDENTIFIER)
{
searchLocalSymTable(functionIdPtr);
if (!functionIdPtr)
{
enterLocalSymTable(functionIdPtr);
functionIdPtr->defn.key = DFN_FUNCTION;
functionIdPtr->defn.info.routine.key = RTN_DECLARED;
functionIdPtr->defn.info.routine.paramCount = 0;
functionIdPtr->defn.info.routine.totalParamSize = 0;
functionIdPtr->defn.info.routine.totalLocalSize = 0;
functionIdPtr->defn.info.routine.params = NULL;
functionIdPtr->defn.info.routine.locals = NULL;
functionIdPtr->defn.info.routine.localSymTable = NULL;
functionIdPtr->defn.info.routine.codeSegment = NULL;
functionIdPtr->library = CurLibrary;
functionIdPtr->typePtr = &DummyType;
functionIdPtr->labelIndex = 0;
}
else if ((functionIdPtr->defn.key == DFN_FUNCTION) && (functionIdPtr->defn.info.routine.key == RTN_FORWARD))
forwardFlag = true;
else if ((functionIdPtr->defn.key == DFN_FUNCTION) && (functionIdPtr->defn.info.routine.key == RTN_EXTERN))
syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
else
syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
getToken();
}
//---------------------
// Error synchronize...
synchronize(followFunctionIdList, declarationStartList, statementStartList);
enterScope(NULL);
if (curToken == TKN_LPAREN)
{
long paramCount;
long totalParamSize;
SymTableNodePtr paramListPtr = formalParamList(&paramCount, &totalParamSize);
if (forwardFlag)
syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED);
else
{
functionIdPtr->defn.info.routine.paramCount = (unsigned char) paramCount;
functionIdPtr->defn.info.routine.totalParamSize = (unsigned char) totalParamSize;
functionIdPtr->defn.info.routine.params = paramListPtr;
}
}
else if (!forwardFlag)
{
functionIdPtr->defn.info.routine.paramCount = 0;
functionIdPtr->defn.info.routine.totalParamSize = 0;
functionIdPtr->defn.info.routine.params = NULL;
}
//--------------------------------------------
// Now, check if return type and/or forward...
functionIdPtr->typePtr = NULL;
if (curToken == TKN_COLON)
{
getToken();
if (curToken == TKN_IDENTIFIER)
{
searchAndFindAllSymTables(typeIdPtr);
if (typeIdPtr->defn.key != DFN_TYPE)
syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE);
if (!forwardFlag)
functionIdPtr->typePtr = typeIdPtr->typePtr;
getToken();
}
else
{
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
functionIdPtr->typePtr = &DummyType;
}
if (forwardFlag)
syntaxError(ABL_ERR_SYNTAX_ALREADY_FORWARDED);
}
return(functionIdPtr);
}
//***************************************************************************
SymTableNodePtr formalParamList (long* count, long* totalSize)
{
SymTableNodePtr paramIdPtr;
SymTableNodePtr firstIdPtr;
SymTableNodePtr lastIdPtr = NULL;
SymTableNodePtr paramListPtr = NULL;
SymTableNodePtr typeIdPtr;
TypePtr paramTypePtr;
DefinitionType paramDefn;
long paramCount = 0;
long paramOffset = STACK_FRAME_HEADER_SIZE;
getToken();
while ((curToken == TKN_IDENTIFIER) || (curToken == TKN_REF))
{
firstIdPtr = NULL;
if (curToken == TKN_REF)
{
paramDefn = DFN_REFPARAM;
getToken();
}
else
paramDefn = DFN_VALPARAM;
//-----------------------------------
// Grab the type of this parameter...
if (curToken == TKN_IDENTIFIER)
{
searchAndFindAllSymTables(typeIdPtr);
if (typeIdPtr->defn.key != DFN_TYPE)
syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE);
paramTypePtr = (TypePtr)(typeIdPtr->typePtr);
getToken();
}
else
{
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
paramTypePtr = &DummyType;
}
//------------------------------------------------------------
// Is this an array parameter? If so, parse the dimensions and
// whether it's an open array...
if (curToken == TKN_LBRACKET)
{
}
//-----------------------------------------------
// Now grab the variable id for this parameter...
if (curToken == TKN_IDENTIFIER)
{
searchAndEnterLocalSymTable(paramIdPtr);
paramIdPtr->defn.key = paramDefn;
paramIdPtr->labelIndex = 0;
paramIdPtr->typePtr = paramTypePtr;
paramIdPtr->defn.info.data.offset = paramOffset++;
paramCount++;
if (paramListPtr == NULL)
paramListPtr = paramIdPtr;
if (lastIdPtr != NULL)
lastIdPtr->next = paramIdPtr;
lastIdPtr = paramIdPtr;
//if (firstIdPtr == NULL)
// firstIdPtr = lastIdPtr = paramIdPtr;
//else {
// lastIdPtr->next = paramIdPtr;
// lastIdPtr = paramIdPtr;
//}
getToken();
//ifTokenGet(TKN_COMMA);
}
else
{
syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
//--------------------------------
// Do we need to synchronize here?
}
//------------------------------------------------------------------
// Assign the offset and the type to all param ids in the sublist...
//for (paramIdPtr = firstIdPtr; paramIdPtr != NULL; paramIdPtr = paramIdPtr->next) {
// paramIdPtr->typePtr = paramTypePtr;
// paramIdPtr->defn.info.data.offset = paramOffset++;
//}
//-----------------------------------------------
// Link this list to the list of all param ids...
//if (prevLastIdPtr != NULL)
// prevLastIdPtr->next = firstIdPtr;
//prevLastIdPtr = lastIdPtr;
//-------------------------------
// Error synch... should be ; or )
synchronize(followParamsList, NULL, NULL);
ifTokenGet(TKN_COMMA);
}
ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN);
*count = paramCount;
*totalSize = paramOffset - STACK_FRAME_HEADER_SIZE;
if (paramCount > 255)
syntaxError(ABL_ERR_SYNTAX_TOO_MANY_FORMAL_PARAMETERS);
return(paramListPtr);
}
//***************************************************************************
TypePtr routineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag)
{
SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
TypePtr resultType = NULL;
if ((routineIdPtr->defn.info.routine.key == RTN_DECLARED) ||
(routineIdPtr->defn.info.routine.key == RTN_FORWARD) ||
(routineIdPtr->defn.info.routine.key == RTN_EXTERN) ||
!paramCheckFlag)
resultType = declaredRoutineCall(routineIdPtr, paramCheckFlag);
else
resultType = standardRoutineCall(routineIdPtr);
CurRoutineIdPtr = thisRoutineIdPtr;
return(resultType);
}
//***************************************************************************
TypePtr declaredRoutineCall (SymTableNodePtr routineIdPtr, long paramCheckFlag)
{
actualParamList(routineIdPtr, paramCheckFlag);
return(/*routineIdPtr->defn.key == DFN_PROCEDURE ? NULL :*/ (TypePtr)(routineIdPtr->typePtr));
}
//***************************************************************************
void actualParamList (SymTableNodePtr routineIdPtr, long paramCheckFlag)
{
SymTableNodePtr formalParamIdPtr = NULL;
DefinitionType formalParamDefn = (DefinitionType)0;
TypePtr formalParamTypePtr = NULL;
TypePtr actualParamTypePtr = NULL;
if (paramCheckFlag)
formalParamIdPtr = (SymTableNodePtr)(routineIdPtr->defn.info.routine.params);
if (curToken == TKN_LPAREN)
{
//-----------------------------------------------
// Loop to process actual parameter expression...
do
{
//----------------------------------------------------
// Obtain info about the corresponding formal param...
if (paramCheckFlag && (formalParamIdPtr != NULL))
{
formalParamDefn = formalParamIdPtr->defn.key;
formalParamTypePtr = (TypePtr)(formalParamIdPtr->typePtr);
}
getToken();
if ((formalParamIdPtr == NULL) || (formalParamDefn == DFN_VALPARAM) || !paramCheckFlag)
{
//--------------
// VAL Params...
actualParamTypePtr = expression();
if (paramCheckFlag && (formalParamIdPtr != NULL) && !isAssignTypeCompatible(formalParamTypePtr, actualParamTypePtr))
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
}
else
{
//--------------
// VAR params...
if (curToken == TKN_IDENTIFIER)
{
SymTableNodePtr idPtr;
searchAndFindAllSymTables(idPtr);
actualParamTypePtr = variable(idPtr);
if (formalParamTypePtr != actualParamTypePtr)
syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
}
else
{
//------------------------------------------------------------------
// Not a variable--parse the expression anyway for error recovery...
actualParamTypePtr = expression();
syntaxError(ABL_ERR_SYNTAX_INVALID_REF_PARAM);
}
}
//---------------------------------------
// More actual params than formal params?
if (paramCheckFlag)
{
if (formalParamIdPtr == NULL)
syntaxError(ABL_ERR_SYNTAX_WRONG_NUMBER_OF_PARAMS);
else
formalParamIdPtr = formalParamIdPtr->next;
}
//---------------
// Error synch...
synchronize(followParamList, statementEndList, NULL);
} while (curToken == TKN_COMMA);
ifTokenGetElseError(TKN_RPAREN, ABL_ERR_SYNTAX_MISSING_RPAREN);
}
//----------------------------------------
// Fewer actual params than formal params?
if (paramCheckFlag && (formalParamIdPtr != NULL))
syntaxError(ABL_ERR_SYNTAX_WRONG_NUMBER_OF_PARAMS);
}
//***************************************************************************
//***************************************************************************
// State routines
//***************************************************************************
void state (void)
{
SymTableNodePtr routineIdPtr = NULL;
//------------------------------------------------------------------------
// Do we want to have "procedures", or do functions handle both cases (with
// and without return values)? For now, functions handle both...
routineIdPtr = stateHeader();
//------------------------------------------------------------------
// We need to save a pointer to the current routine we're parsing...
SymTableNodePtr prevRoutineIdPtr = CurRoutineIdPtr;
CurRoutineIdPtr = routineIdPtr;
//---------------------
// Error synchronize...
synchronize(followHeaderList, declarationStartList, statementStartList);
if (curToken == TKN_SEMICOLON)
getToken();
else if (tokenIn(declarationStartList) || tokenIn(statementStartList))
syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
if (strcmp(wordString, "forward") != 0)
{
routineIdPtr->defn.info.routine.key = RTN_DECLARED;
//analyzeRoutineHeader(routineIdPtr);
routineIdPtr->defn.info.routine.locals = NULL;
//--------------------------------------------------------------
// Parse the routine's block. Use to call block(), now we do the
// stuff right here...
//block(routineIdPtr);
declarations(routineIdPtr, 0, 0);
synchronize(followRoutineDeclsList, NULL, NULL);
if (curToken != TKN_CODE)
syntaxError(ABL_ERR_SYNTAX_MISSING_CODE);
crunchToken();
blockType = BLOCK_ROUTINE;
blockFlag = true;
//compoundStatement();
getToken();
if (curToken != TKN_END_STATE)
do
{
statement();
while (curToken == TKN_SEMICOLON)
getToken();
if (curToken == TKN_END_STATE)
break;
//------------------------------------
// Synchronize after possible error...
synchronize(statementStartList, NULL, NULL);
} while (tokenIn(statementStartList));
ifTokenGetElseError(TKN_END_STATE, ABL_ERR_SYNTAX_MISSING_END_STATE);
blockFlag = false;
ABL::TokenCodeType ttoken = curToken;
curToken = TKN_NONE;
crunchToken ();
curToken = ttoken;
routineIdPtr->defn.info.routine.codeSegment = createCodeSegment(routineIdPtr->defn.info.routine.codeSegmentSize);
analyzeBlock(routineIdPtr->defn.info.routine.codeSegment);
}
else
{
getToken();
routineIdPtr->defn.info.routine.key = RTN_FORWARD;
analyzeRoutineHeader(routineIdPtr);
}
routineIdPtr->defn.info.routine.localSymTable = exitScope();
CurRoutineIdPtr = prevRoutineIdPtr;
}
//***************************************************************************
SymTableNodePtr stateHeader (void)
{
getToken();
SymTableNodePtr functionIdPtr = NULL;
if (curToken == TKN_IDENTIFIER)
{
searchLocalSymTable(functionIdPtr);
if (!functionIdPtr)
{
enterLocalSymTable(functionIdPtr);
functionIdPtr->defn.key = DFN_STATE;
functionIdPtr->defn.info.routine.key = RTN_DECLARED;
functionIdPtr->defn.info.routine.paramCount = 0;
functionIdPtr->defn.info.routine.totalParamSize = 0;
functionIdPtr->defn.info.routine.totalLocalSize = 0;
functionIdPtr->defn.info.routine.params = NULL;
functionIdPtr->defn.info.routine.locals = NULL;
functionIdPtr->defn.info.routine.localSymTable = NULL;
functionIdPtr->defn.info.routine.codeSegment = NULL;
functionIdPtr->library = CurLibrary;
functionIdPtr->typePtr = &DummyType;
functionIdPtr->labelIndex = 0;
}
else if ((functionIdPtr->defn.key == DFN_STATE) && (functionIdPtr->defn.info.routine.key == RTN_FORWARD))
{
}
else
syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
getToken();
}
//---------------------
// Error synchronize...
synchronize(followFunctionIdList, declarationStartList, statementStartList);
enterScope(NULL);
return(functionIdPtr);
}
}