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