--- hatari/src/debug/evaluate.c 2019/04/09 08:48:37 1.1.1.1 +++ hatari/src/debug/evaluate.c 2019/04/09 08:56:48 1.1.1.6 @@ -1,13 +1,15 @@ /* - Hatari - calculate.c + Hatari - evaluate.c - Copyright (C) 1994, 2009 by Eero Tamminen + Copyright (C) 1994, 2009-2014 by Eero Tamminen - This file is distributed under the GNU Public License, version 2 or at - your option any later version. Read the file gpl.txt for details. + This file is distributed under the GNU General Public License, version 2 + or at your option any later version. Read the file gpl.txt for details. calculate.c - parse numbers, number ranges and expressions. Supports - most unary and binary operations, parenthesis and order of precedence. + most unary and binary operations. Parenthesis are used for indirect + ST RAM value addressing. + Originally based on code from my Clac calculator MiNT filter version. */ const char Eval_fileid[] = "Hatari calculate.c : " __DATE__ " " __TIME__; @@ -19,18 +21,22 @@ const char Eval_fileid[] = "Hatari calcu #include #include #include +#include #include "configuration.h" #include "dsp.h" #include "debugcpu.h" #include "evaluate.h" #include "main.h" #include "m68000.h" +#include "stMemory.h" #include "symbols.h" +#include "vars.h" + /* define which character indicates which type of number on expression */ -#define PREFIX_BIN '%' /* binary decimal */ -#define PREFIX_DEC '#' /* normal decimal */ -#define PREFIX_HEX '$' /* hexadecimal */ +#define PREFIX_BIN '%' /* binary decimal */ +#define PREFIX_DEC '#' /* normal decimal */ +#define PREFIX_HEX '$' /* hexadecimal */ /* define error codes */ #define CLAC_EXP_ERR "No expression given" @@ -43,9 +49,9 @@ const char Eval_fileid[] = "Hatari calcu #define CLAC_PRG_ERR "Internal program error" /* define internal allocation sizes (should be enough ;-) */ -#define PARDEPTH_MAX 64 /* max. parenth. nesting depth */ -#define OSTACK_MAX 128 /* size of the operator stack */ -#define VSTACK_MAX 128 /* size of the value stack */ +#define PARDEPTH_MAX 16 /* max. parenth. nesting depth */ +#define OSTACK_MAX 64 /* size of the operator stack */ +#define VSTACK_MAX 64 /* size of the value stack */ /* operation with lowest precedence, used to finish calculations */ #define LOWEST_PREDECENCE '|' @@ -54,7 +60,7 @@ const char Eval_fileid[] = "Hatari calcu static struct { const char *error; /* global error code */ bool valid; /* value validation */ -} id = {0, 0}; +} id = { NULL, 0 }; /* parenthesis and function stacks */ static struct { @@ -122,7 +128,7 @@ static long long close_bracket(long long static int getNumber(const char *str, Uint32 *number, int *nbase) { char *end; - const char const *start = str; + const char *start = str; int base = ConfigureParams.Debugger.nNumberBase; unsigned long int value; @@ -154,7 +160,7 @@ static int getNumber(const char *str, Ui } str += 2; } - else if (!isxdigit(str[0])) { + else if (!isxdigit((unsigned char)str[0])) { /* doesn't start with (hex) number -> is it prefix? */ switch (*str++) { @@ -191,18 +197,19 @@ static int getNumber(const char *str, Ui /** - * Parse unsigned register/symbol/number value and set it to "number". + * Parse unsigned register/symbol/number value and set it to "number" + * and the number base used for parsing to "base". * Return how many characters were parsed or zero for error. */ -static int getValue(const char *str, Uint32 *number, bool bForDsp) +static int getValue(const char *str, Uint32 *number, int *base, bool bForDsp) { char name[64]; const char *end; Uint32 mask, *addr; - int len, dummy; + int len; + + for (end = str; *end == '_' || isalnum((unsigned char)*end); end++); - for (end = str; *end == '_' || isalnum(*end); end++); - len = end-str; if (len >= (int)sizeof(name)) { fprintf(stderr, "ERROR: symbol name at '%s' too long (%d chars)\n", str, len); @@ -211,14 +218,27 @@ static int getValue(const char *str, Uin memcpy(name, str, len); name[len] = '\0'; + *base = 0; /* no base (e.g. variable) */ + + /* internal Hatari variable? */ + if (Vars_GetVariableValue(name, number)) { + return len; + } + if (bForDsp) { + int regsize = DSP_GetRegisterAddress(name, &addr, &mask); /* DSP register or symbol? */ - if (DSP_GetRegisterAddress(name, &addr, &mask)) { - *number = (*addr & mask); + switch (regsize) { + case 16: + *number = (*((Uint16*)addr) & mask); return len; - } - if (Symbols_GetDspAddress(SYMTYPE_ALL, name, number)) { + case 32: + *number = (*addr & mask); return len; + default: + if (Symbols_GetDspAddress(SYMTYPE_ALL, name, number)) { + return len; + } } } else { /* a special case CPU register? */ @@ -241,63 +261,82 @@ static int getValue(const char *str, Uin } /* none of above, assume it's a number */ - return getNumber(str, number, &dummy); + return getNumber(str, number, base); } -/** - * Parse & set an (unsigned) number, assume it's in the configured - * default number base unless it has a suitable prefix. +/* Check that number string is OK and isn't followed by unrecognized + * character (last char char is zero). If not, complain about it. * Return true for success and false for failure. */ -bool Eval_Number(const char *str, Uint32 *number) +static bool isNumberOK(const char *str, int offset, int base) { - int offset, base = 0; - - offset = getNumber(str, number, &base); + const char *basestr; + if (!offset) { return false; } - if (str[offset]) { - const char *basestr; - - switch (base) { - case 2: - basestr = "binary"; - break; - case 8: - basestr = "octal"; - break; - case 10: - basestr = "decimal"; - break; - case 16: - basestr = "hexadecimal"; - break; - default: - basestr = "unknown"; + if (!str[offset]) { + /* no extra chars after the parsed part */ + return true; } - fprintf(stderr, "Extra characters in %s based number '%s'!\n", - basestr, str); + switch (base) { + case 0: + fprintf(stderr, "Name '%s' contains non-alphanumeric characters!\n", str); return false; + case 2: + basestr = "binary"; + break; + case 8: + basestr = "octal"; + break; + case 10: + basestr = "decimal"; + break; + case 16: + basestr = "hexadecimal"; + break; + default: + basestr = "unknown"; } - return true; + fprintf(stderr, "Extra characters in %s based number '%s'!\n", basestr, str); + return false; +} + +/** + * Parse & set an (unsigned) number, assume it's in the configured + * default number base unless it has a suitable prefix. + * Return true for success and false for failure. + */ +bool Eval_Number(const char *str, Uint32 *number) +{ + int offset, base; + /* TODO: add CPU/DSP flag and use getValue() instead of getNumber() + * like getRange() does, so that user can use variable names in + * addition to numbers. + */ + offset = getNumber(str, number, &base); + if (!offset) + return false; + else + return isNumberOK(str, offset, base); } /** - * Get a an adress range, eg. "$fa0000-$fa0100" + * Parse an address range, eg. "$fa0000[-$fa0100]" or "pc[-a0]" and + * output appropriate warnings if range or values are invalid. + * Address can also be a register/variable/symbol name. * returns: - * 0 if OK, - * -1 if not syntaxically a range, - * -2 if values are invalid, - * -3 if syntaxically range, but not value-wise. + * -1 if invalid address or range, + * 0 if single address, + * +1 if a range. */ -static int getRange(char *str1, Uint32 *lower, Uint32 *upper) +int Eval_Range(char *str1, Uint32 *lower, Uint32 *upper, bool fordsp) { + int offset, base, ret; bool fDash = false; char *str2 = str1; - int ret = 0; while (*str2) { if (*str2 == '-') { @@ -307,46 +346,35 @@ static int getRange(char *str1, Uint32 * } str2++; } - if (!fDash) - return -1; - if (!Eval_Number(str1, lower)) - ret = -2; - else if (!Eval_Number(str2, upper)) - ret = -2; - else if (*lower > *upper) - ret = -3; - *--str2 = '-'; - return ret; -} - - -/** - * Parse an adress range, eg. "$fa0000[-$fa0100]" + show appropriate warnings - * returns: - * -1 if invalid address or range, - * 0 if single address, - * +1 if a range. - */ -int Eval_Range(char *str, Uint32 *lower, Uint32 *upper) -{ - switch (getRange(str, lower, upper)) { - case 0: - return 1; - case -1: - /* single address, not a range */ - if (!Eval_Number(str, lower)) - return -1; - return 0; - case -2: - fprintf(stderr,"Invalid address values in '%s'!\n", str); - return -1; - case -3: - fprintf(stderr,"Invalid range ($%x > $%x)!\n", *lower, *upper); - return -1; + offset = getValue(str1, lower, &base, fordsp); + if (offset == 0 || !isNumberOK(str1, offset, base)) { + /* first number not OK */ + fprintf(stderr,"Invalid address value '%s'!\n", str1); + ret = -1; + } else { + /* first number OK */ + ret = 0; + } + if (fDash) { + offset = getValue(str2, upper, &base, fordsp); + if (offset == 0 || !isNumberOK(str2, offset, base)) { + /* second number not OK */ + fprintf(stderr, "Invalid address value '%s'!\n", str2); + ret = -1; + } else { + if (*lower > *upper) { + fprintf(stderr,"Invalid range ($%x > $%x)!\n", *lower, *upper); + /* not a range */ + ret = -1; + } else { + /* second number & range OK */ + ret = 1; + } + } + *--str2 = '-'; } - fprintf(stderr, "INTERNAL ERROR: Unknown getRange() return value.\n"); - return -1; + return ret; } @@ -366,7 +394,7 @@ const char* Eval_Expression(const char * /* offset: character offset in expression */ long long value; - int offset = 0; + int dummy, offset = 0; char mark; /* Uses global variables: */ @@ -428,7 +456,7 @@ const char* Eval_Expression(const char * if (id.valid == false) { Uint32 tmp; int consumed; - consumed = getValue(&(in[offset]), &tmp, bForDsp); + consumed = getValue(&(in[offset]), &tmp, &dummy, bForDsp); /* number parsed? */ if (consumed) { offset += consumed; @@ -666,7 +694,7 @@ static long long apply_op (char opcode, /* ==================================================================== */ /** - * open prenthesis, push values & operators to stack + * open parenthesis, push values & operators to stack */ static void open_bracket (void) { @@ -683,7 +711,7 @@ static void open_bracket (void) /* -------------------------------------------------------------------- */ /** - * close prenthesis, and evaluate / pop stacks + * close parenthesis, and evaluate / pop stacks */ /* last parsed value, last param. flag, trigonometric mode */ static long long close_bracket (long long value) @@ -691,11 +719,18 @@ static long long close_bracket (long lon /* returns the value of the parenthesised expression */ if (id.valid) { /* preceded by an operator */ - if (par.idx > 0) { /* prenthesis has a pair */ + if (par.idx > 0) { /* parenthesis has a pair */ + Uint32 addr; + /* calculate the value of parenthesised exp. */ operation (value, LOWEST_PREDECENCE); - value = val.buf[val.idx]; - op.idx = par.opx[par.idx] - 1; /* restore prev */ + /* fetch the indirect ST RAM value */ + addr = val.buf[val.idx]; + value = STMemory_ReadLong(addr); + fprintf(stderr, " value in RAM at ($%x).l = $%"PRIx64"\n", + addr, (uint64_t)value); + /* restore state before parenthesis */ + op.idx = par.opx[par.idx] - 1; val.idx = par.vax[par.idx] - 1; par.idx --;