/* operator.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* defintion of operators */
/* */
/*****************************************************************************/
#include <stdio.h>
#include <math.h>
#include "stdinc.h"
#include "errmsg.h"
#include "asmdef.h"
#include "asmerr.h"
#include "asmpars.h"
#include "asmrelocs.h"
#include "operator.h"
#define PromoteLValFlags() \
do \
{ \
if (pErg->Typ != TempNone) \
{ \
pErg->Flags |= (pLVal->Flags & eSymbolFlags_Promotable); \
pErg->AddrSpaceMask |= pLVal->AddrSpaceMask; \
if (pErg->DataSize == eSymbolSizeUnknown) pErg->DataSize = pLVal->DataSize; \
} \
} \
while (0)
#define PromoteLRValFlags() \
do \
{ \
if (pErg->Typ != TempNone) \
{ \
pErg->Flags |= ((pLVal->Flags | pRVal->Flags) & eSymbolFlags_Promotable); \
pErg->AddrSpaceMask |= pLVal->AddrSpaceMask | pRVal->AddrSpaceMask; \
if (pErg->DataSize == eSymbolSizeUnknown) pErg->DataSize = pLVal->DataSize; \
if (pErg->DataSize == eSymbolSizeUnknown) pErg->DataSize = pRVal->DataSize; \
} \
} \
while (0)
/*!------------------------------------------------------------------------
* \fn reg_cmp(const tRegDescr *p_reg1, tSymbolSize data_size1,
const tRegDescr *p_reg2, tSymbolSize data_size2)
* \brief compare two register symbols
* \param p_reg1, p_reg2 registers to compare
* \return -1 : reg1 < reg2
* 0 : reg1 = reg2
* +1 : reg1 > reg2
* -2 : unequal, but no smaller/greater relation can be given
* ------------------------------------------------------------------------ */
static int reg_cmp(const TempResult *p_val1, const TempResult *p_val2)
{
tRegInt num1, num2;
/* If the two symbols are for different target architectures,
they are for sure unequal, but no ordering critera can be given: */
if ((p_val1->Contents.RegDescr.Dissect != p_val2->Contents.RegDescr.Dissect)
|| (p_val1->Contents.RegDescr.compare != p_val2->Contents.RegDescr.compare))
return -2;
/* architecture-specific comparison function? */
if (p_val1->Contents.RegDescr.compare)
return p_val1->Contents.RegDescr.compare(p_val1->Contents.RegDescr.Reg, p_val1->DataSize,
p_val2->Contents.RegDescr.Reg, p_val2->DataSize);
/* The generic comparison: If operand sizes differ, they are 'just unequal',
otherwise compare register numbers: */
if (p_val1->DataSize != p_val2->DataSize)
return -2;
num1 = p_val1->Contents.RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
num2 = p_val2->Contents.RegDescr.Reg & ~REGSYM_FLAG_ALIAS;
if (num1 < num2)
return -1;
else if (num1 > num2)
return 1;
else
return 0;
}
static void DummyOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
UNUSED(pLVal);
UNUSED(pRVal);
UNUSED(pErg);
}
static void OneComplOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
UNUSED(pLVal);
as_tempres_set_int(pErg, ~(pRVal->Contents.Int));
PromoteLValFlags();
}
static void ShLeftOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, pLVal->Contents.Int << pRVal->Contents.Int);
PromoteLRValFlags();
}
static void ShRightOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, pLVal->Contents.Int >> pRVal->Contents.Int);
PromoteLRValFlags();
}
static void BitMirrorOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
int z;
if ((pRVal->Contents.Int < 1) || (pRVal->Contents.Int > 32)) WrError(ErrNum_OverRange);
else
{
LargeInt Result = (pLVal->Contents.Int >> pRVal->Contents.Int) << pRVal->Contents.Int;
for (z = 0; z < pRVal->Contents.Int; z++)
{
if ((pLVal->Contents.Int & (1 << (pRVal->Contents.Int - 1 - z))) != 0)
Result |= (1 << z);
}
as_tempres_set_int(pErg, Result);
}
PromoteLRValFlags();
}
static void BinAndOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, pLVal->Contents.Int & pRVal->Contents.Int);
PromoteLRValFlags();
}
static void BinOrOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, pLVal->Contents.Int | pRVal->Contents.Int);
PromoteLRValFlags();
}
static void BinXorOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, pLVal->Contents.Int ^ pRVal->Contents.Int);
PromoteLRValFlags();
}
static void PotOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
LargeInt HVal;
switch (pLVal->Typ)
{
case TempInt:
if (pRVal->Contents.Int < 0) as_tempres_set_int(pErg, 0);
else
{
LargeInt l = pLVal->Contents.Int, r = pRVal->Contents.Int;
HVal = 1;
while (r > 0)
{
if (r & 1)
HVal *= l;
r >>= 1;
if (r)
l *= l;
}
as_tempres_set_int(pErg, HVal);
}
break;
case TempFloat:
if (pRVal->Contents.Float == 0.0)
as_tempres_set_float(pErg, 1.0);
else if (pLVal->Contents.Float == 0.0)
as_tempres_set_float(pErg, 0.0);
else if (pLVal->Contents.Float > 0)
as_tempres_set_float
(pErg
, pow(pLVal
->Contents.
Float, pRVal
->Contents.
Float));
else if ((fabs(pRVal
->Contents.
Float) <= ((double)MaxLongInt
)) && (floor(pRVal
->Contents.
Float) == pRVal
->Contents.
Float))
{
Double Base = pLVal->Contents.Float, Result;
HVal
= (LongInt
) floor(pRVal
->Contents.
Float + 0.5);
if (HVal < 0)
{
Base = 1 / Base;
HVal = -HVal;
}
Result = 1.0;
while (HVal > 0)
{
if (HVal & 1)
Result *= Base;
Base *= Base;
HVal >>= 1;
}
as_tempres_set_float(pErg, Result);
}
else
{
WrError(ErrNum_InvArgPair);
pErg->Typ = TempNone;
}
break;
default:
break;
}
PromoteLRValFlags();
}
static void MultOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, pLVal->Contents.Int * pRVal->Contents.Int);
break;
case TempFloat:
as_tempres_set_float(pErg, pLVal->Contents.Float * pRVal->Contents.Float);
break;
default:
break;
}
PromoteLRValFlags();
}
static void DivOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
if (pRVal->Contents.Int == 0) WrError(ErrNum_DivByZero);
else
as_tempres_set_int(pErg, pLVal->Contents.Int / pRVal->Contents.Int);
break;
case TempFloat:
if (pRVal->Contents.Float == 0.0) WrError(ErrNum_DivByZero);
else
as_tempres_set_float(pErg, pLVal->Contents.Float / pRVal->Contents.Float);
default:
break;
}
PromoteLRValFlags();
}
static void ModOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
if (pRVal->Contents.Int == 0) WrError(ErrNum_DivByZero);
else
as_tempres_set_int(pErg, pLVal->Contents.Int % pRVal->Contents.Int);
PromoteLRValFlags();
}
/* TODO: handle return code of NonZString2Int() better */
static void AddOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_none(pErg);
switch (pLVal->Typ)
{
case TempInt:
switch (pRVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, pLVal->Contents.Int + pRVal->Contents.Int);
pErg->Relocs = MergeRelocs(&(pLVal->Relocs), &(pRVal->Relocs), TRUE);
break;
case TempString:
{
LargeInt RIntVal;
tErrorNum error_num = NonZString2Int(&pRVal->Contents.str, &RIntVal);
if (ErrNum_None == error_num)
{
as_tempres_set_c_str(pErg, "");
Int2NonZString(&pErg->Contents.str, RIntVal + pLVal->Contents.Int);
}
else
WrError(error_num);
break;
}
default:
break;
}
break;
case TempFloat:
if (TempFloat == pRVal->Typ)
as_tempres_set_float(pErg, pLVal->Contents.Float + pRVal->Contents.Float);
break;
case TempString:
{
switch (pRVal->Typ)
{
case TempString:
as_tempres_set_str(pErg, &pLVal->Contents.str);
as_nonz_dynstr_append(&pErg->Contents.str, &pRVal->Contents.str);
break;
case TempInt:
{
LargeInt LIntVal;
tErrorNum error_num = NonZString2Int(&pLVal->Contents.str, &LIntVal);
if (ErrNum_None == error_num)
{
as_tempres_set_c_str(pErg, "");
Int2NonZString(&pErg->Contents.str, LIntVal + pRVal->Contents.Int);
}
else
WrError(error_num);
break;
}
default:
break;
}
break;
}
default:
break;
}
PromoteLRValFlags();
}
static void SubOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, pLVal->Contents.Int - pRVal->Contents.Int);
break;
case TempFloat:
as_tempres_set_float(pErg, pLVal->Contents.Float - pRVal->Contents.Float);
break;
default:
break;
}
PromoteLRValFlags();
}
static void LogNotOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
UNUSED(pLVal);
as_tempres_set_int(pErg, pRVal->Contents.Int ? 0 : 1);
PromoteLValFlags();
}
static void LogAndOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, (pLVal->Contents.Int && pRVal->Contents.Int) ? 1 : 0);
PromoteLRValFlags();
}
static void LogOrOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, (pLVal->Contents.Int || pRVal->Contents.Int) ? 1 : 0);
PromoteLRValFlags();
}
static void LogXorOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
as_tempres_set_int(pErg, ((pLVal->Contents.Int != 0) != (pRVal->Contents.Int != 0)) ? 1 : 0);
PromoteLRValFlags();
}
static void EqOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int == pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float == pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) == 0) ? 1 : 0);
break;
case TempReg:
as_tempres_set_int(pErg, 0 == reg_cmp(pLVal, pRVal));
break;
default:
break;
}
PromoteLRValFlags();
}
static void GtOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int > pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float > pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) > 0) ? 1 : 0);
break;
case TempReg:
as_tempres_set_int(pErg, reg_cmp(pLVal, pRVal) == 1);
break;
default:
break;
}
PromoteLRValFlags();
}
static void LtOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int < pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float < pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) < 0) ? 1 : 0);
break;
case TempReg:
as_tempres_set_int(pErg, reg_cmp(pLVal, pRVal) == -1);
break;
default:
break;
}
PromoteLRValFlags();
}
static void LeOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int <= pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float <= pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) <= 0) ? 1 : 0);
break;
case TempReg:
{
int cmp_res = reg_cmp(pLVal, pRVal);
as_tempres_set_int(pErg, (cmp_res == -1) || (cmp_res == 0));
break;
}
default:
break;
}
PromoteLRValFlags();
}
static void GeOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int >= pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float >= pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) >= 0) ? 1 : 0);
break;
case TempReg:
{
int cmp_res = reg_cmp(pLVal, pRVal);
as_tempres_set_int(pErg, (cmp_res == 1) || (cmp_res == 0));
break;
}
default:
break;
}
PromoteLRValFlags();
}
static void UneqOp(TempResult *pErg, TempResult *pLVal, TempResult *pRVal)
{
switch (pLVal->Typ)
{
case TempInt:
as_tempres_set_int(pErg, (pLVal->Contents.Int != pRVal->Contents.Int) ? 1 : 0);
break;
case TempFloat:
as_tempres_set_int(pErg, (pLVal->Contents.Float != pRVal->Contents.Float) ? 1 : 0);
break;
case TempString:
as_tempres_set_int(pErg, (as_nonz_dynstr_cmp(&pLVal->Contents.str, &pRVal->Contents.str) != 0) ? 1 : 0);
break;
case TempReg:
as_tempres_set_int(pErg, reg_cmp(pLVal, pRVal) != 0);
break;
default:
break;
}
PromoteLRValFlags();
}
#define Int2Int (TempInt | (TempInt << 4) )
#define Float2Float (TempFloat | (TempFloat << 4) )
#define String2String (TempString | (TempString << 4))
#define Reg2Reg (TempReg | (TempReg << 4) )
#define Int2String (TempInt | (TempString << 4))
#define String2Int (TempString | (TempInt << 4) )
const Operator Operators[] =
{
{" " , 1 , False, 0, { 0, 0, 0, 0, 0 }, DummyOp},
{"~" , 1 , False, 1, { TempInt << 4, 0, 0, 0, 0 }, OneComplOp},
{"<<", 2 , True , 3, { Int2Int, 0, 0, 0, 0 }, ShLeftOp},
{">>", 2 , True , 3, { Int2Int, 0, 0, 0, 0 }, ShRightOp},
{"><", 2 , True , 4, { Int2Int, 0, 0, 0, 0 }, BitMirrorOp},
{"&" , 1 , True , 5, { Int2Int, 0, 0, 0, 0 }, BinAndOp},
{"|" , 1 , True , 6, { Int2Int, 0, 0, 0, 0 }, BinOrOp},
{"!" , 1 , True , 7, { Int2Int, 0, 0, 0, 0 }, BinXorOp},
{"^" , 1 , True , 8, { Int2Int, Float2Float, 0, 0, 0 }, PotOp},
{"*" , 1 , True , 11, { Int2Int, Float2Float, 0, 0, 0 }, MultOp},
{"/" , 1 , True , 11, { Int2Int, Float2Float, 0, 0, 0 }, DivOp},
{"#" , 1 , True , 11, { Int2Int, 0, 0, 0, 0 }, ModOp},
{"+" , 1 , True , 13, { Int2Int, Float2Float, String2String, Int2String, String2Int }, AddOp},
{"-" , 1 , True , 13, { Int2Int, Float2Float, 0, 0, 0 }, SubOp},
{"~~", 2 , False, 2, { TempInt << 4, 0, 0, 0, 0 }, LogNotOp},
{"&&", 2 , True , 15, { Int2Int, 0, 0, 0, 0 }, LogAndOp},
{"||", 2 , True , 16, { Int2Int, 0, 0, 0, 0 }, LogOrOp},
{"!!", 2 , True , 17, { Int2Int, 0, 0, 0, 0 }, LogXorOp},
{"=" , 1 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, EqOp},
{"==", 2 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, EqOp},
{">" , 1 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, GtOp},
{"<" , 1 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, LtOp},
{"<=", 2 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, LeOp},
{">=", 2 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, GeOp},
{"<>", 2 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, UneqOp},
{"!=", 2 , True , 23, { Int2Int, Float2Float, String2String, Reg2Reg, 0 }, UneqOp},
/* termination marker */
{NULL, 0 , False, 0, { 0, 0, 0, 0, 0 }, NULL}
},
/* minus may have one or two operands */
MinusMonadicOperator =
{
"-" ,1 , False, 13, { TempInt << 4, TempFloat << 4, 0, 0, 0 }, SubOp
};
const Operator *pPotMonadicOperator = NULL;