//
-// RMAC - Reboot's Macro Assembler for the Atari Jaguar Console System
+// RMAC - Reboot's Macro Assembler for all Atari computers
// EXPR.C - Expression Analyzer
-// Copyright (C) 199x Landon Dyer, 2017 Reboot and Friends
+// Copyright (C) 199x Landon Dyer, 2011-2017 Reboot and Friends
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
// Source utilised with the kind permission of Landon Dyer
//
// N.B.: The size of tokenClass should be identical to the largest value of
// a token; we're assuming 256 but not 100% sure!
static char tokenClass[256]; // Generated table of token classes
-static VALUE evstk[EVSTACKSIZE]; // Evaluator value stack
+static uint64_t evstk[EVSTACKSIZE]; // Evaluator value stack
static WORD evattr[EVSTACKSIZE]; // Evaluator attribute stack
// Token-class initialization list
//
// Obtain a string value
//
-static VALUE str_value(char * p)
+static uint32_t str_value(char * p)
{
- VALUE v;
+ uint32_t v;
for(v=0; *p; p++)
v = (v << 8) | (*p & 0xFF);
{
case CR_ABSCOUNT:
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = (LONG)sect[ABS].sloc;
break;
case CR_TIME:
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = dos_time();
break;
case CR_DATE:
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = dos_date();
break;
case CR_MACDEF: // ^^macdef <macro-name>
p = string[*tok++];
w = (lookup(p, MACRO, 0) == NULL ? 0 : 1);
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = (TOKEN)w;
break;
case CR_DEFINED:
j = (*p == '.' ? curenv : 0);
w = ((sy = lookup(p, LABEL, j)) != NULL && (sy->sattr & w) ? 1 : 0);
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = (TOKEN)w;
break;
case CR_STREQ:
w = (WORD)(!strcmp(p, p2));
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = (TOKEN)w;
break;
}
{
case CONST:
*evalTokenBuffer++ = CONST;
- *evalTokenBuffer++ = *tok++;
+ *evalTokenBuffer++ = *tok++; // HI LONG of constant
+ *evalTokenBuffer++ = *tok++; // LO LONG of constant
break;
case SYMBOL:
p = string[*tok++];
if (sy->sattre & EQUATEDREG)
{
if ((regbank == BANK_0) && (sy->sattre & BANK_1) && !altbankok)
- warns("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
+ warn("equated symbol \'%s\' cannot be used in register bank 0", sy->sname);
if ((regbank == BANK_1) && (sy->sattre & BANK_0) && !altbankok)
- warns("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
+ warn("equated symbol \'%s\' cannot be used in register bank 1", sy->sname);
}
*evalTokenBuffer++ = SYMBOL;
break;
case STRING:
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = str_value(string[*tok++]);
break;
case '(':
return ERROR;
if (*tok++ != ')')
- return error("missing close parenthesis ')'");
+ return error("missing closing parenthesis ')'");
break;
case '[':
return ERROR;
if (*tok++ != ']')
- return error("missing close parenthesis ']'");
+ return error("missing closing bracket ']'");
break;
case '$':
*evalTokenBuffer++ = (orgactive ? orgaddr : pcloc);
// '*' takes attributes of current section, not ABS!
*evalTokenBuffer++ = cursect | DEFINED;
+ break;
+ case '{':
+ if (expr0() != OK) // Eat up first parameter (register or immediate)
+ return ERROR;
+
+ if (*tok++ != ':') // Demand a ':' there
+ return error("missing colon ':'");
+
+ if (expr0() != OK) // Eat up second parameter (register or immediate)
+ return ERROR;
+
+ if (*tok++ != '}')
+ return error("missing closing brace '}'");
+
break;
default:
return error("bad expression");
//
// Recursive-descent expression analyzer (with some simple speed hacks)
//
-int expr(TOKEN * otk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
+int expr(TOKEN * otk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
{
// Passed in values (once derefenced, that is) can all be zero. They are
// there so that the expression analyzer can fill them in as needed. The
int j;
evalTokenBuffer = otk; // Set token pointer to 'exprbuf' (direct.c)
- // Also set in various other places too (riscasm.c, e.g.)
+ // Also set in various other places too (riscasm.c,
+ // e.g.)
//printf("expr(): tokens 0-2: %i %i %i (%c %c %c); tc[2] = %i\n", tok[0], tok[1], tok[2], tok[0], tok[1], tok[2], tokenClass[tok[2]]);
// Optimize for single constant or single symbol.
// Seems that even other tokens (SUNARY type) can fuck this up too.
// if ((tok[1] == EOL)
if ((tok[1] == EOL && (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
- || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
- && (tokenClass[tok[2]] < UNARY)))
+// || (((*tok == CONST || *tok == SYMBOL) || (*tok >= KW_R0 && *tok <= KW_R31))
+// && (tokenClass[tok[2]] < UNARY)))
+ || (((tok[0] == SYMBOL) || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
+ && (tokenClass[tok[2]] < UNARY))
+ || ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
+ )
{
if (*tok >= KW_R0 && *tok <= KW_R31)
{
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
*evalTokenBuffer++ = *a_value = (*tok - KW_R0);
*a_attr = ABS | DEFINED;
else if (*tok == CONST)
{
*evalTokenBuffer++ = CONST;
- *evalTokenBuffer++ = *a_value = tok[1];
+ *evalTokenBuffer++ = tok[1];
+ *evalTokenBuffer++ = tok[2];
+ *a_value = (((uint64_t)tok[1]) << 32) | tok[2];
*a_attr = ABS | DEFINED;
if (a_esym != NULL)
*a_esym = NULL;
- tok += 2;
+ tok += 3;
//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
}
else if (*tok == '*')
{
*evalTokenBuffer++ = CONST;
+ *evalTokenBuffer++ = 0; // Set HI LONG to zero
if (orgactive)
*evalTokenBuffer++ = *a_value = orgaddr;
// means it will be fixed up later, and thus, not an error.
if ((symbol->sattre & UNDEF_EQUR) && !riscImmTokenSeen)
{
- errors("undefined register equate '%s'", symbol->sname);
+ error("undefined register equate '%s'", symbol->sname);
//if we return right away, it returns some spurious errors...
// return ERROR;
}
if (symbol->sattre & EQUATEDREG)
{
if ((regbank == BANK_0) && (symbol->sattre & BANK_1) && !altbankok)
- warns("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
+ warn("equated symbol '%s' cannot be used in register bank 0", symbol->sname);
if ((regbank == BANK_1) && (symbol->sattre & BANK_0) && !altbankok)
- warns("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
+ warn("equated symbol '%s' cannot be used in register bank 1", symbol->sname);
}
*evalTokenBuffer++ = SYMBOL;
// UNDEFINED, but it's value includes everything but the symbol value, and
// `a_esym' is set to the external symbol.
//
-int evexpr(TOKEN * tk, VALUE * a_value, WORD * a_attr, SYM ** a_esym)
+int evexpr(TOKEN * tk, uint64_t * a_value, WORD * a_attr, SYM ** a_esym)
{
- WORD * sattr;
- VALUE * sval;
WORD attr;
SYM * sy;
- SYM * esym;
- WORD sym_seg;
-
- sval = evstk; // (Empty) initial stack
- sattr = evattr;
- esym = NULL; // No external symbol involved
- sym_seg = 0;
+ uint64_t * sval = evstk; // (Empty) initial stack
+ WORD * sattr = evattr;
+ SYM * esym = NULL; // No external symbol involved
+ WORD sym_seg = 0;
while (*tk != ENDEXPR)
{
sym_seg = (WORD)(sy->sattr & TDB);
break;
case CONST:
-//printf("evexpr(): CONST = %i\n", *tk);
- *++sval = *tk++; // Push value
+ *++sval = ((uint64_t)*tk++) << 32; // Push value
+ *sval |= *tk++; // & LO LONG (will this work???--should)
+//printf("evexpr(): CONST = %lX\n", *sval);
*++sattr = ABS | DEFINED; // Push simple attribs
break;
case ACONST:
sattr--; // Pop attrib
if (sval[1] == 0)
- return error("divide by zero");
+ return error("division by zero");
//printf("--> N/N: %i / %i = ", sval[0], sval[1]);
// Compiler is picky here: Without casting these, it discards
// the sign if dividing a negative # by a positive one,
// creating a bad result. :-/
- // Probably a side effect of using VALUE intead of ints.
- *sval = (int)sval[0] / (int)sval[1];
+ // Definitely a side effect of using uint32_ts intead of ints.
+ *sval = (int32_t)sval[0] / (int32_t)sval[1];
//printf("%i\n", *sval);
break;
case '%':
// sym_seg added in 1.0.16 to solve a problem with forward symbols in
// expressions where absolute values also existed. The absolutes were
// overiding the symbol segments and not being included :(
- //*a_attr = *sattr | sym_seg; // Copy value + attrib
+ //*a_attr = *sattr | sym_seg; // Copy value + attrib
*a_attr = *sattr; // Copy value + attrib
*a_value = *sval;