mmixallib.ch 8.86 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
This file has been written by Felix Albrecht and was modified by Martin Ruckert.

We start by adding a preprocessor definition to disable warnings
about deprecated functions, like strcpy or sprintf, and 
include mmixlib.h at the start of the sybroutines 
to declare the extern library interface.

@x
@<Preprocessor definitions@>=
@y
@<Sub...@>=
#include "mmixlib.h"
#include "libname.h"

@ @<Global...@>=
static jmp_buf error_exit;

@ @<Preprocessor definitions@>=
#include <setjmp.h>
20
21
22
#ifdef MMIX_PRINT
extern int mmix_printf(char *format,...);
#define printf(...) mmix_printf(__VA_ARGS__)
23
#endif
24
#ifdef WIN32
25
#pragma warning(disable : 4996)
26
#endif
27
28
29
30
31
32
33
#define _MMIXAL_
@z

We change error messages that handle errors in the command line 
(there is none). Errors are no longer written to stderr.

@x
34
35
36
    fprintf(stderr,
       "(say `-b <number>' to increase the length of my input buffer)\n");
@y
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    err("*use the Options dialog to increase the length of my input buffer");
@z

Besides filenames, we need to keep track
of external file numbers.

@x
Char *filename[257];
@y
Char *filename[257];
static int file_no[257];
@z

Whenever we enter a new filename, we look up
the external file number for it.

@x
54
        filename_count++;
55
@y
56
57
        file_no[filename_count]=filename2file(filename[filename_count],filename_count);
        filename_count++;
58
59
60
61
62
@z


Next we change the way errors are reported:

63
64
65
66
67
68
69
70
71
72
73
74
@x
  if (message[0]=='*')
    fprintf(stderr,"\"%s\", line %d warning: %s\n",
                 filename[cur_file],line_no,message+1);
  else if (message[0]=='!')
    fprintf(stderr,"\"%s\", line %d fatal error: %s\n",
                 filename[cur_file],line_no,message+1);
  else {
    fprintf(stderr,"\"%s\", line %d: %s!\n",
                 filename[cur_file],line_no,message);
    err_count++;
  }
75
@y
76
77
78
79
80
81
82
83
84
85
86
  if (message[0]=='*'){
    mmixal_error(message+1,file_no[cur_file],line_no,1);
    err_count+=0x1;
    }
  else if (message[0]=='!') {
    mmixal_error(message+1,file_no[cur_file],line_no,-1);
    err_count=-2;
  }
  else {
    mmixal_error(message,file_no[cur_file],line_no,0);
    err_count+=0x10000;
87
88
89
90
91
92
93
94
95
96
97
98
99
  }
@z                 


The error exit is redirected using a longjmp.

@x
  if (message[0]=='!') exit(-2);
@y
  if (message[0]=='!') 
    longjmp(error_exit,-2);
@z

100
101
102
103
@x
int err_count; /* this many errors were found */
@y
int err_count; /* negativ for fatal erros else (erros<<16)+warnings */
104
105
106
107
108
109
110
@z

In the assemble subroutine, we have the
opportunity to gain some information about
the association of lines and locations.

@x
111
  for (j=0;j<k;j++) {
112
113
114
115
116
117
118
119
@y
 add_line_loc(file_no[cur_file], line_no, cur_loc);
 for (j=0;j<k;j++) {
@z

We allocate tree nodes node by node so that we can free them again.

@x
120
121
122
123
124
125
126
127
  register trie_node *t=next_trie_node;
  if (t==last_trie_node) {
    t=(trie_node*)calloc(1000,sizeof(trie_node));
    if (!t) panic("Capacity exceeded: Out of trie memory");
@.Capacity exceeded...@>
    last_trie_node=t+1000;
  }
  next_trie_node=t+1;
128
129
  return t;
@y
130
131
  trie_node *t=(trie_node*)calloc(1,sizeof(trie_node));
  if (!t) panic("Capacity exceeded: Out of trie memory");
132
133
134
135
136
137
  return t;
@z

We need extra information in the symbol table.

@x
138
typedef struct sym_tab_struct {
139
@y
140
141
142
typedef struct sym_tab_struct {
  int file_no;
  int line_no;
143
144
145
146
147
@z

We allocat single sym nodes to be able to free them.

@x
148
149
150
151
152
153
154
155
156
157
158
159
    p=next_sym_node;
    if (p==last_sym_node) {
      p=(sym_node*)calloc(1000,sizeof(sym_node));
      if (!p) panic("Capacity exceeded: Out of symbol memory");
@.Capacity exceeded...@>
      last_sym_node=p+1000;
    }
    next_sym_node=p+1;
@y
    p=(sym_node*)calloc(1,sizeof(sym_node));
    if (!p) panic("Capacity exceeded: Out of symbol memory");
@z   
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

The special names are already defined in mmix-sim.w

@x
Char *special_name[32]={"rB","rD","rE","rH","rJ","rM","rR","rBB",
 "rC","rN","rO","rS","rI","rT","rTT","rK","rQ","rU","rV","rG","rL",
 "rA","rF","rP","rW","rX","rY","rZ","rWW","rXX","rYY","rZZ"};
@y
extern Char *special_name[32];

@z

Errors generated at the end of the assembly should use the
normal error reporting macros.

@x
176
177
178
  fprintf(stderr,"undefined symbol: %s\n",sym_buf+1);
@.undefined symbol@>
  err_count++;
179
@y
180
  sprintf(err_buf,"undefined symbol: %s",sym_buf+1);
181
  report_error(err_buf);
182
183
@.undefined symbol@>
  err_count+=0x10000;
184
185
186
187
188
@z

when a sym_node becomes DEFINED, we record file and line.

@x
189
190
191
192
193
  @<Find the symbol table node, |pp|@>;
@y
  @<Find the symbol table node, |pp|@>;
  pp->file_no=file_no[cur_file];
  pp->line_no=line_no;  
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
@z




Some global variables need to be static to
avoid name conflicts in the library.

@x
tetra z,y,x,yz,xyz; /* pieces for assembly */
@y
static tetra z,y,x,yz,xyz; /* pieces for assembly */
@z

The main() program becomes mmixal().

@x
211
212
213
214
215
216
217
218
219
220
221
222
@c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
@#
@<Preprocessor definitions@>@;
@<Type definitions@>@;
@<Global variables@>@;
@<Subroutines@>@;
@#
223
224
225
int main(argc,argv)
  int argc;@+
  char *argv[];
226
227
228
{
  register int j,k; /* all-purpose integers */
  @<Local variables@>;
229
  @<Process the command line@>;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  @<Initialize everything@>;
  while(1) {
    @<Get the next line of input text, or |break| if the input has ended@>;
    while(1) {
      @<Process the next \MMIXAL\ instruction or comment@>;
      if (!*buf_ptr) break;
    }
    if (listing_file) {
      if (listing_bits) listing_clear();
      else if (!line_listed) flush_listing_line("                   ");
    }
  }
  @<Finish the assembly@>;
}
244
@y
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
@c
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
@#
@<Preprocessor definitions@>@;
@<Type definitions@>@;
@#
int main(argc,argv)
  int argc;@+
  char *argv[];
{
  register int j,k; /* all-purpose integers */
  @<Local variables@>;
  @<Process the command line@>;
  return mmixal(mms_name, mmo_name, mml_name, x_option, b_option);
}

@ @(libmmixal.c@>=
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
@#
@h
@<Preprocessor definitions@>@;
@<Type definitions@>@;
@<Global variables@>@;
@<Subroutines@>@;
@#
int mmixal(char *mms_name, char *mmo_name, char *mml_name, int x_option, int b_option)
{
  register int j,k; /* all-purpose integers */
  @<Local variables@>;
  /* instead of processing the commandline */
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
  err_count=setjmp(error_exit);
  if (err_count!=0){
   prune(trie_root);
   goto clean_up;
  }
  if (mms_name==NULL)
    panic("No input file name");
  src_file_name= mms_name;
  if (mmo_name==NULL)
    obj_file_name[0]=0;
  else
    strncpy(obj_file_name,mmo_name,FILENAME_MAX);
  if (mml_name==NULL)
    listing_name[0]=0;
  else
    strncpy(listing_name,mml_name,FILENAME_MAX);
  expanding = x_option;
  buf_size = b_option;
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    cur_file=0;
  line_no=0;
  long_warning_given=0;
  cur_loc.h=cur_loc.l=0;
  listing_loc.h=listing_loc.l=0;
  spec_mode= 0;
  spec_mode_loc= 0;
  mmo_ptr=0;
  err_count=0;
  serial_number=0;
  filename_count=0;
  for (j=0;j<10;j++)
  { forward_local[j].link=0;
    backward_local[j].link=0;
  }
  greg= 255;
317
  lreg= 32;
318
319
320
321
322
323
324
325
326
327
328
329
330
331
  @<Initialize everything@>;
  while(1) {
    @<Get the next line of input text, or |break| if the input has ended@>;
    while(1) {
      @<Process the next \MMIXAL\ instruction or comment@>;
      if (!*buf_ptr) break;
    }
    if (listing_file) {
      if (listing_bits) listing_clear();
      else if (!line_listed) flush_listing_line("                   ");
    }
  }
  @<Finish the assembly@>;
}
332
333
334
335
336
@z

We assign the source file to filename[0]
and set also file_no[0]
@x
337
filename[0]=src_file_name;
338
339
filename_count=1;
@y
340
341
filename[0]=src_file_name;
file_no[0]=filename2file(src_file_name,0);
342
343
344
345
346
347
filename_count=1;
@z

We end with return instead of exit.

@x
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
if (err_count) {
  if (err_count>1) fprintf(stderr,"(%d errors were found.)\n",err_count);
  else fprintf(stderr,"(One error was found.)\n");
}
exit(err_count);
@y
  if (err_count>0){
    sprintf(err_buf,"%d errors and %d warnings were found.",err_count>>16, err_count&0xFFFF);
    report_error(err_buf);
  }
clean_up:
  if (listing_file!=NULL) 
  { fclose(listing_file);
    listing_file=NULL;
  }
  if (obj_file!=NULL) 
  { fclose(obj_file);
    obj_file=NULL;
  }
  if (src_file!=NULL) 
  { fclose(src_file);
    src_file=NULL;
  }
  cur_file=0;
  line_no=0;
  long_warning_given=0;
  cur_loc.h=cur_loc.l=0;
  listing_loc.h=listing_loc.l=0;
  spec_mode= 0;
  spec_mode_loc= 0;
  serial_number=0;
  free(buffer); buffer=NULL;
  free(lab_field); lab_field=NULL;
  free(op_field); op_field=NULL;
  free(operand_list); operand_list=NULL;
  free(err_buf);err_buf=NULL;
  free(op_stack); op_stack=NULL;
  free(val_stack);val_stack=NULL;
  filename[0]=NULL;
  filename_passed[0]=0;
  for (j=1;j<filename_count;j++)
  { free(filename[j]);
    filename[j]=NULL;
	filename_passed[j]=0;
  }
  filename_count=0;
  
395
396
397
398
399
400
401
return err_count;
@z

To report undefined local sysmbols we use the
usual error reporting.

@x
402
403
404
405
406
407
408
  err_count++,fprintf(stderr,"undefined local symbol %dF\n",j);
@y
  { err_count+=0x10000;
    sprintf(err_buf,"undefined local symbol %dF\n",j);
    report_error(err_buf);
  }
@z