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.
2004 lines
58 KiB
C++
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(¶mCount, &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(¶mCount, &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);
|
|
}
|
|
|
|
} |