NASM 0.96
[platform/upstream/nasm.git] / nasmlib.c
1 /* nasmlib.c    library routines for the Netwide Assembler
2  *
3  * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4  * Julian Hall. All rights reserved. The software is
5  * redistributable under the licence given in the file "Licence"
6  * distributed in the NASM archive.
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <ctype.h>
13
14 #include "nasm.h"
15 #include "nasmlib.h"
16
17 static efunc nasm_malloc_error;
18
19 #ifdef LOGALLOC
20 static FILE *logfp;
21 #endif
22
23 void nasm_set_malloc_error (efunc error) {
24     nasm_malloc_error = error;
25 #ifdef LOGALLOC
26     logfp = fopen ("malloc.log", "w");
27     setvbuf (logfp, NULL, _IOLBF, BUFSIZ);
28     fprintf (logfp, "null pointer is %p\n", NULL);
29 #endif
30 }
31
32 #ifdef LOGALLOC
33 void *nasm_malloc_log (char *file, int line, size_t size)
34 #else
35 void *nasm_malloc (size_t size)
36 #endif
37 {
38     void *p = malloc(size);
39     if (!p)
40         nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory");
41 #ifdef LOGALLOC
42     else
43         fprintf(logfp, "%s %d malloc(%ld) returns %p\n",
44                 file, line, (long)size, p);
45 #endif
46     return p;
47 }
48
49 #ifdef LOGALLOC
50 void *nasm_realloc_log (char *file, int line, void *q, size_t size)
51 #else
52 void *nasm_realloc (void *q, size_t size)
53 #endif
54 {
55     void *p = q ? realloc(q, size) : malloc(size);
56     if (!p)
57         nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory");
58 #ifdef LOGALLOC
59     else if (q)
60         fprintf(logfp, "%s %d realloc(%p,%ld) returns %p\n",
61                 file, line, q, (long)size, p);
62     else
63         fprintf(logfp, "%s %d malloc(%ld) returns %p\n",
64                 file, line, (long)size, p);
65 #endif
66     return p;
67 }
68
69 #ifdef LOGALLOC
70 void nasm_free_log (char *file, int line, void *q)
71 #else
72 void nasm_free (void *q)
73 #endif
74 {
75     if (q) {
76         free (q);
77 #ifdef LOGALLOC
78         fprintf(logfp, "%s %d free(%p)\n",
79                 file, line, q);
80 #endif
81     }
82 }
83
84 #ifdef LOGALLOC
85 char *nasm_strdup_log (char *file, int line, char *s)
86 #else
87 char *nasm_strdup (char *s)
88 #endif
89 {
90     char *p;
91     int size = strlen(s)+1;
92
93     p = malloc(size);
94     if (!p)
95         nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory");
96 #ifdef LOGALLOC
97     else
98         fprintf(logfp, "%s %d strdup(%ld) returns %p\n",
99                 file, line, (long)size, p);
100 #endif
101     strcpy (p, s);
102     return p;
103 }
104
105 #ifdef LOGALLOC
106 char *nasm_strndup_log (char *file, int line, char *s, size_t len)
107 #else
108 char *nasm_strndup (char *s, size_t len)
109 #endif
110 {
111     char *p;
112     int size = len+1;
113
114     p = malloc(size);
115     if (!p)
116         nasm_malloc_error (ERR_FATAL | ERR_NOFILE, "out of memory");
117 #ifdef LOGALLOC
118     else
119         fprintf(logfp, "%s %d strndup(%ld) returns %p\n",
120                 file, line, (long)size, p);
121 #endif
122     strncpy (p, s, len);
123     p[len] = '\0';
124     return p;
125 }
126
127 int nasm_stricmp (char *s1, char *s2) {
128     while (*s1 && toupper(*s1) == toupper(*s2))
129         s1++, s2++;
130     if (!*s1 && !*s2)
131         return 0;
132     else if (toupper(*s1) < toupper(*s2))
133         return -1;
134     else
135         return 1;
136 }
137
138 int nasm_strnicmp (char *s1, char *s2, int n) {
139     while (n > 0 && *s1 && toupper(*s1) == toupper(*s2))
140         s1++, s2++, n--;
141     if ((!*s1 && !*s2) || n==0)
142         return 0;
143     else if (toupper(*s1) < toupper(*s2))
144         return -1;
145     else
146         return 1;
147 }
148
149 #define lib_isnumchar(c)   ( isalnum(c) || (c) == '$')
150 #define numvalue(c)  ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')
151
152 long readnum (char *str, int *error) {
153     char *r = str, *q;
154     long radix;
155     unsigned long result, checklimit;
156     int warn = FALSE;
157
158     *error = FALSE;
159
160     while (isspace(*r)) r++;           /* find start of number */
161     q = r;
162
163     while (lib_isnumchar(*q)) q++;     /* find end of number */
164
165     /*
166      * If it begins 0x, 0X or $, or ends in H, it's in hex. if it
167      * ends in Q, it's octal. if it ends in B, it's binary.
168      * Otherwise, it's ordinary decimal.
169      */
170     if (*r=='0' && (r[1]=='x' || r[1]=='X'))
171         radix = 16, r += 2;
172     else if (*r=='$')
173         radix = 16, r++;
174     else if (q[-1]=='H' || q[-1]=='h')
175         radix = 16 , q--;
176     else if (q[-1]=='Q' || q[-1]=='q')
177         radix = 8 , q--;
178     else if (q[-1]=='B' || q[-1]=='b')
179         radix = 2 , q--;
180     else
181         radix = 10;
182
183     /*
184      * If this number has been found for us by something other than
185      * the ordinary scanners, then it might be malformed by having
186      * nothing between the prefix and the suffix. Check this case
187      * now.
188      */
189     if (r >= q) {
190         *error = TRUE;
191         return 0;
192     }
193
194     /*
195      * `checklimit' must be 2**32 / radix. We can't do that in
196      * 32-bit arithmetic, which we're (probably) using, so we
197      * cheat: since we know that all radices we use are even, we
198      * can divide 2**31 by radix/2 instead.
199      */
200     checklimit = 0x80000000UL / (radix>>1);
201
202     result = 0;
203     while (*r && r < q) {
204         if (*r<'0' || (*r>'9' && *r<'A') || numvalue(*r)>=radix) {
205             *error = TRUE;
206             return 0;
207         }
208         if (result >= checklimit)
209             warn = TRUE;
210         result = radix * result + numvalue(*r);
211         r++;
212     }
213
214     if (warn)
215         nasm_malloc_error (ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV,
216                            "numeric constant %s does not fit in 32 bits",
217                            str);
218
219     return result;
220 }
221
222 static long next_seg;
223
224 void seg_init(void) {
225     next_seg = 0;
226 }
227
228 long seg_alloc(void) {
229     return (next_seg += 2) - 2;
230 }
231
232 void fwriteshort (int data, FILE *fp) {
233     fputc ((int) (data & 255), fp);
234     fputc ((int) ((data >> 8) & 255), fp);
235 }
236
237 void fwritelong (long data, FILE *fp) {
238     fputc ((int) (data & 255), fp);
239     fputc ((int) ((data >> 8) & 255), fp);
240     fputc ((int) ((data >> 16) & 255), fp);
241     fputc ((int) ((data >> 24) & 255), fp);
242 }
243
244 void standard_extension (char *inname, char *outname, char *extension,
245                          efunc error) {
246     char *p, *q;
247
248     if (*outname)                      /* file name already exists, */
249         return;                        /* so do nothing */
250     q = inname;
251     p = outname;
252     while (*q) *p++ = *q++;            /* copy, and find end of string */
253     *p = '\0';                         /* terminate it */
254     while (p > outname && *--p != '.');/* find final period (or whatever) */
255     if (*p != '.') while (*p) p++;     /* go back to end if none found */
256     if (!strcmp(p, extension)) {       /* is the extension already there? */
257         if (*extension)
258             error(ERR_WARNING | ERR_NOFILE,
259                   "file name already ends in `%s': "
260                   "output will be in `nasm.out'",
261                   extension);
262         else
263             error(ERR_WARNING | ERR_NOFILE,
264                   "file name already has no extension: "
265                   "output will be in `nasm.out'");
266         strcpy(outname, "nasm.out");
267     } else
268         strcpy(p, extension);
269 }
270
271 #define RAA_BLKSIZE 4096               /* this many longs allocated at once */
272 #define RAA_LAYERSIZE 1024             /* this many _pointers_ allocated */
273
274 typedef struct RAA RAA;
275 typedef union RAA_UNION RAA_UNION;
276 typedef struct RAA_LEAF RAA_LEAF;
277 typedef struct RAA_BRANCH RAA_BRANCH;
278
279 struct RAA {
280     /*
281      * Number of layers below this one to get to the real data. 0
282      * means this structure is a leaf, holding RAA_BLKSIZE real
283      * data items; 1 and above mean it's a branch, holding
284      * RAA_LAYERSIZE pointers to the next level branch or leaf
285      * structures.
286      */
287     int layers;
288     /*
289      * Number of real data items spanned by one position in the
290      * `data' array at this level. This number is 1, trivially, for
291      * a leaf (level 0): for a level 1 branch it should be
292      * RAA_BLKSIZE, and for a level 2 branch it's
293      * RAA_LAYERSIZE*RAA_BLKSIZE.
294      */
295     long stepsize;
296     union RAA_UNION {
297         struct RAA_LEAF {
298             long data[RAA_BLKSIZE];
299         } l;
300         struct RAA_BRANCH {
301             struct RAA *data[RAA_LAYERSIZE];
302         } b;
303     } u;
304 };
305
306 #define LEAFSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_LEAF))
307 #define BRANCHSIZ (sizeof(RAA)-sizeof(RAA_UNION)+sizeof(RAA_BRANCH))
308
309 #define LAYERSIZ(r) ( (r)->layers==0 ? RAA_BLKSIZE : RAA_LAYERSIZE )
310
311 static struct RAA *real_raa_init (int layers) {
312     struct RAA *r;
313
314     if (layers == 0) {
315         r = nasm_malloc (LEAFSIZ);
316         memset (r->u.l.data, 0, sizeof(r->u.l.data));
317         r->layers = 0;
318         r->stepsize = 1L;
319     } else {
320         r = nasm_malloc (BRANCHSIZ);
321         memset (r->u.b.data, 0, sizeof(r->u.b.data));
322         r->layers = layers;
323         r->stepsize = RAA_BLKSIZE;
324         while (--layers)
325             r->stepsize *= RAA_LAYERSIZE;
326     }
327     return r;
328 }
329
330 struct RAA *raa_init (void) {
331     return real_raa_init (0);
332 }
333
334 void raa_free (struct RAA *r) {
335     if (r->layers == 0)
336         nasm_free (r);
337     else {
338         struct RAA **p;
339         for (p = r->u.b.data; p - r->u.b.data < RAA_LAYERSIZE; p++)
340             if (*p)
341                 raa_free (*p);
342     }
343 }
344
345 long raa_read (struct RAA *r, long posn) {
346     if (posn > r->stepsize * LAYERSIZ(r))
347         return 0L;
348     while (r->layers > 0) {
349         ldiv_t l;
350         l = ldiv (posn, r->stepsize);
351         r = r->u.b.data[l.quot];
352         posn = l.rem;
353         if (!r)                        /* better check this */
354             return 0L;
355     }
356     return r->u.l.data[posn];
357 }
358
359 struct RAA *raa_write (struct RAA *r, long posn, long value) {
360     struct RAA *result;
361
362     if (posn < 0)
363         nasm_malloc_error (ERR_PANIC, "negative position in raa_write");
364
365     while (r->stepsize * LAYERSIZ(r) < posn) {
366         /*
367          * Must go up a layer.
368          */
369         struct RAA *s;
370
371         s = nasm_malloc (BRANCHSIZ);
372         memset (s->u.b.data, 0, sizeof(r->u.b.data));
373         s->layers = r->layers + 1;
374         s->stepsize = RAA_LAYERSIZE * r->stepsize;
375         s->u.b.data[0] = r;
376         r = s;
377     }
378
379     result = r;
380
381     while (r->layers > 0) {
382         ldiv_t l;
383         struct RAA **s;
384         l = ldiv (posn, r->stepsize);
385         s = &r->u.b.data[l.quot];
386         if (!*s)
387             *s = real_raa_init (r->layers - 1);
388         r = *s;
389         posn = l.rem;
390     }
391
392     r->u.l.data[posn] = value;
393
394     return result;
395 }
396
397 #define SAA_MAXLEN 8192
398
399 struct SAA {
400     /*
401      * members `end' and `elem_len' are only valid in first link in
402      * list; `rptr' and `rpos' are used for reading
403      */
404     struct SAA *next, *end, *rptr;
405     long elem_len, length, posn, start, rpos;
406     char *data;
407 };
408
409 struct SAA *saa_init (long elem_len) {
410     struct SAA *s;
411
412     if (elem_len > SAA_MAXLEN)
413         nasm_malloc_error (ERR_PANIC | ERR_NOFILE, "SAA with huge elements");
414
415     s = nasm_malloc (sizeof(struct SAA));
416     s->posn = s->start = 0L;
417     s->elem_len = elem_len;
418     s->length = SAA_MAXLEN - (SAA_MAXLEN % elem_len);
419     s->data = nasm_malloc (s->length);
420     s->next = NULL;
421     s->end = s;
422
423     return s;
424 }
425
426 void saa_free (struct SAA *s) {
427     struct SAA *t;
428
429     while (s) {
430         t = s->next;
431         nasm_free (s->data);
432         nasm_free (s);
433         s = t;
434     }
435 }
436
437 void *saa_wstruct (struct SAA *s) {
438     void *p;
439
440     if (s->end->length - s->end->posn < s->elem_len) {
441         s->end->next = nasm_malloc (sizeof(struct SAA));
442         s->end->next->start = s->end->start + s->end->posn;
443         s->end = s->end->next;
444         s->end->length = s->length;
445         s->end->next = NULL;
446         s->end->posn = 0L;
447         s->end->data = nasm_malloc (s->length);
448     }
449
450     p = s->end->data + s->end->posn;
451     s->end->posn += s->elem_len;
452     return p;
453 }
454
455 void saa_wbytes (struct SAA *s, void *data, long len) {
456     char *d = data;
457
458     while (len > 0) {
459         long l = s->end->length - s->end->posn;
460         if (l > len)
461             l = len;
462         if (l > 0) {
463             if (d) {
464                 memcpy (s->end->data + s->end->posn, d, l);
465                 d += l;
466             } else
467                 memset (s->end->data + s->end->posn, 0, l);
468             s->end->posn += l;
469             len -= l;
470         }
471         if (len > 0) {
472             s->end->next = nasm_malloc (sizeof(struct SAA));
473             s->end->next->start = s->end->start + s->end->posn;
474             s->end = s->end->next;
475             s->end->length = s->length;
476             s->end->next = NULL;
477             s->end->posn = 0L;
478             s->end->data = nasm_malloc (s->length);
479         }
480     }
481 }
482
483 void saa_rewind (struct SAA *s) {
484     s->rptr = s;
485     s->rpos = 0L;
486 }
487
488 void *saa_rstruct (struct SAA *s) {
489     void *p;
490
491     if (!s->rptr)
492         return NULL;
493
494     if (s->rptr->posn - s->rpos < s->elem_len) {
495         s->rptr = s->rptr->next;
496         if (!s->rptr)
497             return NULL;               /* end of array */
498         s->rpos = 0L;
499     }
500
501     p = s->rptr->data + s->rpos;
502     s->rpos += s->elem_len;
503     return p;
504 }
505
506 void *saa_rbytes (struct SAA *s, long *len) {
507     void *p;
508
509     if (!s->rptr)
510         return NULL;
511
512     p = s->rptr->data + s->rpos;
513     *len = s->rptr->posn - s->rpos;
514     s->rptr = s->rptr->next;
515     s->rpos = 0L;
516     return p;
517 }
518
519 void saa_rnbytes (struct SAA *s, void *data, long len) {
520     char *d = data;
521
522     while (len > 0) {
523         long l;
524
525         if (!s->rptr)
526             return;
527
528         l = s->rptr->posn - s->rpos;
529         if (l > len)
530             l = len;
531         if (l > 0) {
532             memcpy (d, s->rptr->data + s->rpos, l);
533             d += l;
534             s->rpos += l;
535             len -= l;
536         }
537         if (len > 0) {
538             s->rptr = s->rptr->next;
539             s->rpos = 0L;
540         }
541     }
542 }
543
544 void saa_fread (struct SAA *s, long posn, void *data, long len) {
545     struct SAA *p;
546     long pos;
547     char *cdata = data;
548
549     if (!s->rptr || posn > s->rptr->start + s->rpos)
550         saa_rewind (s);
551     while (posn >= s->rptr->start + s->rptr->posn) {
552         s->rptr = s->rptr->next;
553         if (!s->rptr)
554             return;                    /* what else can we do?! */
555     }
556
557     p = s->rptr;
558     pos = posn - s->rptr->start;
559     while (len) {
560         long l = s->rptr->posn - pos;
561         if (l > len)
562             l = len;
563         memcpy (cdata, s->rptr->data+pos, l);
564         len -= l;
565         cdata += l;
566         p = p->next;
567         if (!p)
568             return;
569         pos = 0L;
570     }
571 }
572
573 void saa_fwrite (struct SAA *s, long posn, void *data, long len) {
574     struct SAA *p;
575     long pos;
576     char *cdata = data;
577
578     if (!s->rptr || posn > s->rptr->start + s->rpos)
579         saa_rewind (s);
580     while (posn >= s->rptr->start + s->rptr->posn) {
581         s->rptr = s->rptr->next;
582         if (!s->rptr)
583             return;                    /* what else can we do?! */
584     }
585
586     p = s->rptr;
587     pos = posn - s->rptr->start;
588     while (len) {
589         long l = s->rptr->posn - pos;
590         if (l > len)
591             l = len;
592         memcpy (s->rptr->data+pos, cdata, l);
593         len -= l;
594         cdata += l;
595         p = p->next;
596         if (!p)
597             return;
598         pos = 0L;
599     }
600 }
601
602 void saa_fpwrite (struct SAA *s, FILE *fp) {
603     char *data;
604     long len;
605
606     saa_rewind (s);
607     while ( (data = saa_rbytes (s, &len)) )
608         fwrite (data, 1, len, fp);
609 }
610
611 /*
612  * Register, instruction, condition-code and prefix keywords used
613  * by the scanner.
614  */
615 #include "names.c"
616 static char *special_names[] = {
617     "byte", "dword", "far", "long", "near", "nosplit", "qword",
618     "short", "to", "tword", "word"
619 };
620 static char *prefix_names[] = {
621     "a16", "a32", "lock", "o16", "o32", "rep", "repe", "repne",
622     "repnz", "repz", "times"
623 };
624
625
626 /*
627  * Standard scanner routine used by parser.c and some output
628  * formats. It keeps a succession of temporary-storage strings in
629  * stdscan_tempstorage, which can be cleared using stdscan_reset.
630  */
631 static char **stdscan_tempstorage = NULL;
632 static int stdscan_tempsize = 0, stdscan_templen = 0;
633 #define STDSCAN_TEMP_DELTA 256
634
635 static void stdscan_pop(void) {
636     nasm_free (stdscan_tempstorage[--stdscan_templen]);
637 }
638
639 void stdscan_reset(void) {
640     while (stdscan_templen > 0)
641         stdscan_pop();
642 }
643
644 static char *stdscan_copy(char *p, int len) {
645     char *text;
646
647     text = nasm_malloc(len+1);
648     strncpy (text, p, len);
649     text[len] = '\0';
650
651     if (stdscan_templen >= stdscan_tempsize) {
652         stdscan_tempsize += STDSCAN_TEMP_DELTA;
653         stdscan_tempstorage = nasm_realloc(stdscan_tempstorage,
654                                            stdscan_tempsize*sizeof(char *));
655     }
656     stdscan_tempstorage[stdscan_templen++] = text;
657
658     return text;
659 }
660
661 char *stdscan_bufptr = NULL;
662 int stdscan (void *private_data, struct tokenval *tv) {
663     char ourcopy[256], *r, *s;
664
665     while (isspace(*stdscan_bufptr)) stdscan_bufptr++;
666     if (!*stdscan_bufptr)
667         return tv->t_type = 0;
668
669     /* we have a token; either an id, a number or a char */
670     if (isidstart(*stdscan_bufptr) ||
671         (*stdscan_bufptr == '$' && isidstart(stdscan_bufptr[1]))) {
672         /* now we've got an identifier */
673         int i;
674         int is_sym = FALSE;
675
676         if (*stdscan_bufptr == '$') {
677             is_sym = TRUE;
678             stdscan_bufptr++;
679         }
680
681         r = stdscan_bufptr++;
682         while (isidchar(*stdscan_bufptr)) stdscan_bufptr++;
683         tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
684
685         for (s=tv->t_charptr, r=ourcopy; *s; s++)
686             *r++ = tolower (*s);
687         *r = '\0';
688         if (is_sym)
689             return tv->t_type = TOKEN_ID;/* bypass all other checks */
690         /* right, so we have an identifier sitting in temp storage. now,
691          * is it actually a register or instruction name, or what? */
692         if ((tv->t_integer=bsi(ourcopy, reg_names,
693                                elements(reg_names)))>=0) {
694             tv->t_integer += EXPR_REG_START;
695             return tv->t_type = TOKEN_REG;
696         } else if ((tv->t_integer=bsi(ourcopy, insn_names,
697                                       elements(insn_names)))>=0) {
698             return tv->t_type = TOKEN_INSN;
699         }
700         for (i=0; i<elements(icn); i++)
701             if (!strncmp(ourcopy, icn[i], strlen(icn[i]))) {
702                 char *p = ourcopy + strlen(icn[i]);
703                 tv->t_integer = ico[i];
704                 if ((tv->t_inttwo=bsi(p, conditions,
705                                          elements(conditions)))>=0)
706                     return tv->t_type = TOKEN_INSN;
707             }
708         if ((tv->t_integer=bsi(ourcopy, prefix_names,
709                                   elements(prefix_names)))>=0) {
710             tv->t_integer += PREFIX_ENUM_START;
711             return tv->t_type = TOKEN_PREFIX;
712         }
713         if ((tv->t_integer=bsi(ourcopy, special_names,
714                                   elements(special_names)))>=0)
715             return tv->t_type = TOKEN_SPECIAL;
716         if (!strcmp(ourcopy, "seg"))
717             return tv->t_type = TOKEN_SEG;
718         if (!strcmp(ourcopy, "wrt"))
719             return tv->t_type = TOKEN_WRT;
720         return tv->t_type = TOKEN_ID;
721     } else if (*stdscan_bufptr == '$' && !isnumchar(stdscan_bufptr[1])) {
722         /*
723          * It's a $ sign with no following hex number; this must
724          * mean it's a Here token ($), evaluating to the current
725          * assembly location, or a Base token ($$), evaluating to
726          * the base of the current segment.
727          */
728         stdscan_bufptr++;
729         if (*stdscan_bufptr == '$') {
730             stdscan_bufptr++;
731             return tv->t_type = TOKEN_BASE;
732         }
733         return tv->t_type = TOKEN_HERE;
734     } else if (isnumstart(*stdscan_bufptr)) {  /* now we've got a number */
735         int rn_error;
736
737         r = stdscan_bufptr++;
738         while (isnumchar(*stdscan_bufptr))
739             stdscan_bufptr++;
740
741         if (*stdscan_bufptr == '.') {
742             /*
743              * a floating point constant
744              */
745             stdscan_bufptr++;
746             while (isnumchar(*stdscan_bufptr)) {
747                 stdscan_bufptr++;
748             }
749             tv->t_charptr = stdscan_copy(r, stdscan_bufptr - r);
750             return tv->t_type = TOKEN_FLOAT;
751         }
752         r = stdscan_copy(r, stdscan_bufptr - r);
753         tv->t_integer = readnum(r, &rn_error);
754         stdscan_pop();
755         if (rn_error)
756             return tv->t_type = TOKEN_ERRNUM;/* some malformation occurred */
757         tv->t_charptr = NULL;
758         return tv->t_type = TOKEN_NUM;
759     } else if (*stdscan_bufptr == '\'' ||
760                *stdscan_bufptr == '"') {/* a char constant */
761         char quote = *stdscan_bufptr++, *r;
762         r = tv->t_charptr = stdscan_bufptr;
763         while (*stdscan_bufptr && *stdscan_bufptr != quote) stdscan_bufptr++;
764         tv->t_inttwo = stdscan_bufptr - r;      /* store full version */
765         if (!*stdscan_bufptr)
766             return tv->t_type = TOKEN_ERRNUM;       /* unmatched quotes */
767         tv->t_integer = 0;
768         r = stdscan_bufptr++;                  /* skip over final quote */
769         while (quote != *--r) {
770             tv->t_integer = (tv->t_integer<<8) + (unsigned char) *r;
771         }
772         return tv->t_type = TOKEN_NUM;
773     } else if (*stdscan_bufptr == ';') {  /* a comment has happened - stay */
774         return tv->t_type = 0;
775     } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '>') {
776         stdscan_bufptr += 2;
777         return tv->t_type = TOKEN_SHR;
778     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '<') {
779         stdscan_bufptr += 2;
780         return tv->t_type = TOKEN_SHL;
781     } else if (stdscan_bufptr[0] == '/' && stdscan_bufptr[1] == '/') {
782         stdscan_bufptr += 2;
783         return tv->t_type = TOKEN_SDIV;
784     } else if (stdscan_bufptr[0] == '%' && stdscan_bufptr[1] == '%') {
785         stdscan_bufptr += 2;
786         return tv->t_type = TOKEN_SMOD;
787     } else if (stdscan_bufptr[0] == '=' && stdscan_bufptr[1] == '=') {
788         stdscan_bufptr += 2;
789         return tv->t_type = TOKEN_EQ;
790     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '>') {
791         stdscan_bufptr += 2;
792         return tv->t_type = TOKEN_NE;
793     } else if (stdscan_bufptr[0] == '!' && stdscan_bufptr[1] == '=') {
794         stdscan_bufptr += 2;
795         return tv->t_type = TOKEN_NE;
796     } else if (stdscan_bufptr[0] == '<' && stdscan_bufptr[1] == '=') {
797         stdscan_bufptr += 2;
798         return tv->t_type = TOKEN_LE;
799     } else if (stdscan_bufptr[0] == '>' && stdscan_bufptr[1] == '=') {
800         stdscan_bufptr += 2;
801         return tv->t_type = TOKEN_GE;
802     } else if (stdscan_bufptr[0] == '&' && stdscan_bufptr[1] == '&') {
803         stdscan_bufptr += 2;
804         return tv->t_type = TOKEN_DBL_AND;
805     } else if (stdscan_bufptr[0] == '^' && stdscan_bufptr[1] == '^') {
806         stdscan_bufptr += 2;
807         return tv->t_type = TOKEN_DBL_XOR;
808     } else if (stdscan_bufptr[0] == '|' && stdscan_bufptr[1] == '|') {
809         stdscan_bufptr += 2;
810         return tv->t_type = TOKEN_DBL_OR;
811     } else                             /* just an ordinary char */
812         return tv->t_type = (unsigned char) (*stdscan_bufptr++);
813 }
814
815 /*
816  * Return TRUE if the argument is a simple scalar. (Or a far-
817  * absolute, which counts.)
818  */
819 int is_simple (expr *vect) {
820     while (vect->type && !vect->value)
821         vect++;
822     if (!vect->type)
823         return 1;
824     if (vect->type != EXPR_SIMPLE)
825         return 0;
826     do {
827         vect++;
828     } while (vect->type && !vect->value);
829     if (vect->type && vect->type < EXPR_SEGBASE+SEG_ABS) return 0;
830     return 1;
831 }
832
833 /*
834  * Return TRUE if the argument is a simple scalar, _NOT_ a far-
835  * absolute.
836  */
837 int is_really_simple (expr *vect) {
838     while (vect->type && !vect->value)
839         vect++;
840     if (!vect->type)
841         return 1;
842     if (vect->type != EXPR_SIMPLE)
843         return 0;
844     do {
845         vect++;
846     } while (vect->type && !vect->value);
847     if (vect->type) return 0;
848     return 1;
849 }
850
851 /*
852  * Return TRUE if the argument is relocatable (i.e. a simple
853  * scalar, plus at most one segment-base, plus possibly a WRT).
854  */
855 int is_reloc (expr *vect) {
856     while (vect->type && !vect->value)
857         vect++;
858     if (!vect->type)
859         return 1;
860     if (vect->type < EXPR_SIMPLE)
861         return 0;
862     if (vect->type == EXPR_SIMPLE) {
863         do {
864             vect++;
865         } while (vect->type && !vect->value);
866         if (!vect->type)
867             return 1;
868     }
869     if (vect->type != EXPR_WRT && vect->value != 0 && vect->value != 1)
870         return 0;                      /* segment base multiplier non-unity */
871     do {
872         vect++;
873     } while (vect->type && (vect->type == EXPR_WRT || !vect->value));
874     if (!vect->type)
875         return 1;
876     return 0;
877 }
878
879 /*
880  * Return TRUE if the argument contains an `unknown' part.
881  */
882 int is_unknown(expr *vect) {
883     while (vect->type && vect->type < EXPR_UNKNOWN)
884         vect++;
885     return (vect->type == EXPR_UNKNOWN);
886 }
887
888 /*
889  * Return TRUE if the argument contains nothing but an `unknown'
890  * part.
891  */
892 int is_just_unknown(expr *vect) {
893     while (vect->type && !vect->value)
894         vect++;
895     return (vect->type == EXPR_UNKNOWN);
896 }
897
898 /*
899  * Return the scalar part of a relocatable vector. (Including
900  * simple scalar vectors - those qualify as relocatable.)
901  */
902 long reloc_value (expr *vect) {
903     while (vect->type && !vect->value)
904         vect++;
905     if (!vect->type) return 0;
906     if (vect->type == EXPR_SIMPLE)
907         return vect->value;
908     else
909         return 0;
910 }
911
912 /*
913  * Return the segment number of a relocatable vector, or NO_SEG for
914  * simple scalars.
915  */
916 long reloc_seg (expr *vect) {
917     while (vect->type && (vect->type == EXPR_WRT || !vect->value))
918         vect++;
919     if (vect->type == EXPR_SIMPLE) {
920         do {
921             vect++;
922         } while (vect->type && (vect->type == EXPR_WRT || !vect->value));
923     }
924     if (!vect->type)
925         return NO_SEG;
926     else
927         return vect->type - EXPR_SEGBASE;
928 }
929
930 /*
931  * Return the WRT segment number of a relocatable vector, or NO_SEG
932  * if no WRT part is present.
933  */
934 long reloc_wrt (expr *vect) {
935     while (vect->type && vect->type < EXPR_WRT)
936         vect++;
937     if (vect->type == EXPR_WRT) {
938         return vect->value;
939     } else
940         return NO_SEG;
941 }
942
943 /*
944  * Binary search.
945  */
946 int bsi (char *string, char **array, int size) {
947     int i = -1, j = size;              /* always, i < index < j */
948     while (j-i >= 2) {
949         int k = (i+j)/2;
950         int l = strcmp(string, array[k]);
951         if (l<0)                       /* it's in the first half */
952             j = k;
953         else if (l>0)                  /* it's in the second half */
954             i = k;
955         else                           /* we've got it :) */
956             return k;
957     }
958     return -1;                         /* we haven't got it :( */
959 }