void constDefinitions (void) { //------------------------------------------------------- // Loop to process definitions separated by semicolons... while (curToken == TKN_IDENTIFIER) { SymTableNodePtr constantIdPtr; searchAndEnterLocalSymTable(constantIdPtr); constantIdPtr->defn.key = DFN_CONST; constantIdPtr->library = CurLibrary; getToken(); ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL); doConst(constantIdPtr); analyzeConstDefn(constantIdPtr); //--------------------------------- // Error synchronize: should be a ; synchronize(followDeclarationList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); } }
void typeDefinitions (void) { while (curToken == TKN_IDENTIFIER) { SymTableNodePtr typeIdPtr; searchAndEnterLocalSymTable(typeIdPtr); typeIdPtr->defn.key = DFN_TYPE; typeIdPtr->library = CurLibrary; getToken(); ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL); //---------------------------------- // Process the type specification... typeIdPtr->typePtr = doType(); if (typeIdPtr->typePtr->typeIdPtr == NULL) typeIdPtr->typePtr->typeIdPtr = typeIdPtr; analyzeTypeDefn(typeIdPtr); //--------------- // Error synch... synchronize(followDeclarationList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); } }
void declarations (SymTableNodePtr routineIdPtr, bool allowFunctions) { if (curToken == TKN_CONST) { getToken(); constDefinitions(); } if (curToken == TKN_TYPE) { getToken(); typeDefinitions(); } if (curToken == TKN_VAR) { getToken(); varDeclarations(routineIdPtr); } //--------------------------------------------------- // Loop to process all of the function definitions... if (allowFunctions) while ((curToken == TKN_FUNCTION) || (curToken == TKN_ORDER) || (curToken == TKN_STATE)){ routine(); //--------------------- // Error synchronize... synchronize(followRoutineList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (tokenIn(declarationStartList) || tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); } else if ((curToken == TKN_FUNCTION) || (curToken == TKN_ORDER) || (curToken == TKN_STATE)) syntaxError(ABL_ERR_SYNTAX_NO_FUNCTION_NESTING); }
void caseBranch (CaseItemPtr& caseItemHead, CaseItemPtr& caseItemTail, long& caseLabelCount, TypePtr expressionType) { //static CaseItemPtr oldCaseItemTail = NULL; CaseItemPtr oldCaseItemTail = caseItemTail; bool anotherLabel; do { TypePtr labelType = caseLabel(caseItemHead, caseItemTail, caseLabelCount); if (expressionType != labelType) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); getToken(); if (curToken == TKN_COMMA) { getToken(); if (tokenIn(CaseLabelStartList)) anotherLabel = true; else { syntaxError(ABL_ERR_SYNTAX_MISSING_CONSTANT); anotherLabel = false; } } else anotherLabel = false; } while (anotherLabel); //-------------- // Error sync... synchronize(FollowCaseLabelList, statementStartList, NULL); ifTokenGetElseError(TKN_COLON, ABL_ERR_SYNTAX_MISSING_COLON); //----------------------------------------------------------------- // Fill in the branch location for each CaseItem for this branch... CaseItemPtr caseItem = (!oldCaseItemTail ? caseItemHead : oldCaseItemTail->next); //oldCaseItemTail = CaseItemTail; while (caseItem) { caseItem->branchLocation = codeBufferPtr; caseItem = caseItem->next; } if (curToken != TKN_END_CASE) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_CASE) break; } while (tokenIn(statementStartList)); ifTokenGetElseError(TKN_END_CASE, ABL_ERR_SYNTAX_MISSING_END_CASE); ifTokenGetElseError(TKN_SEMICOLON, ABL_ERR_SYNTAX_MISSING_SEMICOLON); }
TypePtr arraySubscriptList (TypePtr typePtr) { TypePtr indexTypePtr = NULL; TypePtr elementTypePtr = NULL; TypePtr subscriptTypePtr = NULL; do { if (typePtr->form == FRM_ARRAY) { indexTypePtr = typePtr->info.array.indexTypePtr; elementTypePtr = typePtr->info.array.elementTypePtr; getToken(); subscriptTypePtr = expression(); //------------------------------------------------------------- // If the subscript expression isn't assignment type compatible // with its corresponding subscript type, we're screwed... if (!isAssignTypeCompatible(indexTypePtr, subscriptTypePtr)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); typePtr = elementTypePtr; } else { syntaxError(ABL_ERR_SYNTAX_TOO_MANY_SUBSCRIPTS); while ((curToken != TKN_RBRACKET) && !tokenIn(statementEndList)) getToken(); } } while (curToken == TKN_COMMA); ifTokenGetElseError(TKN_RBRACKET, ABL_ERR_SYNTAX_MISSING_RBRACKET); return(typePtr); }
void whileStatement (void) { // NEW STYLE, using endwhile keyword... getToken(); char* loopEndLocation = crunchAddressMarker(NULL); TypePtr exprType = expression(); if (exprType != BooleanTypePtr) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); //--------------------------------------- // Let's not use a DO keyword, for now... ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO); if (curToken != TKN_END_WHILE) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_WHILE) break; } while (tokenIn(statementStartList)); ifTokenGetElseError(TKN_END_WHILE, ABL_ERR_SYNTAX_MISSING_END_WHILE); fixupAddressMarker(loopEndLocation); }
void forStatement (void) { getToken(); char* loopEndLocation = crunchAddressMarker(NULL); TypePtr forType = NULL; if (curToken == TKN_IDENTIFIER) { SymTableNodePtr forIdPtr = NULL; searchAndFindAllSymTables(forIdPtr); crunchSymTableNodePtr(forIdPtr); if (/*(forIdPtr->level != level) ||*/ (forIdPtr->defn.key != DFN_VAR)) syntaxError(ABL_ERR_SYNTAX_INVALID_FOR_CONTROL); forType = forIdPtr->typePtr; getToken(); //------------------------------------------------------------------ // If we end up adding a CHAR type, this line needs to be changed... if ((forType != IntegerTypePtr) && /*(forType != CharTypePtr) &&*/ (forType->form != FRM_ENUM)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); } else { syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); forType = &DummyType; } ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL); TypePtr exprType = expression(); if (!isAssignTypeCompatible(forType, exprType)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); if (curToken == TKN_TO) getToken(); else syntaxError(ABL_ERR_SYNTAX_MISSING_TO); exprType = expression(); if (!isAssignTypeCompatible(forType, exprType)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); //----------------------------------------- // For now, let's use the DO keyword... ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO); if (curToken != TKN_END_FOR) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_FOR) break; } while (tokenIn(statementStartList)); ifTokenGetElseError(TKN_END_FOR, ABL_ERR_SYNTAX_MISSING_END_FOR); fixupAddressMarker(loopEndLocation); }
void ifStatement (void) { getToken(); char* falseLocation = crunchAddressMarker(NULL); TypePtr exprType = expression(); if (exprType != BooleanTypePtr) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); ifTokenGetElseError(TKN_THEN, ABL_ERR_SYNTAX_MISSING_THEN); if ((curToken != TKN_END_IF) && (curToken != TKN_ELSE)) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if ((curToken == TKN_END_IF) || (curToken == TKN_ELSE)) break; } while (tokenIn(statementStartList)); fixupAddressMarker(falseLocation); //----------------------------- // ELSE branch, if necessary... if (curToken == TKN_ELSE) { getToken(); char* ifEndLocation = crunchAddressMarker(NULL); if (curToken != TKN_END_IF) do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_END_IF) break; } while (tokenIn(statementStartList)); fixupAddressMarker(ifEndLocation); } ifTokenGetElseError(TKN_END_IF, ABL_ERR_SYNTAX_MISSING_END_IF); }
TypePtr simpleExpression (void) { bool usedUnaryOp = false; TokenCodeType unaryOp = TKN_PLUS; if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS)) { unaryOp = curToken; usedUnaryOp = true; getToken(); } //------------------------------------------------ // Grab the first term in the simple expression... TypePtr resultType = term(); if (usedUnaryOp && (resultType != IntegerTypePtr) && (resultType != RealTypePtr)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); //--------------------------------------------------- // Continue to process all terms in the expression... while (tokenIn(addOperatorList)) { TokenCodeType op = curToken; getToken(); TypePtr secondType = term(); switch (op) { case TKN_PLUS: case TKN_MINUS: if (integerOperands(resultType, secondType)) { //--------------------------------------------------- // Both operands are integer, so result is integer... resultType = IntegerTypePtr; } else if (realOperands(resultType, secondType)) { //---------------------------------------------------- // Both real operands, or mixed (real and integer)... resultType = RealTypePtr; } else { syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = &DummyType; } break; case TKN_OR: if (!booleanOperands(resultType, secondType)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = BooleanTypePtr; break; } } return(resultType); }
TypePtr expression (void) { //------------------------------------ // Grab the first simple expression... TypePtr resultType = simpleExpression(); if (tokenIn(relationalOperatorList)) { //--------------------------------------- // Snatch the second simple expression... getToken(); TypePtr secondType = simpleExpression(); checkRelationalOpTypes(resultType, secondType); resultType = BooleanTypePtr; } return(resultType); }
void synchronize(TokenCodeType* tokenList1, TokenCodeType* tokenList2, TokenCodeType* tokenList3) { bool badLists = (!tokenIn(tokenList1) && !tokenIn(tokenList2) && !tokenIn(tokenList3)); if (badLists) { syntaxError((curToken == TKN_EOF) ? ABL_ERR_SYNTAX_UNEXPECTED_EOF : ABL_ERR_SYNTAX_UNEXPECTED_TOKEN); //---------------------------------------------- // Now, we need to re-sync by skipping tokens... while (!tokenIn(tokenList1) && !tokenIn(tokenList2) && !tokenIn(tokenList3) && (curToken != TKN_EOF)) getToken(); } }
void repeatStatement (void) { getToken(); if (curToken != TKN_UNTIL) { do { statement(); while (curToken == TKN_SEMICOLON) getToken(); if (curToken == TKN_UNTIL) break; } while (tokenIn(statementStartList)); } ifTokenGetElseError(TKN_UNTIL, ABL_ERR_SYNTAX_MISSING_UNTIL); TypePtr exprType = expression(); if (exprType != BooleanTypePtr) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); }
TypePtr term (void) { //------------------------- // Grab the first factor... TypePtr resultType = factor(); //------------------------------------------------------------------ // Now, continue grabbing factors separated by multiply operators... while (tokenIn(multiplyOperatorList)) { TokenCodeType op = curToken; getToken(); TypePtr secondType = factor(); switch (op) { case TKN_STAR: if (integerOperands(resultType, secondType)) { //--------------------------------------------------- // Both operands are integer, so result is integer... resultType = IntegerTypePtr; } else if (realOperands(resultType, secondType)) { //---------------------------------------------------- // Both real operands, or mixed (real and integer)... resultType = RealTypePtr; } else { syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = &DummyType; } break; case TKN_FSLASH: if (integerOperands(resultType, secondType)) { //--------------------------------------------------- // Both operands are integer, so result is integer... resultType = IntegerTypePtr; } else if (realOperands(resultType, secondType)) { //---------------------------------------------------- // Both real operands, or mixed (real and integer)... resultType = RealTypePtr; } else { syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = &DummyType; } break; case TKN_DIV: case TKN_MOD: //---------------------------------------------------------- // Both operands should be integer, and result is integer... if (!integerOperands(resultType, secondType)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = IntegerTypePtr; break; case TKN_AND: if (!booleanOperands(resultType, secondType)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); resultType = BooleanTypePtr; break; } } return(resultType); }
TypePtr doType (void) { switch (curToken) { case TKN_IDENTIFIER: { SymTableNodePtr idPtr; searchAllSymTables(idPtr); if (!idPtr) { syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER); return(NULL); } else if (idPtr->defn.key == DFN_TYPE) { //---------------------------------------------------------- // NOTE: Array types should be parsed in this case if a left // bracket follows the type identifier. TypePtr elementType = setType(identifierType(idPtr)); if (curToken == TKN_LBRACKET) { //-------------- // Array type... TypePtr typePtr = createType(); if (!typePtr) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array type "); TypePtr elementTypePtr = typePtr; do { getToken(); if (tokenIn(indexTypeStartList)) { elementTypePtr->form = FRM_ARRAY; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; //---------------------------------------------- // All array indices must be integer, for now... elementTypePtr->info.array.indexTypePtr = setType(IntegerTypePtr); //------------------------ // Read the index count... switch (curToken) { case TKN_NUMBER: if (curLiteral.type == LIT_INTEGER) elementTypePtr->info.array.elementCount = curLiteral.value.integer; else { elementTypePtr->form = FRM_NONE; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; elementTypePtr->info.array.indexTypePtr = NULL; syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE); } getToken(); break; case TKN_IDENTIFIER: { SymTableNodePtr idPtr; searchAllSymTables(idPtr); if (idPtr == NULL) syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER); else if (idPtr->defn.key == DFN_CONST) { if (idPtr->typePtr == IntegerTypePtr) elementTypePtr->info.array.elementCount = idPtr->defn.info.constant.value.integer; else { elementTypePtr->form = FRM_NONE; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; elementTypePtr->info.array.indexTypePtr = NULL; syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE); } } else { elementTypePtr->form = FRM_NONE; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; elementTypePtr->info.array.indexTypePtr = NULL; syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE); } getToken(); } break; default: elementTypePtr->form = FRM_NONE; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; elementTypePtr->info.array.indexTypePtr = NULL; syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE); getToken(); } } else { elementTypePtr->form = FRM_NONE; elementTypePtr->size = 0; elementTypePtr->typeIdPtr = NULL; elementTypePtr->info.array.indexTypePtr = NULL; syntaxError(ABL_ERR_SYNTAX_INVALID_INDEX_TYPE); getToken(); } synchronize(followDimensionList, NULL, NULL); //-------------------------------- // Create an array element type... if (curToken == TKN_COMMA) { elementTypePtr = elementTypePtr->info.array.elementTypePtr = createType(); if (!elementTypePtr) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc array element Type "); } } while (curToken == TKN_COMMA); ifTokenGetElseError(TKN_RBRACKET, ABL_ERR_SYNTAX_MISSING_RBRACKET); elementTypePtr->info.array.elementTypePtr = elementType; typePtr->size = arraySize(typePtr); elementType = typePtr; } return(elementType); } else { syntaxError(ABL_ERR_SYNTAX_NOT_A_TYPE_IDENTIFIER); return(NULL); } } break; case TKN_LPAREN: return(enumerationType()); default: syntaxError(ABL_ERR_SYNTAX_INVALID_TYPE); return(NULL); } }
void statement (void) { //------------------------------------------------------------------- // NOTE: Since we currently don't support generic BEGIN/END (compound // statement) blocks... if ((curToken != TKN_CODE) /*&& (curToken != TKN_BEGIN)*/) crunchStatementMarker(); switch (curToken) { case TKN_IDENTIFIER: { SymTableNodePtr IdPtr = NULL; //-------------------------------------------------------------- // First, do we have an assignment statement or a function call? searchAndFindAllSymTables(IdPtr); if ((IdPtr->defn.key == DFN_FUNCTION)/* || (IdPtr->defn.key == DFN_MODULE)*/) { RoutineKey key = IdPtr->defn.info.routine.key; if ((key == RTN_ASSERT) || (key == RTN_PRINT) || (key == RTN_CONCAT)) { bool uncrunch = ((key == RTN_ASSERT) && !AssertEnabled) || ((key == RTN_PRINT) && !PrintEnabled) || ((key == RTN_CONCAT) && !StringFunctionsEnabled); if (uncrunch) { uncrunchStatementMarker(); Crunch = false; } } crunchSymTableNodePtr(IdPtr); if (IdPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) { if (NumOrderCalls == MAX_ORDERS) syntaxError(ABL_ERR_SYNTAX_TOO_MANY_ORDERS); crunchByte((unsigned char)(NumOrderCalls / 32)); crunchByte((unsigned char)(NumOrderCalls % 32)); NumOrderCalls++; } getToken(); SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr; routineCall(IdPtr, 1); CurRoutineIdPtr = thisRoutineIdPtr; Crunch = true; } else assignmentStatement(IdPtr); } break; case TKN_REPEAT: repeatStatement(); break; case TKN_WHILE: whileStatement(); break; case TKN_IF: ifStatement(); break; case TKN_FOR: forStatement(); break; case TKN_SWITCH: switchStatement(); break; case TKN_TRANS: transStatement(); break; case TKN_TRANS_BACK: transBackStatement(); break; } //--------------------------------------------------------------------- // Now, make sure the statement is closed off with the proper block end // statement, if necessary (which is usually the case :). synchronize(statementEndList, NULL, NULL); if (tokenIn(statementStartList)) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); }
void switchStatement (void) { //------------------------- // Init the branch table... getToken(); char* branchTableLocation = crunchAddressMarker(NULL); CaseItemPtr caseItemHead = NULL; CaseItemPtr caseItemTail = NULL; long caseLabelCount = 0; //CaseItemHead = CaseItemTail = NULL; //CaseLabelCount = 0; TypePtr expressionType = expression(); //----------------------------------------------------------------------------- // NOTE: If we have subranges in ABL, we'll have to check in the following line // for a subrange, as well... if (((expressionType->form != FRM_SCALAR) && (expressionType->form != FRM_ENUM)) || (expressionType == RealTypePtr)) syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES); synchronize(FollowSwitchExpressionList, NULL, NULL); //---------------------------- // Process each CASE branch... bool moreBranches = (curToken == TKN_CASE); char* caseEndChain = NULL; while (moreBranches) { getToken(); if (tokenIn(CaseLabelStartList)) caseBranch(caseItemHead, caseItemTail, caseLabelCount, expressionType); //--------------------------------------------------- // Link another address marker at the end of the CASE // branch to point to the end of the CASE block... caseEndChain = crunchAddressMarker(caseEndChain); moreBranches = (curToken == TKN_CASE); } //if (curToken == TKN_DEFAULT) { //} //------------------------- // Emit the branch table... fixupAddressMarker(branchTableLocation); crunchInteger(caseLabelCount); CaseItemPtr caseItem = caseItemHead; while (caseItem) { crunchInteger(caseItem->labelValue); crunchOffset(caseItem->branchLocation); CaseItemPtr nextCaseItem = caseItem->next; ABLStackFreeCallback(caseItem); caseItem = nextCaseItem; } ifTokenGetElseError(TKN_END_SWITCH, ABL_ERR_SYNTAX_MISSING_END_SWITCH); //-------------------------------------------- // Patch up the case branch address markers... while (caseEndChain) caseEndChain = fixupAddressMarker(caseEndChain); }
void varOrFieldDeclarations (SymTableNodePtr routineIdPtr, long offset) { bool varFlag = (routineIdPtr != NULL); SymTableNodePtr idPtr = NULL; SymTableNodePtr firstIdPtr = NULL; SymTableNodePtr lastIdPtr = NULL; SymTableNodePtr prevLastIdPtr = NULL; long totalSize = 0; while ((curToken == TKN_IDENTIFIER) || (curToken == TKN_ETERNAL) || (curToken == TKN_STATIC)) { VariableType varType = VAR_TYPE_NORMAL; if ((curToken == TKN_ETERNAL) || (curToken == TKN_STATIC)) { if (curToken == TKN_ETERNAL) varType = VAR_TYPE_ETERNAL; else varType = VAR_TYPE_STATIC; getToken(); if (curToken != TKN_IDENTIFIER) syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER); } firstIdPtr = NULL; //------------------------------ // Process the variable type... TypePtr typePtr = doType(); //------------------------------------------------------------------ // Since we haven't really assigned it here, decrement its // numInstances. Every variable in this list will set it properly... typePtr->numInstances--; long size = typePtr->size; //------------------------------------------------------- // Now that we've read the type, read in the variable (or // possibly list of variables) declared of this type. // Loop to process every variable (and field, if records // are being implemented:) in sublist... while (curToken == TKN_IDENTIFIER) { if (varFlag) { //--------------------------------------------- // We're working with a variable declaration... if (varType == VAR_TYPE_ETERNAL) { long curLevel = level; level = 0; searchAndEnterThisTable (idPtr, SymTableDisplay[0]); level = curLevel; } else searchAndEnterLocalSymTable(idPtr); idPtr->library = CurLibrary; idPtr->defn.key = DFN_VAR; } else syntaxError(ABL_ERR_SYNTAX_NO_RECORD_TYPES); idPtr->labelIndex = 0; //------------------------------------------ // Now, link Id's together into a sublist... if (!firstIdPtr) { firstIdPtr = lastIdPtr = idPtr; if (varFlag && (varType != VAR_TYPE_ETERNAL) && (routineIdPtr->defn.info.routine.locals == NULL)) routineIdPtr->defn.info.routine.locals = idPtr; } else { lastIdPtr->next = idPtr; lastIdPtr = idPtr; } getToken(); ifTokenGet(TKN_COMMA); } //-------------------------------------------------------------------------- // Assign the offset and the type to all variable or field Ids in sublist... for (idPtr = firstIdPtr; idPtr != NULL; idPtr = idPtr->next) { idPtr->typePtr = setType(typePtr); if (varFlag) { idPtr->defn.info.data.varType = varType; switch (varType) { case VAR_TYPE_NORMAL: totalSize += size; idPtr->defn.info.data.offset = offset++; break; case VAR_TYPE_ETERNAL: { idPtr->defn.info.data.offset = eternalOffset; //----------------------------------- // Initialize the variable to zero... StackItemPtr dataPtr = (StackItemPtr)stack + eternalOffset; if (typePtr->form == FRM_ARRAY) { dataPtr->address = (Address)ABLStackMallocCallback((size_t)size); if (!dataPtr->address) ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc eternal array "); memset(dataPtr->address, 0, size); EternalVariablesSizes[eternalOffset] = size; } else { dataPtr->integer = 0; EternalVariablesSizes[eternalOffset] = 0; } eternalOffset++; } break; case VAR_TYPE_STATIC: { if (NumStaticVariables == MaxStaticVariables) syntaxError(ABL_ERR_SYNTAX_TOO_MANY_STATIC_VARS); idPtr->defn.info.data.offset = NumStaticVariables; if (typePtr->form == FRM_ARRAY) StaticVariablesSizes[NumStaticVariables] = size; else StaticVariablesSizes[NumStaticVariables] = 0; NumStaticVariables++; } break; } analyzeVarDecl(idPtr); } else { //---------------- // record field... idPtr->defn.info.data.varType = VAR_TYPE_NORMAL; idPtr->defn.info.data.offset = offset; offset += size; } } //-------------------------------------------------- // Now, link this sublist to the previous sublist... if (varType != VAR_TYPE_ETERNAL) { if (prevLastIdPtr != NULL) prevLastIdPtr->next = firstIdPtr; prevLastIdPtr = lastIdPtr; } //--------------------- // Error synchronize... if (varFlag) synchronize(followVariablesList, declarationStartList, statementStartList); if (curToken == TKN_SEMICOLON) getToken(); else if (varFlag && (tokenIn(declarationStartList) || tokenIn(statementStartList))) syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON); } synchronize(followVarBlockList, NULL, NULL); if (varFlag) { //---------------------------------------------------------------- // If the following error occurs too frequently, simply make the // totalLocalSize field an unsigned long instead, and dramatically // increase the totalSize limit here... if (totalSize > 32000) syntaxError(ABL_ERR_SYNTAX_TOO_MANY_LOCAL_VARIABLES); routineIdPtr->defn.info.routine.totalLocalSize = (unsigned short)totalSize; } }