rizin/libr/asm/arch/z80/expressions.c
Jeffrey Crowell ed1aae7fd1 fix lots of spelling
fix some errors from the sed script

undo file mode crap
2014-12-07 17:00:59 +01:00

757 lines
18 KiB
C

/* Z80 assembler by shevek
Copyright (C) 2002-2009 Bas Wijnen <wijnen@debian.org>
Copyright (C) 2005 Jan Wilmans <jw@dds.nl>
This file is part of z80asm.
Z80asm is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Z80asm is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
//#include "z80asm.h"
/* reading expressions. The following operators are supported
* in order of precedence, with function name:
* expr?expr:expr do_rd_expr
* | rd_expr_or
* ^ rd_expr_xor
* & rd_expr_and
* == != rd_expr_equal
* >= <= > < rd_expr_unequal
* << >> rd_expr_shift
* + - (binary) rd_term
* * / % rd_factor
* ~ + - (unary) rd_factor
*/
static int do_rd_expr (const char **p, char delimiter, int *valid, int level,
int *check, int print_errors);
static int
rd_number (const char **p, const char **endp, int base)
{
int result = 0, i;
char *c, num[] = "0123456789abcdefghijklmnopqrstuvwxyz";
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read number of base %d"
"(string=%s).\n", stack[sp].line, addr, base, *p);
num[base] = '\0';
*p = delspc (*p);
while (**p && (c = strchr (num, tolower ((const unsigned char)**p))))
{
i = c - num;
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): Digit found:%1x.\n", stack[sp].line,
addr, i);
result = result * base + i;
(*p)++;
}
if (endp)
*endp = *p;
*p = delspc (*p);
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_number returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_otherbasenumber (const char **p, int *valid, int print_errors)
{
char c;
if (verbose >= 6)
fprintf (stderr,
"%5d (0x%04x): Starting to read basenumber (string=%s).\n",
stack[sp].line, addr, *p);
(*p)++;
if (!**p)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "unexpected end of line after `@'\n");
return 0;
}
if (**p == '0' || !isalnum ((const unsigned char)**p))
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "base must be between 1 and z\n");
return 0;
}
c = **p;
(*p)++;
if (isalpha ((const unsigned char)**p))
return rd_number (p, NULL, tolower ((unsigned char)c) - 'a' + 1);
return rd_number (p, NULL, c - '0' + 1);
}
static int
rd_character (const char **p, int *valid, int print_errors)
{
int i;
if (verbose >= 6)
fprintf (stderr,
"%5d (0x%04x): Starting to read character (string=%s).\n",
stack[sp].line, addr, *p);
i = **p;
if (!i)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "unexpected end of line in string constant\n");
return 0;
}
if (i == '\\')
{
(*p)++;
if (**p >= '0' && **p <= '7')
{
int b, num_digits;
i = 0;
if ((*p)[1] >= '0' && (*p)[1] <= '7')
{
if (**p <= '3' && (*p)[2] >= '0' && (*p)[2] <= '7')
num_digits = 3;
else
num_digits = 2;
}
else
num_digits = 1;
for (b = 0; b < num_digits; ++b)
{
int bit = (*p)[num_digits - 1 - b] - '0';
i += (1 << (b * 3)) * bit;
}
*p += num_digits;
}
else
{
switch (**p)
{
case 'n':
i = 10;
break;
case 'r':
i = 13;
break;
case 't':
i = 9;
break;
case 'a':
i = 7;
break;
case '\'':
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "empty literal character\n");
return 0;
case 0:
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "unexpected end of line after "
"backslash in string constant\n");
return 0;
default:
i = **p;
}
(*p)++;
}
}
else
(*p)++;
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_character returned %d (%c).\n",
stack[sp].line, addr, i, i);
return i;
}
static int
check_label (struct label *labels, const char **p, struct label **ret,
struct label **previous, int force_skip)
{
struct label *l;
const char *c;
unsigned s2;
*p = delspc (*p);
for (c = *p; isalnum ((const unsigned char)*c) || *c == '_' || *c == '.'; ++c)
{
}
s2 = c - *p;
for (l = labels; l; l = l->next)
{
unsigned s1, s;
int cmp;
s1 = strlen (l->name);
s = s1 < s2 ? s1 : s2;
cmp = strncmp (l->name, *p, s);
if (cmp > 0 || (cmp == 0 && s1 > s))
{
if (force_skip)
*p = c;
return 0;
}
if (cmp < 0 || s2 > s)
{
if (previous)
*previous = l;
continue;
}
*p = c;
/* if label is not valid, compute it */
if (l->ref)
{
compute_ref (l->ref, 1);
if (!l->ref->done)
{
/* label was not valid, and isn't computable. tell the
* caller that it doesn't exist, so it will try again later.
* Set ret to show actual existence. */
if (verbose >= 6)
fprintf (stderr,
"%5d (0x%04x): returning invalid label %s.\n",
stack[sp].line, addr, l->name);
*ret = l;
return 0;
}
}
*ret = l;
return 1;
}
if (force_skip)
*p = c;
return 0;
}
static int
rd_label (const char **p, int *exists, struct label **previous, int level,
int print_errors)
{
struct label *l = NULL;
int s;
if (exists)
*exists = 0;
if (previous)
*previous = NULL;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read label (string=%s).\n",
stack[sp].line, addr, *p);
for (s = level; s >= 0; --s)
{
if (check_label (stack[s].labels, p, &l,
(**p == '.' && s == sp) ? previous : NULL, 0))
break;
}
if (s < 0)
{
/* not yet found */
const char *old_p = *p;
/* label does not exist, or is invalid. This is an error if there
* is no existence check. */
if (!exists && print_errors)
printerr (1, "using undefined label %.*s\n", *p - old_p, old_p);
/* Return a value to discriminate between non-existing and invalid */
if (verbose >= 7)
fprintf (stderr, "rd_label returns invalid value\n");
return l != NULL;
}
if (exists)
*exists = 1;
if (verbose >= 7)
fprintf (stderr, "rd_label returns valid value 0x%x\n", l->value);
return l->value;
}
static int
rd_value (const char **p, int *valid, int level, int *check, int print_errors)
{
int sign = 1, not = 0, base, v;
const char *p0, *p1, *p2;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read value (string=%s).\n",
stack[sp].line, addr, *p);
*p = delspc (*p);
while (**p && strchr ("+-~", **p))
{
if (**p == '-')
sign = -sign;
else if (**p == '~')
not = ~not;
(*p)++;
*p = delspc (*p);
}
base = 10; /* Default base for suffixless numbers */
/* Check for parenthesis around full expression: not if no parenthesis */
if (**p != '(')
*check = 0;
switch (**p)
{
int exist, retval;
char quote;
int dummy_check;
case '(':
(*p)++;
dummy_check = 0;
retval = not ^ (sign * do_rd_expr (p, ')', valid, level, &dummy_check,
print_errors));
++*p;
return retval;
case '0':
if ((*p)[1] == 'x')
{
(*p) += 2;
return not ^ (sign * rd_number (p, NULL, 0x10));
}
base = 8; /* If first digit it 0, assume octal unless suffix */
/* fall through */
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
p0 = *p;
rd_number (p, &p1, 36); /* Advance to end of numeric string */
p1--; /* Last character in numeric string */
switch (*p1)
{
case 'h':
case 'H':
base = 16;
break;
case 'b':
case 'B':
base = 2;
break;
case 'o':
case 'O':
case 'q':
case 'Q':
base = 8;
break;
case 'd':
case 'D':
base = 10;
break;
default: /* No suffix */
p1++;
break;
}
v = rd_number (&p0, &p2, base);
if (p1 != p2)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "invalid character in number: \'%c\'\n", *p2);
}
return not ^ (sign * v);
case '$':
++*p;
*p = delspc (*p);
p0 = *p;
v = rd_number (&p0, &p2, 0x10);
if (p2 == *p)
{
v = baseaddr;
}
else
*p = p2;
return not ^ (sign * v);
case '%':
(*p)++;
return not ^ (sign * rd_number (p, NULL, 2));
case '\'':
case '"':
quote = **p;
++*p;
retval = not ^ (sign * rd_character (p, valid, print_errors));
if (**p != quote)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "missing closing quote (%c)\n", quote);
return 0;
}
++*p;
return retval;
case '@':
return not ^ (sign * rd_otherbasenumber (p, valid, print_errors));
case '?':
rd_label (p, &exist, NULL, level, 0);
return not ^ (sign * exist);
case '&':
{
++*p;
switch (**p)
{
case 'h':
case 'H':
base = 0x10;
break;
case 'o':
case 'O':
base = 010;
break;
case 'b':
case 'B':
base = 2;
break;
default:
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "invalid literal starting with &%c\n", **p);
return 0;
}
++*p;
return not ^ (sign * rd_number (p, NULL, base));
}
default:
{
int value;
exist = 1;
value = rd_label (p, valid ? &exist : NULL, NULL, level, print_errors);
if (!exist)
*valid = 0;
return not ^ (sign * value);
}
}
}
static int
rd_factor (const char **p, int *valid, int level, int *check, int print_errors)
{
/* read a factor of an expression */
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read factor (string=%s).\n",
stack[sp].line, addr, *p);
result = rd_value (p, valid, level, check, print_errors);
*p = delspc (*p);
while (**p == '*' || **p == '/')
{
*check = 0;
if (**p == '*')
{
(*p)++;
result *= rd_value (p, valid, level, check, print_errors);
}
else if (**p == '/')
{
(*p)++;
int value = rd_value (p, valid, level, check, print_errors);
if (value == 0){
printerr (1, "division by zero\n");
return -1;
}
result /= value;
}
*p = delspc (*p);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_factor returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_term (const char **p, int *valid, int level, int *check, int print_errors)
{
/* read a term of an expression */
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read term (string=%s).\n",
stack[sp].line, addr, *p);
result = rd_factor (p, valid, level, check, print_errors);
*p = delspc (*p);
while (**p == '+' || **p == '-')
{
*check = 0;
if (**p == '+')
{
(*p)++;
result += rd_factor (p, valid, level, check, print_errors);
}
else if (**p == '-')
{
(*p)++;
result -= rd_factor (p, valid, level, check, print_errors);
}
*p = delspc (*p);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_term returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_shift (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read shift expression "
"(string=%s).\n", stack[sp].line, addr, *p);
result = rd_term (p, valid, level, check, print_errors);
*p = delspc (*p);
while ((**p == '<' || **p == '>') && (*p)[1] == **p)
{
*check = 0;
if (**p == '<')
{
(*p) += 2;
result <<= rd_term (p, valid, level, check, print_errors);
}
else if (**p == '>')
{
(*p) += 2;
result >>= rd_term (p, valid, level, check, print_errors);
}
*p = delspc (*p);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_unequal (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read "
"unequality expression (string=%s).\n", stack[sp].line, addr,
*p);
result = rd_expr_shift (p, valid, level, check, print_errors);
*p = delspc (*p);
if (**p == '<' && (*p)[1] == '=')
{
*check = 0;
(*p) += 2;
return result <= rd_expr_unequal (p, valid, level, check, print_errors);
}
else if (**p == '>' && (*p)[1] == '=')
{
*check = 0;
(*p) += 2;
return result >= rd_expr_unequal (p, valid, level, check, print_errors);
}
if (**p == '<' && (*p)[1] != '<')
{
*check = 0;
(*p)++;
return result < rd_expr_unequal (p, valid, level, check, print_errors);
}
else if (**p == '>' && (*p)[1] != '>')
{
*check = 0;
(*p)++;
return result > rd_expr_unequal (p, valid, level, check, print_errors);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_shift returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_equal (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read equality epression "
"(string=%s).\n", stack[sp].line, addr, *p);
result = rd_expr_unequal (p, valid, level, check, print_errors);
*p = delspc (*p);
if (**p == '=')
{
*check = 0;
++*p;
if (**p == '=')
++ * p;
return result == rd_expr_equal (p, valid, level, check, print_errors);
}
else if (**p == '!' && (*p)[1] == '=')
{
*check = 0;
(*p) += 2;
return result != rd_expr_equal (p, valid, level, check, print_errors);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_equal returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_and (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read and expression "
"(string=%s).\n", stack[sp].line, addr, *p);
result = rd_expr_equal (p, valid, level, check, print_errors);
*p = delspc (*p);
if (**p == '&')
{
*check = 0;
(*p)++;
result &= rd_expr_and (p, valid, level, check, print_errors);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_expr_and returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_xor (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read xor expression "
"(string=%s).\n", stack[sp].line, addr, *p);
result = rd_expr_and (p, valid, level, check, print_errors);
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_expr_xor: rd_expr_and returned %d "
"(%04x).\n", stack[sp].line, addr, result, result);
*p = delspc (*p);
if (**p == '^')
{
*check = 0;
(*p)++;
result ^= rd_expr_xor (p, valid, level, check, print_errors);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_expr_xor returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
rd_expr_or (const char **p, int *valid, int level, int *check,
int print_errors)
{
int result;
if (verbose >= 6)
fprintf (stderr, "%5d (0x%04x): Starting to read or expression "
"(string=%s).\n", stack[sp].line, addr, *p);
result = rd_expr_xor (p, valid, level, check, print_errors);
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_expr_or: rd_expr_xor returned %d "
"(%04x).\n", stack[sp].line, addr, result, result);
*p = delspc (*p);
if (**p == '|')
{
*check = 0;
(*p)++;
result |= rd_expr_or (p, valid, level, check, print_errors);
}
if (verbose >= 7)
fprintf (stderr, "%5d (0x%04x): rd_expr_or returned %d (%04x).\n",
stack[sp].line, addr, result, result);
return result;
}
static int
do_rd_expr (const char **p, char delimiter, int *valid, int level, int *check,
int print_errors)
{
/* read an expression. delimiter can _not_ be '?' */
int result = 0;
if (verbose >= 6)
fprintf (stderr,
"%5d (0x%04x): Starting to read expression "
"(string=%s, delimiter=%c).\n", stack[sp].line, addr, *p,
delimiter ? delimiter : ' ');
*p = delspc (*p);
if (!**p || **p == delimiter)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "expression expected (not %s)\n", *p);
return 0;
}
result = rd_expr_or (p, valid, level, check, print_errors);
*p = delspc (*p);
if (**p == '?')
{
*check = 0;
(*p)++;
if (result)
{
result = do_rd_expr (p, ':', valid, level, check, print_errors);
if (**p)
(*p)++;
do_rd_expr (p, delimiter, valid, level, check, print_errors);
}
else
{
do_rd_expr (p, ':', valid, level, check, print_errors);
if (**p)
(*p)++;
result = do_rd_expr (p, delimiter, valid, level, check,
print_errors);
}
}
*p = delspc (*p);
if (**p && **p != delimiter)
{
if (valid)
*valid = 0;
else if (print_errors)
printerr (1, "junk at end of expression: %s\n", *p);
}
if (verbose >= 7)
{
fprintf (stderr, "%5d (0x%04x): rd_expr returned %d (%04x).\n",
stack[sp].line, addr, result, result);
if (valid && !*valid)
fprintf (stderr, "%5d (0x%04x): Returning invalid result.\n",
stack[sp].line, addr);
}
return result;
}
static int
rd_expr (const char **p, char delimiter, int *valid, int level,
int print_errors)
{
int check = 1;
int result;
if (valid)
*valid = 1;
result = do_rd_expr (p, delimiter, valid, level, &check, print_errors);
if (print_errors && (!valid || *valid) && check)
printerr (0, "expression fully enclosed in parenthesis\n");
return result;
}