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 #include	"include.h"
18 
vReportDiagnostic(const char * format,va_list args)19 static void vReportDiagnostic(const char *format,va_list args)
20 // Display diagnostic messages
21 {
22 	if(displayDiagnostics)
23 	{
24 		vfprintf(stderr,format,args);
25 	}
26 }
27 
ReportDiagnostic(const char * format,...)28 void ReportDiagnostic(const char *format,...)
29 // Display diagnostic messages
30 {
31 	va_list
32 		args;
33 
34 	va_start(args,format);
35 	vReportDiagnostic(format,args);				// do actual reporting
36 	va_end(args);
37 }
38 
vReportMessage(const char * fileName,unsigned int lineNumber,const char * type,const char * format,va_list args)39 static void vReportMessage(const char *fileName,unsigned int lineNumber,const char *type,const char *format,va_list args)
40 // report messages (errors, warnings, etc...)
41 // type is a string which is descriptive of the message type
42 // This will report to the stderr.
43 // NOTE: this will report during any pass of assembly
44 {
45 	unsigned int
46 		length;
47 
48 	if(fileName)
49 	{
50 		length=strlen(fileName);
51 		if(length<16)			// work out how much to space over to the error message
52 		{
53 			length=16-length;
54 		}
55 		else
56 		{
57 			length=0;
58 		}
59 		fprintf(stderr,"%s:%-6d%*s:",fileName,lineNumber,length,"");
60 	}
61 	else
62 	{
63 		fprintf(stderr,"<command line>         :");
64 	}
65 	fprintf(stderr,"%s: ",type);
66 	vfprintf(stderr,format,args);
67 }
68 
ReportMessage(const char * fileName,unsigned int lineNumber,const char * type,const char * format,...)69 static void ReportMessage(const char *fileName,unsigned int lineNumber,const char *type,const char *format,...)
70 // report messages (errors, warnings, etc...)
71 // type is a string which is descriptive of the message type
72 // This will report to the stderr.
73 // NOTE: this will report during any pass of assembly
74 {
75 	va_list
76 		args;
77 
78 	va_start(args,format);
79 	vReportMessage(fileName,lineNumber,type,format,args);
80 	va_end(args);
81 }
82 
ReportVirtualPosition()83 static void ReportVirtualPosition()
84 // If the current file location and virtual position do not match up, report
85 // the virtual position
86 {
87 	if(currentVirtualFile&&(currentFile!=currentVirtualFile||currentFileLine!=currentVirtualFileLine))
88 	{
89 		ReportMessage(STNodeName(currentVirtualFile),currentVirtualFileLine,"^      ","Previous message generated indirectly from here\n");
90 	}
91 }
92 
vReportComplaint(WHERE_FROM * whereFrom,bool isError,const char * format,va_list args)93 static void vReportComplaint(WHERE_FROM *whereFrom,bool isError,const char *format,va_list args)
94 // This will report to the stderr.
95 // NOTE: this will report during any pass of assembly
96 // NOTE: whereFrom can be passed as NULL, in which case, the current
97 // location will be reported
98 // if isError is true, the comlpaint will be reported as an error,
99 // otherwise as a warning
100 {
101 	if(isError||displayWarnings)
102 	{
103 		if(whereFrom)
104 		{
105 			vReportMessage(whereFrom->file?STNodeName(whereFrom->file):NULL,whereFrom->fileLineNumber,isError?"error  ":"warning",format,args);
106 		}
107 		else
108 		{
109 			vReportMessage(currentFile?STNodeName(currentFile):NULL,currentFileLine,isError?"error  ":"warning",format,args);
110 			ReportVirtualPosition();
111 		}
112 		if(listFile&&outputListing)
113 		{
114 			if(isError)
115 			{
116 				fprintf(listFile,"**** ERROR:   ");
117 			}
118 			else
119 			{
120 				fprintf(listFile,"**** WARNING: ");
121 			}
122 			vfprintf(listFile,format,args);
123 		}
124 		if(isError)
125 		{
126 			errorCount++;
127 		}
128 		else
129 		{
130 			warningCount++;
131 		}
132 	}
133 }
134 
vReportSupplement(WHERE_FROM * whereFrom,const char * format,va_list args)135 static void vReportSupplement(WHERE_FROM *whereFrom,const char *format,va_list args)
136 // This will report to the stderr.
137 // NOTE: this will report during any pass of assembly
138 // NOTE: whereFrom can be passed as NULL, in which case, the current
139 // location will be reported
140 {
141 	if(whereFrom)
142 	{
143 		vReportMessage(whereFrom->file?STNodeName(whereFrom->file):NULL,whereFrom->fileLineNumber,"       ",format,args);
144 	}
145 	else
146 	{
147 		vReportMessage(currentFile?STNodeName(currentFile):NULL,currentFileLine,"       ",format,args);
148 		ReportVirtualPosition();
149 	}
150 }
151 
ReportComplaint(bool isError,const char * format,...)152 void ReportComplaint(bool isError,const char *format,...)
153 // if a hard error (failed to allocate memory, or open file, etc), or warning occurs while
154 // assembling, report it immediately with this function
155 // This will report to the stderr.
156 // NOTE: this will report during any pass of assembly
157 {
158 	va_list
159 		args;
160 
161 	va_start(args,format);
162 	vReportComplaint(NULL,isError,format,args);
163 	va_end(args);
164 }
165 
AssemblyComplaint(WHERE_FROM * whereFrom,bool isError,const char * format,...)166 void AssemblyComplaint(WHERE_FROM *whereFrom,bool isError,const char *format,...)
167 // Report assembly errors or warnings
168 // This will report to the stderr, as well as to the listing file if there is one
169 // NOTE: this only reports during the final pass of assembly
170 {
171 	va_list
172 		args;
173 
174 	if(!intermediatePass)
175 	{
176 		va_start(args,format);
177 		vReportComplaint(whereFrom,isError,format,args);
178 		va_end(args);
179 	}
180 }
181 
AssemblySupplement(WHERE_FROM * whereFrom,const char * format,...)182 void AssemblySupplement(WHERE_FROM *whereFrom,const char *format,...)
183 // Report supplementary information about an error or warning
184 // This will report to the stderr, as well as to the listing file if there is one
185 // NOTE: this only reports during the final pass of assembly
186 {
187 	va_list
188 		args;
189 
190 	if(!intermediatePass)
191 	{
192 		va_start(args,format);
193 		vReportSupplement(whereFrom,format,args);
194 		va_end(args);
195 	}
196 }
197 
CreateListStringValue(LISTING_RECORD * listingRecord,int value,bool unresolved)198 void CreateListStringValue(LISTING_RECORD *listingRecord,int value,bool unresolved)
199 // Create the listing output string for a value
200 {
201 	if(!unresolved)
202 	{
203 		sprintf(listingRecord->listObjectString,"(%08X)",value);
204 	}
205 	else
206 	{
207 		sprintf(listingRecord->listObjectString,"(???????\?)");	// see that '\'?? It's there because of the brilliant individual who invented trigraphs
208 	}
209 }
210 
OutputListFileHeader(time_t timeVal)211 void OutputListFileHeader(time_t timeVal)
212 // Dump the header information to the list file
213 {
214 	if(listFile)
215 	{
216 		timeVal=time(NULL);
217 		fprintf(listFile,"tpasm %s		Assembling on %s",VERSION,ctime(&timeVal));
218 		fprintf(listFile,"\n");
219 		fprintf(listFile,"Source File: %s\n",sourceFileName);
220 		fprintf(listFile,"\n");
221 		fprintf(listFile,"Line  Loc      Object/(Value) T	Source\n");
222 		fprintf(listFile,"----- -------- -------------- -	------\n");
223 	}
224 }
225 
GetNextWrapIndex(char * listObjectString,unsigned int * startIndex,unsigned int * endIndex)226 static void GetNextWrapIndex(char *listObjectString,unsigned int *startIndex,unsigned int *endIndex)
227 // look through the listObjectString, try to find good wrap points, return them
228 // NOTE: startIndex is passed in as the place to start working
229 // both startIndex and endIndex are modified
230 // startIndex will point to the end of the string when there is nothing
231 // more to print
232 {
233 	unsigned int
234 		bestEndIndex;
235 
236 	while(listObjectString[*startIndex]&&listObjectString[*startIndex]==' ')	// move through all the white at the start
237 	{
238 		(*startIndex)++;
239 	}
240 	bestEndIndex=(*endIndex)=(*startIndex);
241 	while(listObjectString[*endIndex]&&((*endIndex)-(*startIndex))<14)
242 	{
243 		if(listObjectString[*endIndex]==' ')
244 		{
245 			bestEndIndex=*endIndex;
246 		}
247 		(*endIndex)++;
248 	}
249 	if(listObjectString[*endIndex]==' ')									// check for space at the very end
250 	{
251 		bestEndIndex=*endIndex;
252 	}
253 	if(bestEndIndex==(*startIndex)||!listObjectString[*endIndex])			// if nothing good found, or at end, then set best to the end
254 	{
255 		bestEndIndex=(*endIndex);
256 	}
257 	(*endIndex)=bestEndIndex;												// this is the end
258 }
259 
OutputListFileLine(LISTING_RECORD * listingRecord,const char * sourceLine)260 void OutputListFileLine(LISTING_RECORD *listingRecord,const char *sourceLine)
261 // Output the listing line
262 // NOTE: this may generate more than one line if listingRecord->listObjectString is long
263 // the string will be wrapped (preferably on space boundaries) and written on
264 // subsequent lines
265 {
266 	unsigned int
267 		startIndex,
268 		endIndex;
269 
270 	if(!intermediatePass&&listFile&&outputListing&&listingRecord->wantList)
271 	{
272 		startIndex=0;
273 		GetNextWrapIndex(listingRecord->listObjectString,&startIndex,&endIndex);
274 		fprintf(listFile,"%-5d %08X %-14.*s %c	%s\n",listingRecord->lineNumber,listingRecord->listPC,endIndex-startIndex,&listingRecord->listObjectString[startIndex],listingRecord->sourceType,sourceLine);
275 
276 		startIndex=endIndex;
277 		GetNextWrapIndex(listingRecord->listObjectString,&startIndex,&endIndex);			// move to the next spot
278 		while(listingRecord->listObjectString[startIndex])									// if more to print, then do it
279 		{
280 			fprintf(listFile,"               %-14.*s %c\n",endIndex-startIndex,&listingRecord->listObjectString[startIndex],listingRecord->sourceType);
281 			startIndex=endIndex;
282 			GetNextWrapIndex(listingRecord->listObjectString,&startIndex,&endIndex);
283 		}
284 	}
285 }
286 
OutputListFileStats(unsigned int totalTime)287 void OutputListFileStats(unsigned int totalTime)
288 // Dump stats information to the list file
289 {
290 	unsigned int
291 		hours,minutes,seconds;
292 
293 	hours=totalTime/3600;
294 	totalTime-=(hours*3600);
295 	minutes=totalTime/60;
296 	totalTime-=(minutes*60);
297 	seconds=totalTime;
298 	ReportDiagnostic("\n");
299 	ReportDiagnostic("Assembled in %d passes\n",passCount+1);
300 	ReportDiagnostic("\n");
301 	ReportDiagnostic("Total assembly time %02d:%02d:%02d\n",hours,minutes,seconds);
302 	ReportDiagnostic("Total Errors:   %d\n",errorCount);
303 	ReportDiagnostic("Total Warnings: %d\n",warningCount);
304 
305 	if(listFile)
306 	{
307 		fprintf(listFile,"\n");
308 		fprintf(listFile,"Assembled in %d passes\n",passCount+1);
309 		fprintf(listFile,"\n");
310 		fprintf(listFile,"Total assembly time %02d:%02d:%02d\n",hours,minutes,seconds);
311 		fprintf(listFile,"Total Errors:   %d\n",errorCount);
312 		fprintf(listFile,"Total Warnings: %d\n",warningCount);
313 	}
314 }
315 
OutputListFileSegments()316 void OutputListFileSegments()
317 // Dump segment information to the list file
318 {
319 	if(listFile)
320 	{
321 		fprintf(listFile,"\n");
322 		DumpSegmentsListing(listFile);
323 	}
324 }
325 
CompareLabels(const void * i,const void * j)326 static int CompareLabels(const void *i,const void *j)
327 // compare the labels given by the entries i and j
328 // This is called by qsort
329 {
330 	LABEL_RECORD
331 		**recordA,
332 		**recordB;
333 
334 	recordA=(LABEL_RECORD **)i;
335 	recordB=(LABEL_RECORD **)j;
336 	return(strcmp(STNodeName((*recordA)->symbol),STNodeName((*recordB)->symbol)));
337 }
338 
OutputTextSymbols(FILE * file)339 bool OutputTextSymbols(FILE *file)
340 // Dump symbol information in a textual way to file
341 {
342 	LABEL_RECORD
343 		*label;
344 	unsigned int
345 		i,
346 		numLabels;
347 	LABEL_RECORD
348 		**sortArray;
349 
350 	numLabels=NumLabels();
351 	if((sortArray=(LABEL_RECORD **)NewPtr(sizeof(LABEL_RECORD *)*numLabels)))
352 	{
353 		label=labelsHead;
354 		for(i=0;i<numLabels;i++)		// make array of pointers to labels
355 		{
356 			sortArray[i]=label;
357 			label=label->next;
358 		}
359 
360 		qsort(sortArray,numLabels,sizeof(LABEL_RECORD *),CompareLabels);	// sort the array
361 
362 		fprintf(file,"Symbol Table Listing\n");
363 		fprintf(file,"Value    U Name\n");
364 		fprintf(file,"-------- - ----\n");
365 
366 		for(i=0;i<numLabels;i++)		// make array of pointers to labels
367 		{
368 			label=sortArray[i];
369 			if(label->resolved)
370 			{
371 				fprintf(file,"%08X %c %s\n",label->value,(label->refCount==0)?'*':' ',STNodeName(label->symbol));
372 			}
373 			else
374 			{
375 				fprintf(file,"????????   %s\n",STNodeName(label->symbol));
376 			}
377 		}
378 
379 		DisposePtr(sortArray);
380 	}
381 	return(true);
382 }
383 
OutputListFileLabels()384 void OutputListFileLabels()
385 // Dump symbol information to the list file
386 {
387 	if(listFile)
388 	{
389 		fprintf(listFile,"\n");
390 		OutputTextSymbols(listFile);
391 	}
392 }
393