ref: 52d62c6b215478566c20afd8f8e7e9cc049ac92c
parent: b4a73f33ce62de139d2c4490a9cc3877c6832cb2
author: ISSOtm <[email protected]>
date: Mon Jan 20 18:07:31 EST 2020
Handle subtractions between labels
--- a/src/asm/rpn.c
+++ b/src/asm/rpn.c
@@ -274,6 +274,28 @@
}
}
+static struct sSymbol const *symbolOf(struct Expression const *expr)
+{
+ /* If an expression starts with a symbol ref... */
+ if (!expr->tRPN || expr->tRPN[0] != RPN_SYM || expr->nRPNPatchSize != 5)
+ return NULL;
+ return sym_FindSymbol((char *)expr->tRPN + 1);
+}
+
+static bool isDiffConstant(struct Expression const *src1,
+ struct Expression const *src2)
+{
+ /* Check if both expressions only refer to a single symbol */
+ struct sSymbol const *symbol1 = symbolOf(src1);
+ struct sSymbol const *symbol2 = symbolOf(src2);
+
+ if (!symbol1 || !symbol2
+ || symbol1->type != SYM_LABEL || symbol2->type != SYM_LABEL)
+ return false;
+
+ return symbol1->pSection == symbol2->pSection;
+}
+
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
const struct Expression *src1, const struct Expression *src2)
{
@@ -383,8 +405,12 @@
fatalerror("%d is no binary operator", op);
}
- /* TODO: under some conditions, the expression will still be known */
+ } else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
+ struct sSymbol const *symbol1 = symbolOf(src1);
+ struct sSymbol const *symbol2 = symbolOf(src2);
+ expr->nVal = symbol1->nValue - symbol2->nValue;
+ expr->isKnown = true;
} else {
/* If it's not known, start computing the RPN expression */