blob: 19bfebac8007a22a66e6cd4e89f10ab39d9006e8 [file] [log] [blame]
/* nasmlib.c library routines for the Netwide Assembler
*
* The Netwide Assembler is copyright (C) 1996 Simon Tatham and
* Julian Hall. All rights reserved. The software is
* redistributable under the licence given in the file "Licence"
* distributed in the NASM archive.
*/
#include <util.h>
#include <libyasm/coretype.h>
#include <ctype.h>
#include "nasm.h"
#include "nasmlib.h"
/*#include "insns.h"*/ /* For MAX_KEYWORD */
#define lib_isnumchar(c) ( isalnum(c) || (c) == '$')
#define numvalue(c) ((c)>='a' ? (c)-'a'+10 : (c)>='A' ? (c)-'A'+10 : (c)-'0')
long nasm_readnum (char *str, int *error)
{
char *r = str, *q;
long radix;
unsigned long result, checklimit;
int digit, last;
int warn = FALSE;
int sign = 1;
*error = FALSE;
while (isspace(*r)) r++; /* find start of number */
/*
* If the number came from make_tok_num (as a result of an %assign), it
* might have a '-' built into it (rather than in a preceeding token).
*/
if (*r == '-')
{
r++;
sign = -1;
}
q = r;
while (lib_isnumchar(*q)) q++; /* find end of number */
/*
* If it begins 0x, 0X or $, or ends in H, it's in hex. if it
* ends in Q, it's octal. if it ends in B, it's binary.
* Otherwise, it's ordinary decimal.
*/
if (*r=='0' && (r[1]=='x' || r[1]=='X'))
radix = 16, r += 2;
else if (*r=='$')
radix = 16, r++;
else if (q[-1]=='H' || q[-1]=='h')
radix = 16 , q--;
else if (q[-1]=='Q' || q[-1]=='q' || q[-1]=='O' || q[-1]=='o')
radix = 8 , q--;
else if (q[-1]=='B' || q[-1]=='b')
radix = 2 , q--;
else
radix = 10;
/*
* If this number has been found for us by something other than
* the ordinary scanners, then it might be malformed by having
* nothing between the prefix and the suffix. Check this case
* now.
*/
if (r >= q) {
*error = TRUE;
return 0;
}
/*
* `checklimit' must be 2**32 / radix. We can't do that in
* 32-bit arithmetic, which we're (probably) using, so we
* cheat: since we know that all radices we use are even, we
* can divide 2**31 by radix/2 instead.
*/
checklimit = 0x80000000UL / (radix>>1);
/*
* Calculate the highest allowable value for the last digit
* of a 32 bit constant... in radix 10, it is 6, otherwise it is 0
*/
last = (radix == 10 ? 6 : 0);
result = 0;
while (*r && r < q) {
if (*r<'0' || (*r>'9' && *r<'A') || (digit = numvalue(*r)) >= radix)
{
*error = TRUE;
return 0;
}
if (result > checklimit ||
(result == checklimit && digit >= last))
{
warn = TRUE;
}
result = radix * result + digit;
r++;
}
#if 0
if (warn)
nasm_malloc_error (ERR_WARNING | ERR_PASS1 | ERR_WARN_NOV,
"numeric constant %s does not fit in 32 bits",
str);
#endif
return result*sign;
}
long nasm_readstrnum (char *str, int length, int *warn)
{
long charconst = 0;
int i;
*warn = FALSE;
str += length;
for (i=0; i<length; i++) {
if (charconst & 0xff000000UL) {
*warn = TRUE;
}
charconst = (charconst<<8) + (unsigned char) *--str;
}
return charconst;
}
static long next_seg;
void nasm_seg_init(void)
{
next_seg = 0;
}
long nasm_seg_alloc(void)
{
return (next_seg += 2) - 2;
}
/*
* Return TRUE if the argument is a simple scalar. (Or a far-
* absolute, which counts.)
*/
int nasm_is_simple (nasm_expr *vect)
{
while (vect->type && !vect->value)
vect++;
if (!vect->type)
return 1;
if (vect->type != EXPR_SIMPLE)
return 0;
do {
vect++;
} while (vect->type && !vect->value);
if (vect->type && vect->type < EXPR_SEGBASE+SEG_ABS) return 0;
return 1;
}
/*
* Return TRUE if the argument is a simple scalar, _NOT_ a far-
* absolute.
*/
int nasm_is_really_simple (nasm_expr *vect)
{
while (vect->type && !vect->value)
vect++;
if (!vect->type)
return 1;
if (vect->type != EXPR_SIMPLE)
return 0;
do {
vect++;
} while (vect->type && !vect->value);
if (vect->type) return 0;
return 1;
}
/*
* Return TRUE if the argument is relocatable (i.e. a simple
* scalar, plus at most one segment-base, plus possibly a WRT).
*/
int nasm_is_reloc (nasm_expr *vect)
{
while (vect->type && !vect->value) /* skip initial value-0 terms */
vect++;
if (!vect->type) /* trivially return TRUE if nothing */
return 1; /* is present apart from value-0s */
if (vect->type < EXPR_SIMPLE) /* FALSE if a register is present */
return 0;
if (vect->type == EXPR_SIMPLE) { /* skip over a pure number term... */
do {
vect++;
} while (vect->type && !vect->value);
if (!vect->type) /* ...returning TRUE if that's all */
return 1;
}
if (vect->type == EXPR_WRT) { /* skip over a WRT term... */
do {
vect++;
} while (vect->type && !vect->value);
if (!vect->type) /* ...returning TRUE if that's all */
return 1;
}
if (vect->value != 0 && vect->value != 1)
return 0; /* segment base multiplier non-unity */
do { /* skip over _one_ seg-base term... */
vect++;
} while (vect->type && !vect->value);
if (!vect->type) /* ...returning TRUE if that's all */
return 1;
return 0; /* And return FALSE if there's more */
}
/*
* Return TRUE if the argument contains an `unknown' part.
*/
int nasm_is_unknown(nasm_expr *vect)
{
while (vect->type && vect->type < EXPR_UNKNOWN)
vect++;
return (vect->type == EXPR_UNKNOWN);
}
/*
* Return TRUE if the argument contains nothing but an `unknown'
* part.
*/
int nasm_is_just_unknown(nasm_expr *vect)
{
while (vect->type && !vect->value)
vect++;
return (vect->type == EXPR_UNKNOWN);
}
/*
* Return the scalar part of a relocatable vector. (Including
* simple scalar vectors - those qualify as relocatable.)
*/
long nasm_reloc_value (nasm_expr *vect)
{
while (vect->type && !vect->value)
vect++;
if (!vect->type) return 0;
if (vect->type == EXPR_SIMPLE)
return vect->value;
else
return 0;
}
/*
* Return the segment number of a relocatable vector, or NO_SEG for
* simple scalars.
*/
long nasm_reloc_seg (nasm_expr *vect)
{
while (vect->type && (vect->type == EXPR_WRT || !vect->value))
vect++;
if (vect->type == EXPR_SIMPLE) {
do {
vect++;
} while (vect->type && (vect->type == EXPR_WRT || !vect->value));
}
if (!vect->type)
return NO_SEG;
else
return vect->type - EXPR_SEGBASE;
}
/*
* Return the WRT segment number of a relocatable vector, or NO_SEG
* if no WRT part is present.
*/
long nasm_reloc_wrt (nasm_expr *vect)
{
while (vect->type && vect->type < EXPR_WRT)
vect++;
if (vect->type == EXPR_WRT) {
return vect->value;
} else
return NO_SEG;
}
/*
* Binary search.
*/
int nasm_bsi (char *string, const char **array, int size)
{
int i = -1, j = size; /* always, i < index < j */
while (j-i >= 2) {
int k = (i+j)/2;
int l = strcmp(string, array[k]);
if (l<0) /* it's in the first half */
j = k;
else if (l>0) /* it's in the second half */
i = k;
else /* we've got it :) */
return k;
}
return -1; /* we haven't got it :( */
}
static char *file_name = NULL;
static long line_number = 0;
char *nasm_src_set_fname(char *newname)
{
char *oldname = file_name;
file_name = newname;
return oldname;
}
char *nasm_src_get_fname(void)
{
return file_name;
}
long nasm_src_set_linnum(long newline)
{
long oldline = line_number;
line_number = newline;
return oldline;
}
long nasm_src_get_linnum(void)
{
return line_number;
}
int nasm_src_get(long *xline, char **xname)
{
if (!file_name || !*xname || strcmp(*xname, file_name))
{
nasm_free(*xname);
*xname = file_name ? nasm_strdup(file_name) : NULL;
*xline = line_number;
return -2;
}
if (*xline != line_number)
{
long tmp = line_number - *xline;
*xline = line_number;
return tmp;
}
return 0;
}
void nasm_quote(char **str)
{
size_t ln=strlen(*str);
char q=(*str)[0];
char *p;
if (ln>1 && (*str)[ln-1]==q && (q=='"' || q=='\''))
return;
q = '"';
if (strchr(*str,q))
q = '\'';
p = nasm_malloc(ln+3);
strcpy(p+1, *str);
nasm_free(*str);
p[ln+1] = p[0] = q;
p[ln+2] = 0;
*str = p;
}
char *nasm_strcat(char *one, char *two)
{
char *rslt;
int l1=strlen(one);
rslt = nasm_malloc(l1+strlen(two)+1);
strcpy(rslt, one);
strcpy(rslt+l1, two);
return rslt;
}