// Copyright (C) 1999-2003 Core Technologies. // // This file is part of tpasm. // // tpasm is free software; you can redistribute it and/or modify // it under the terms of the tpasm LICENSE AGREEMENT. // // tpasm is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // tpasm LICENSE AGREEMENT for more details. // // You should have received a copy of the tpasm LICENSE AGREEMENT // along with tpasm; see the file "LICENSE.TXT". // Assembler label management #include "include.h" static SYMTABLE *labelSymbols; // symbol table int NumLabels() // Count up the number of labels { LABEL_RECORD *theLabel; int numLabels; theLabel=labelsHead; numLabels=0; while(theLabel) { numLabels++; theLabel=theLabel->next; } return(numLabels); } LABEL_RECORD *LocateLabel(char *labelName) // Given a label name, return its record (if it can be located) // If there is no label, return NULL { void *resultValue; if((resultValue=STFindDataForName(labelSymbols,labelName))) { return((LABEL_RECORD *)resultValue); } return(NULL); } void DestroyLabel(LABEL_RECORD *theLabel) // remove theLabel from the global label table { STRemoveEntry(labelSymbols,theLabel->theSymbol); if(theLabel->next) { theLabel->next->previous=theLabel->previous; } if(theLabel->previous) { theLabel->previous->next=theLabel->next; } else { labelsHead=theLabel->next; } DisposePtr(theLabel); } static void ReportLabelDefinitionLocation(LABEL_RECORD *theLabelRecord) // Report as a supplementary message, the location where theLabelRecord // was defined { AssemblySupplement(&theLabelRecord->whereFrom,"Previous definition was here\n"); } LABEL_RECORD *CreateLabel(char *labelName,int value,int type,int passCount,bool resolved) // Create a new label in the global table // If there is a problem, report it, and return NULL { LABEL_RECORD *newRecord; if(!LocateLabel(labelName)) { if((newRecord=(LABEL_RECORD *)NewPtr(sizeof(LABEL_RECORD)))) { if((newRecord->theSymbol=STAddEntryAtEnd(labelSymbols,labelName,newRecord))) { newRecord->theValue=value; newRecord->theType=type; newRecord->passCount=passCount; newRecord->resolved=resolved; newRecord->whereFrom.theFile=currentVirtualFile; newRecord->whereFrom.fileLineNumber=currentVirtualFileLine; newRecord->previous=NULL; if((newRecord->next=labelsHead)) { labelsHead->previous=newRecord; } labelsHead=newRecord; return(newRecord); } else { ReportComplaint(true,"Failed to create symbol table entry (Out of memory)\n"); } DisposePtr(newRecord); } else { ReportComplaint(true,"Failed to create label (Out of memory)\n"); } } else { ReportComplaint(true,"Label '%s' already exists\n",labelName); } return(NULL); } bool AssignLabel(char *labelName,bool isLocal,int theValue) // A line label has been encountered. // This is called to assign a label, check what is happening, // set flags, and complain as needed. // If there is a problem assigning the label (hard error), return false { LABEL_RECORD *oldLabel; bool fail; fail=false; if((oldLabel=LocateLabel(labelName))) // see if there is a definition for this already { if(oldLabel->theType==LF_LABEL) // make sure it is a label, and not a constant { if(oldLabel->passCountpassCount=passCount; // update the passcount if(!isLocal) // if not local, then update the current scope { strcpy(scope,labelName); } if(oldLabel->theValue!=theValue) // see if value is changing between passes { ReportDiagnostic("Modified label: '%s' (old=%08X, new=%08X)\n",labelName,oldLabel->theValue,theValue); numModifiedLabels++; // it is, so remember that we have modified a label oldLabel->theValue=theValue; // re-assign new value } } else { AssemblyComplaint(NULL,true,"Label '%s' already defined\n",labelName); ReportLabelDefinitionLocation(oldLabel); } } else { AssemblyComplaint(NULL,true,"Label '%s' already defined as a constant\n",labelName); ReportLabelDefinitionLocation(oldLabel); } } else { if(!isLocal) // if not local, then update the current scope { strcpy(scope,labelName); } if(!CreateLabel(labelName,theValue,LF_LABEL,passCount,true)) { fail=true; } } return(!fail); } bool AssignConstant(char *theName,int theValue,bool resolved) // Assign a constant. // return false if there is a hard error { LABEL_RECORD *oldLabel; bool fail; fail=false; if((oldLabel=LocateLabel(theName))) // see if there is a definition for this already { switch(oldLabel->theType) { case LF_EXT_CONST: if(oldLabel->resolved&&resolved) // make sure both are resolved so the compare below is meaningful { if(oldLabel->theValue!=theValue) // only complain if the value is changing { AssemblyComplaint(NULL,true,"Label '%s' already defined as constant of different value\n",theName); ReportLabelDefinitionLocation(oldLabel); } } break; case LF_CONST: if(oldLabel->passCountpassCount=passCount; // update the passcount if(oldLabel->resolved) { if(resolved) // was resolved and is resolved { if(oldLabel->theValue!=theValue) // see if value is changing between passes { ReportDiagnostic("Modified label: '%s' (old=%08X, new=%08X)\n",theName,oldLabel->theValue,theValue); numModifiedLabels++; // it is, so remember that we have modified a label oldLabel->theValue=theValue; // re-assign new value } } else { // ### this should not happen // oldLabel->resolved=false; // going from resolved to unresolved??? // numModifiedLabels++; // it is, so remember that we have modified a label } } else { if((oldLabel->resolved=resolved)) // resolve it now if we can { oldLabel->theValue=theValue; // assign the current value numModifiedLabels++; // remember it was messed with } } } else // see same label being defined again in the current pass { if(oldLabel->resolved) { if(!resolved||(oldLabel->theValue!=theValue)) // only complain if the value is changing { AssemblyComplaint(NULL,true,"Label '%s' already defined\n",theName); ReportLabelDefinitionLocation(oldLabel); } } else { oldLabel->resolved=resolved; // resolve it now if we can oldLabel->theValue=theValue; // assign the current value numModifiedLabels++; // remember it was messed with } } break; case LF_SET: AssemblyComplaint(NULL,true,"Label '%s' already defined with 'set'\n",theName); ReportLabelDefinitionLocation(oldLabel); break; case LF_LABEL: AssemblyComplaint(NULL,true,"Label '%s' already defined as a label\n",theName); ReportLabelDefinitionLocation(oldLabel); break; default: break; } } else { if(!CreateLabel(theName,theValue,LF_CONST,passCount,resolved)) { fail=true; } } return(!fail); } void UnAssignSetConstant(char *theName) // remove a constant that was assigned by AssignSetConstant // return false if there is a hard error { LABEL_RECORD *oldLabel; if((oldLabel=LocateLabel(theName))) // see if there is a definition for this already { switch(oldLabel->theType) { case LF_EXT_CONST: AssemblyComplaint(NULL,true,"Label '%s' defined as constant cannot be unset\n",theName); ReportLabelDefinitionLocation(oldLabel); break; case LF_CONST: AssemblyComplaint(NULL,true,"Label '%s' defined with 'equ' cannot be unset\n",theName); ReportLabelDefinitionLocation(oldLabel); break; case LF_SET: DestroyLabel(oldLabel); break; case LF_LABEL: AssemblyComplaint(NULL,true,"Label '%s' defined as a label cannot be unset\n",theName); ReportLabelDefinitionLocation(oldLabel); break; default: break; } } else { AssemblyComplaint(NULL,true,"Label '%s' not defined\n",theName); } } bool AssignSetConstant(char *theName,int theValue,bool resolved) // Assign a set constant (one which can be changed by other // set instructions). // return false if there is a hard error { LABEL_RECORD *oldLabel; bool fail; fail=false; if((oldLabel=LocateLabel(theName))) // see if there is a definition for this already { switch(oldLabel->theType) { case LF_EXT_CONST: AssemblyComplaint(NULL,true,"Label '%s' already defined as a constant\n",theName); ReportLabelDefinitionLocation(oldLabel); break; case LF_CONST: AssemblyComplaint(NULL,true,"Label '%s' already defined with 'equ'\n",theName); ReportLabelDefinitionLocation(oldLabel); break; case LF_SET: oldLabel->passCount=passCount; // update the passcount oldLabel->theValue=theValue; // update the value (do not update numModifiedLabels, since these are ALLOWED to change) oldLabel->resolved=resolved; // remember if it is resolved or not break; case LF_LABEL: AssemblyComplaint(NULL,true,"Label '%s' already defined as a label\n",theName); ReportLabelDefinitionLocation(oldLabel); break; default: break; } } else { if(!CreateLabel(theName,theValue,LF_SET,passCount,resolved)) { fail=true; } } return(!fail); } void UnInitLabels() // undo what InitLabels did { while(labelsHead) { DestroyLabel(labelsHead); // get rid of all labels } STDisposeSymbolTable(labelSymbols); } bool InitLabels() // initialize label table for assembler labels { labelsHead=NULL; if((labelSymbols=STNewSymbolTable())) { return(true); } return(false); }