PTR ptk;
evalTokenBuffer.u32 = 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.
- // Shamus: Subtle bug here. EOL token is 101; if you have a constant token
- // followed by the value 101, it will trigger a bad evaluation here.
- // This is probably a really bad assumption to be making here...!
- // (assuming tok[1] == EOL is a single token that is)
- // Seems that even other tokens (SUNARY type) can fuck this up too.
-#if 0
-// if ((tok[1] == EOL)
- if ((tok[1] == EOL && ((tok[0] != CONST || tok[0] != FCONST) && tokenClass[tok[0]] != SUNARY))
-// || (((*tok == CONST || *tok == FCONST || *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 || tok[0] == FCONST) && (tokenClass[tok[3]] < UNARY))
- )
-#else
// Shamus: Seems to me that this could be greatly simplified by 1st checking if the first token is a multibyte token, *then* checking if there's an EOL after it depending on the actual length of the token (multiple vs. single). Otherwise, we have the horror show that is the following:
if ((tok[1] == EOL
&& (tok[0] != CONST && tokenClass[tok[0]] != SUNARY))
- || (((tok[0] == SYMBOL)
- || (tok[0] >= KW_R0 && tok[0] <= KW_R31))
+ || ((tok[0] == SYMBOL)
&& (tokenClass[tok[2]] < UNARY))
|| ((tok[0] == CONST) && (tokenClass[tok[3]] < UNARY))
)
-// Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis niavely checking tok[1] for an EOL. O_o
-#endif
+// Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis naively checking tok[1] for an EOL. O_o
{
- if (*tok >= KW_R0 && *tok <= KW_R31)
- {
- *evalTokenBuffer.u32++ = CONST;
- *evalTokenBuffer.u64++ = *a_value = (*tok - KW_R0);
- *a_attr = ABS | DEFINED | RISCREG;
-
- if (a_esym != NULL)
- *a_esym = NULL;
-
- tok++;
- }
- else if (*tok == CONST)
+ if (*tok == CONST)
{
ptk.u32 = tok;
*evalTokenBuffer.u32++ = *ptk.u32++;
#define MAXINTERNCC 26 // Maximum internal condition codes
+// Useful macros
+#define EVAL_REG_RETURN_IF_ERROR(x, y) \
+x = EvaluateRegisterFromTokenStream(y); \
+\
+if (x == ERROR) \
+ return ERROR;
+
+#define EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(x, y) \
+x = EvaluateRegisterFromTokenStream(y); \
+\
+if ((x == ERROR) || (ErrorIfNotAtEOL() == ERROR)) \
+ return ERROR;
+
+#define CHECK_EOL \
+if (ErrorIfNotAtEOL() == ERROR) \
+ return ERROR;
unsigned altbankok = 0; // Ok to use alternate register bank
unsigned orgactive = 0; // RISC/6502 org directive active
malform1, malform2, malform3, malform4
};
-
//
// Function to return "malformed expression" error
// This is done mainly to remove a bunch of GOTO statements in the parser
return error("Malformed opcode, %s", malformErr[signal]);
}
-
//
// Function to return "Illegal Indexed Register" error
// Anyone trying to index something other than R14 or R15
return error("Attempted index reference with non-indexable register (r%d)", reg - KW_R0);
}
-
//
// Function to return "Illegal Indexed Register" error for EQUR scenarios
// Trying to use register value within EQUR that isn't 14 or 15
return error("Attempted index reference with non-indexable register within EQUR (%s = r%d)", sy->sname, sy->svalue);
}
-
//
// Build up & deposit RISC instruction word
//
D_word(value);
}
-
//
// Evaluate the RISC register from the token stream. Passed in value is the
// FIXUP attribute to use if the expression comes back as undefined.
//
-static int EvaluateRegisterFromTokenStream(uint32_t attr)
+static int EvaluateRegisterFromTokenStream(uint32_t fixup)
{
+ // Firstly, check to see if it's a register token and return that. No
+ // need to invoke expr() for easy cases like this.
+ if (*tok >= KW_R0 && *tok <= KW_R31)
+ {
+ int reg = *tok - KW_R0;
+ tok++;
+ return reg;
+ }
+
+ if (*tok != SYMBOL)
+ {
+ // If at this point we don't have a symbol then it's garbage. Punt.
+ return error("Expected register number or EQUREG");
+ }
+
uint64_t eval; // Expression value
WORD eattr; // Expression attributes
SYM * esym; // External symbol involved in expr.
TOKEN r_expr[EXPRSIZE]; // Expression token list
// Evaluate what's in the global "tok" buffer
+ // N.B.: We should either get a fixup or a register name from EQUR
if (expr(r_expr, &eval, &eattr, &esym) != OK)
return ERROR;
if (!(eattr & DEFINED))
{
- AddFixup(FU_WORD | attr, sloc, r_expr);
+ AddFixup(FU_WORD | fixup, sloc, r_expr);
return 0;
}
return error(reg_err);
}
-
//
// Do RISC code generation
//
// ABS, MIRROR, NEG, NOT, PACK, RESMAC, SAT8, SAT16, SAT16S, SAT24, SAT32S,
// UNPACK
case RI_ONE:
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, parm >> 6, reg2);
break;
if (parm == 37)
altbankok = 1; // MOVEFA
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (parm == 36)
altbankok = 1; // MOVETA
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, 0, reg2);
val = WORDSWAP32(eval);
else
{
parm = 34;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
if (!indexed)
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
else
{
if (indexed)
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
else
{
}
else
{
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
}
}
tok++;
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
// Rn,(Rn) = 47 / Rn,(R14/R15+n) = 49/50 / Rn,(R14/R15+Rn) = 60/61
case RI_STORE:
parm = 47;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (*tok != '(')
if (!indexed)
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
else
{
if (indexed)
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
else
{
}
else
{
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
}
}
return MalformedOpcode(MALF_RPAREN);
tok++;
- ErrorIfNotAtEOL();
+ CHECK_EOL;
DepositRISCInstructionWord(parm, reg2, reg1);
break;
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
CHECK_COMMA;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
- ErrorIfNotAtEOL();
+ EVAL_REG_RETURN_IF_ERROR_OR_NO_EOL(reg2, FU_REGTWO);
DepositRISCInstructionWord(parm, reg1, reg2);
break;
// STOREB/STOREP/STOREW Rn,(Rn)
case RI_STOREN:
- reg1 = EvaluateRegisterFromTokenStream(FU_REGONE);
+ EVAL_REG_RETURN_IF_ERROR(reg1, FU_REGONE);
CHECK_COMMA;
if (*tok != '(')
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
- ErrorIfNotAtEOL();
+ CHECK_EOL;
DepositRISCInstructionWord(parm, reg2, reg1);
break;
return MalformedOpcode(MALF_LPAREN);
tok++;
- reg2 = EvaluateRegisterFromTokenStream(FU_REGTWO);
+ EVAL_REG_RETURN_IF_ERROR(reg2, FU_REGTWO);
if (*tok != ')')
return MalformedOpcode(MALF_RPAREN);
tok++;
- ErrorIfNotAtEOL();
+ CHECK_EOL;
}
DepositRISCInstructionWord(parm, reg2, reg1);
lastOpcode = type;
return 0;
}
-