// 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 macros, and other text block related functions #include "include.h" static SYMTABLE *macroSymbols; // macro symbol list is kept here void DestroyTextBlockLines(TEXT_BLOCK *theBlock) { TEXT_LINE *tempLine; while(theBlock->firstLine) // get rid of lines of text { tempLine=theBlock->firstLine->next; DisposePtr(theBlock->firstLine); theBlock->firstLine=tempLine; } } bool AddLineToTextBlock(TEXT_BLOCK *theBlock,char *theLine) // Add theLine to theBlock { int length; bool fail; TEXT_LINE *theTextLine; fail=false; length=strlen(theLine); if((theTextLine=(TEXT_LINE *)NewPtr(sizeof(TEXT_LINE)+length+1))) { theTextLine->next=NULL; theTextLine->whereFrom.theFile=currentVirtualFile; theTextLine->whereFrom.fileLineNumber=currentVirtualFileLine; strcpy(&theTextLine->theLine[0],theLine); if(theBlock->lastLine) { theBlock->lastLine->next=theTextLine; // link onto the end theBlock->lastLine=theTextLine; } else { theBlock->firstLine=theBlock->lastLine=theTextLine; // link in as first line } } else { fail=true; } return(!fail); } MACRO_RECORD *MatchMacro(char *theOpcode) // try to match theOpcode against the list of macros { void *resultValue; if((resultValue=STFindDataForName(macroSymbols,theOpcode))) { return((MACRO_RECORD *)resultValue); } return(NULL); } bool CreateParameterList(char *theLine,int *lineIndex,TEXT_BLOCK *theBlock) // Parse out a list of text elements // return false if there was a hard error { char theElement[MAXSTRING]; bool fail; fail=false; if(ParseFirstListElement(theLine,lineIndex,theElement)) { fail=!AddLineToTextBlock(theBlock,theElement); while(!fail&&ParseNextListElement(theLine,lineIndex,theElement)) { fail=!AddLineToTextBlock(theBlock,theElement); } } if(fail) { ReportComplaint(true,"Failed to create parameter list element\n"); } return(!fail); } bool CreateParameterLabels(char *theLine,int *lineIndex,TEXT_BLOCK *theBlock) // Parse out a list of label elements // return false if there was a hard error { char theElement[MAXSTRING]; bool fail; fail=false; if(ParseFirstLabelElement(theLine,lineIndex,theElement)) { fail=!AddLineToTextBlock(theBlock,theElement); while(!fail&&ParseNextLabelElement(theLine,lineIndex,theElement)) { fail=!AddLineToTextBlock(theBlock,theElement); } } if(fail) { ReportComplaint(true,"Failed to create parameter label element\n"); } return(!fail); } bool HandleMacroMatch(MACRO_RECORD *theMacro,char *theLine,int *lineIndex,LISTING_RECORD *listingRecord) // A macro has been encountered in the source code, so dump the contents of the macro into the // assembly stream { bool fail; TEXT_BLOCK paramValues; fail=false; paramValues.firstLine=paramValues.lastLine=NULL; if(CreateParameterList(theLine,lineIndex,¶mValues)) { if(ParseComment(theLine,lineIndex)) { listingRecord->sourceType='m'; // output a small 'm' on lines which invoke a macro OutputListFileLine(listingRecord,theLine); // output the line first so that the macro contents follow it listingRecord->wantList=false; fail=!ProcessTextBlock(&theMacro->contents,&theMacro->parameters,¶mValues,'M'); // process text of macro back into assembly stream } else { AssemblyComplaint(NULL,true,"Ill formed macro parameters\n"); } } else { fail=true; } DestroyTextBlockLines(¶mValues); return(!fail); } void DestroyMacro(MACRO_RECORD *theMacro) // remove theMacro from existence { DestroyTextBlockLines(&theMacro->parameters); DestroyTextBlockLines(&theMacro->contents); STRemoveEntry(macroSymbols,theMacro->theSymbol); if(theMacro->next) { theMacro->next->previous=theMacro->previous; } if(theMacro->previous) { theMacro->previous->next=theMacro->next; } else { macrosHead=theMacro->next; } DisposePtr(theMacro); } void DestroyMacros() // remove all macros, and all symbols from the symbol table { while(macrosHead) { DestroyMacro(macrosHead); } } MACRO_RECORD *CreateMacro(char *macroName) // Create a macro record, link it to the head of the global list, create a symbol table entry for it { MACRO_RECORD *theRecord; if((theRecord=(MACRO_RECORD *)NewPtr(sizeof(MACRO_RECORD)))) { theRecord->parameters.firstLine=NULL; theRecord->parameters.lastLine=NULL; theRecord->contents.firstLine=NULL; theRecord->contents.lastLine=NULL; theRecord->whereFrom.theFile=currentVirtualFile; theRecord->whereFrom.fileLineNumber=currentVirtualFileLine; if((theRecord->theSymbol=STAddEntryAtEnd(macroSymbols,macroName,theRecord))) { theRecord->previous=NULL; if((theRecord->next=macrosHead)) { theRecord->next->previous=theRecord; // make reverse link } macrosHead=theRecord; return(theRecord); } DisposePtr(theRecord); } return(NULL); } void UnInitMacros() // undo what InitMacros did { STDisposeSymbolTable(macroSymbols); } bool InitMacros() // initialize symbol table for macros { if((macroSymbols=STNewSymbolTable())) { return(true); } return(false); }