// 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". // Handle creation and manipulation of operand aliases #include "include.h" static SYMTABLE *aliasSymbols; // alias symbol list is kept here ALIAS_RECORD *MatchAlias(char *theOperand) // try to match theOperand against the list of aliases { void *resultValue; if((resultValue=STFindDataForName(aliasSymbols,theOperand))) { return((ALIAS_RECORD *)resultValue); } return(NULL); } bool HandleAliasMatches(char *theLine,int *lineIndex,LISTING_RECORD *listingRecord) // scans the line for anything matching an "alias" and replaces it with the // contents of that alias. This is called after an opcode has been identified, // so lineIndex points to (possibly whitespace before) operands. // NOTE: this will detect when the output would grow too long, and complain. // NOTE: this is called often, so it attempts to minimize copying data unless a // substiution is actually going to take place // NOTE: for more speed, this checks to see if any aliases have even been defined // before attempting any substitutions. { ALIAS_RECORD *theRecord; char substitutionText[MAXSTRING], token[MAXSTRING]; int writeBackIndex, // place where data will be written back to output line if substitution is needed subOutIndex, // tells where the next data gets written into the substitutionText array tempIndex, // temporary index skipIndex, // keeps track of where we are currently in the input data tokenIndex, // used to copy data to token inIndex; // keeps an index to the start of source data to be written into the substitutionText array bool haveSubstitution; bool tooLong; if(aliasesHead) // skip all of this if there are no aliases defined { writeBackIndex=*lineIndex; // keep track of where we are now (do not modify lineIndex) ParseWhiteSpace(theLine,&writeBackIndex); // skip over any initial whitespace inIndex=skipIndex=writeBackIndex; // begin reading from here subOutIndex=0; // start writing into substitution array here tooLong=false; haveSubstitution=false; // so far, no substitution is needed while(!tooLong&&!ParseComment(theLine,&skipIndex)) // keep going until end of line, or substitution text too long { if(IsLabelChar(theLine[skipIndex])) // start of a token? { tempIndex=skipIndex; // remember where we are, so if there's a match, we can copy up to this point tokenIndex=0; do { token[tokenIndex++]=theLine[skipIndex++]; // scoop up the token } while(IsLabelChar(theLine[skipIndex])); token[tokenIndex]='\0'; // terminate the token so we can do the match if((theRecord=MatchAlias(token))) // see if an alias can be found which matches this token { if((subOutIndex+(tempIndex-inIndex)+theRecord->contentLength)contents[0],theRecord->contentLength); // copy in the substituted text subOutIndex+=theRecord->contentLength; // move over for that too inIndex=skipIndex; // next copy starts from here } else { tooLong=true; // had a problem } haveSubstitution=true; // found something, so remember it } } else { skipIndex++; // move through all the non-label junk } } if(haveSubstitution&&!tooLong) // see if there was a substitution -- if so, update the line { if(writeBackIndex+subOutIndex+(skipIndex-inIndex)+1sourceType='a'; OutputListFileLine(listingRecord,theLine); // output the original line listingRecord->sourceType='A'; memmove(&theLine[writeBackIndex+subOutIndex],&theLine[inIndex],skipIndex-inIndex); // move over the stuff past the end of the last substitution memcpy(&theLine[writeBackIndex],substitutionText,subOutIndex); // blast in the substitution text theLine[writeBackIndex+subOutIndex+(skipIndex-inIndex)]='\0'; // re-terminate the line } else { tooLong=true; } } if(tooLong) { AssemblyComplaint(NULL,true,"Alias substitution too long\n"); } } return(true); // this never fails hard } void DestroyAlias(ALIAS_RECORD *theAlias) // remove theAlias from existence { STRemoveEntry(aliasSymbols,theAlias->theSymbol); if(theAlias->next) { theAlias->next->previous=theAlias->previous; } if(theAlias->previous) { theAlias->previous->next=theAlias->next; } else { aliasesHead=theAlias->next; } DisposePtr(theAlias); } void DestroyAliases() // remove all aliases, and all symbols from the symbol table { while(aliasesHead) { DestroyAlias(aliasesHead); } } ALIAS_RECORD *CreateAlias(char *aliasName,char *aliasString) // Create an alias record, link it to the head of the global list, create a symbol table entry for it { int length; ALIAS_RECORD *theRecord; length=strlen(aliasString); if((theRecord=(ALIAS_RECORD *)NewPtr(sizeof(ALIAS_RECORD)+length+1))) { theRecord->whereFrom.theFile=currentVirtualFile; theRecord->whereFrom.fileLineNumber=currentVirtualFileLine; theRecord->contentLength=length; strcpy(&theRecord->contents[0],aliasString); if((theRecord->theSymbol=STAddEntryAtEnd(aliasSymbols,aliasName,theRecord))) { theRecord->previous=NULL; if((theRecord->next=aliasesHead)) { theRecord->next->previous=theRecord; // make reverse link } aliasesHead=theRecord; return(theRecord); } DisposePtr(theRecord); } return(NULL); } void UnInitAliases() // undo what InitAliases did { STDisposeSymbolTable(aliasSymbols); } bool InitAliases() // initialize symbol table for aliases { if((aliasSymbols=STNewSymbolTable())) { return(true); } return(false); }