1 //	Copyright (C) 1999-2012 Core Technologies.
2 //
3 //	This file is part of tpasm.
4 //
5 //	tpasm is free software; you can redistribute it and/or modify
6 //	it under the terms of the tpasm LICENSE AGREEMENT.
7 //
8 //	tpasm is distributed in the hope that it will be useful,
9 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //	tpasm LICENSE AGREEMENT for more details.
12 //
13 //	You should have received a copy of the tpasm LICENSE AGREEMENT
14 //	along with tpasm; see the file "LICENSE.TXT".
15 
16 
17 // Handle creation and manipulation of operand aliases
18 
19 #include	"include.h"
20 
21 static SYM_TABLE
22 	*aliasSymbols;						// alias symbol list is kept here
23 
MatchAlias(const char * operand)24 ALIAS_RECORD *MatchAlias(const char *operand)
25 // try to match operand against the list of aliases
26 {
27 	void
28 		*resultValue;
29 
30 	if((resultValue=STFindDataForName(aliasSymbols,operand)))
31 	{
32 		return((ALIAS_RECORD *)resultValue);
33 	}
34 	return(NULL);
35 }
36 
HandleAliasMatches(char * line,unsigned int * lineIndex,LISTING_RECORD * listingRecord)37 bool HandleAliasMatches(char *line,unsigned int *lineIndex,LISTING_RECORD *listingRecord)
38 // Scans the line for anything matching an "alias" and replaces it with the
39 // contents of that alias.  This is called after any initial label on the line
40 // has been processed.
41 // NOTE: this will detect when the output would grow too long, and complain.
42 // NOTE: this is called often, so it attempts to minimize copying data unless a
43 // substiution is actually going to take place
44 // NOTE: for more speed, this checks to see if any aliases have even been defined
45 // before attempting any substitutions.
46 {
47 	ALIAS_RECORD
48 		*record;
49 	char
50 		substitutionText[MAX_STRING],
51 		token[MAX_STRING];
52 	unsigned int
53 		writeBackIndex,					// place where data will be written back to output line if substitution is needed
54 		subOutIndex,					// tells where the next data gets written into the substitutionText array
55 		tempIndex,						// temporary index
56 		skipIndex,						// keeps track of where we are currently in the input data
57 		tokenIndex,						// used to copy data to token
58 		inIndex;						// keeps an index to the start of source data to be written into the substitutionText array
59 	bool
60 		haveSubstitution;
61 	bool
62 		tooLong;
63 
64 	if(aliasesHead)							// skip all of this if there are no aliases defined
65 	{
66 		writeBackIndex=*lineIndex;			// keep track of where we are now (do not modify lineIndex)
67 		SkipWhiteSpace(line,&writeBackIndex);	// skip over any initial whitespace
68 		inIndex=skipIndex=writeBackIndex;	// begin reading from here
69 		subOutIndex=0;						// start writing into substitution array here
70 		tooLong=false;
71 		haveSubstitution=false;				// so far, no substitution is needed
72 		while(!tooLong&&!ParseComment(line,&skipIndex))	// keep going until end of line, or substitution text too long
73 		{
74 			if(IsLabelChar(line[skipIndex]))	// start of a token?
75 			{
76 				tempIndex=skipIndex;		// remember where we are, so if there's a match, we can copy up to this point
77 				tokenIndex=0;
78 				do
79 				{
80 					token[tokenIndex++]=line[skipIndex++];	// scoop up the token
81 				} while(IsLabelChar(line[skipIndex]));
82 
83 				token[tokenIndex]='\0';		// terminate the token so we can do the match
84 
85 				if((record=MatchAlias(token)))	// see if an alias can be found which matches this token
86 				{
87 					if((subOutIndex+(tempIndex-inIndex)+record->contentLength)<MAX_STRING)	// make sure the whole thing fits
88 					{
89 						memcpy(&substitutionText[subOutIndex],&line[inIndex],tempIndex-inIndex);	// copy the data up to this substitution
90 						subOutIndex+=tempIndex-inIndex;			// add to the output index
91 						memcpy(&substitutionText[subOutIndex],&record->contents[0],record->contentLength);	// copy in the substituted text
92 						subOutIndex+=record->contentLength;	// move over for that too
93 						inIndex=skipIndex;	// next copy starts from here
94 					}
95 					else
96 					{
97 						tooLong=true;		// had a problem
98 					}
99 					haveSubstitution=true;	// found something, so remember it
100 				}
101 			}
102 			else
103 			{
104 				skipIndex++;				// move through all the non-label junk
105 			}
106 		}
107 		if(haveSubstitution&&!tooLong)		// see if there was a substitution -- if so, update the line
108 		{
109 			if(writeBackIndex+subOutIndex+(skipIndex-inIndex)+1<MAX_STRING)		// make sure there's room in the output for the substitution
110 			{
111 				listingRecord->sourceType='a';
112 				OutputListFileLine(listingRecord,line);	// output the original line
113 				listingRecord->sourceType='A';
114 				memmove(&line[writeBackIndex+subOutIndex],&line[inIndex],skipIndex-inIndex);	// move over the stuff past the end of the last substitution
115 				memcpy(&line[writeBackIndex],substitutionText,subOutIndex);	// blast in the substitution text
116 				line[writeBackIndex+subOutIndex+(skipIndex-inIndex)]='\0';	// re-terminate the line
117 			}
118 			else
119 			{
120 				tooLong=true;
121 			}
122 		}
123 		if(tooLong)
124 		{
125 			AssemblyComplaint(NULL,true,"Alias substitution too long\n");
126 		}
127 	}
128 	return(true);							// this never fails hard
129 }
130 
DestroyAlias(ALIAS_RECORD * alias)131 void DestroyAlias(ALIAS_RECORD *alias)
132 // remove alias from existence
133 {
134 	STRemoveEntry(aliasSymbols,alias->symbol);
135 
136 	if(alias->next)
137 	{
138 		alias->next->previous=alias->previous;
139 	}
140 
141 	if(alias->previous)
142 	{
143 		alias->previous->next=alias->next;
144 	}
145 	else
146 	{
147 		aliasesHead=alias->next;
148 	}
149 	DisposePtr(alias);
150 }
151 
DestroyAliases()152 void DestroyAliases()
153 // remove all aliases, and all symbols from the symbol table
154 {
155 	while(aliasesHead)
156 	{
157 		DestroyAlias(aliasesHead);
158 	}
159 }
160 
CreateAlias(const char * aliasName,const char * aliasString)161 ALIAS_RECORD *CreateAlias(const char *aliasName,const char *aliasString)
162 // Create an alias record, link it to the head of the global list, create a symbol table entry for it
163 {
164 	unsigned int
165 		length;
166 	ALIAS_RECORD
167 		*record;
168 
169 	length=strlen(aliasString);
170 	if((record=(ALIAS_RECORD *)NewPtr(sizeof(ALIAS_RECORD)+length+1)))
171 	{
172 		record->whereFrom.file=currentVirtualFile;
173 		record->whereFrom.fileLineNumber=currentVirtualFileLine;
174 
175 		record->contentLength=length;
176 		strcpy(&record->contents[0],aliasString);
177 
178 		if((record->symbol=STAddEntryAtEnd(aliasSymbols,aliasName,record)))
179 		{
180 			record->previous=NULL;
181 			if((record->next=aliasesHead))
182 			{
183 				record->next->previous=record;	// make reverse link
184 			}
185 			aliasesHead=record;
186 			return(record);
187 		}
188 		DisposePtr(record);
189 	}
190 	return(NULL);
191 }
192 
UnInitAliases()193 void UnInitAliases()
194 // undo what InitAliases did
195 {
196 	STDisposeSymbolTable(aliasSymbols);
197 }
198 
InitAliases()199 bool InitAliases()
200 // initialize symbol table for aliases
201 {
202 	if((aliasSymbols=STNewSymbolTable(0)))
203 	{
204 		return(true);
205 	}
206 	return(false);
207 }
208