/* intformat.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS */
/* */
/* enums regarding integer constant notations */
/* */
/*****************************************************************************/
#include "strutil.h"
#include "datatypes.h"
#include "stdinc.h"
#include <stdlib.h>
#include <string.h>
#include "intformat.h"
static const Word BaseVals[4] =
{
2, 8, 16, 256
};
LongWord NativeIntConstModeMask, OtherIntConstModeMask;
tIntFormatList *IntFormatList = NULL;
tIntConstMode IntConstMode;
Boolean IntConstModeIBMNoTerm, RelaxedMode;
int RadixBase;
static Boolean ChkIntFormatCHex(tIntCheckCtx *pCtx, char Ch)
{
if ((pCtx->ExprLen > 2)
&& (*pCtx->pExpr == '0')
&& (RadixBase <= Ch - 'A' + 10)
&& (as_toupper(pCtx->pExpr[1]) == Ch))
{
pCtx->pExpr += 2;
pCtx->ExprLen -= 2;
return True;
}
return False;
}
static Boolean ChkIntFormatCBin(tIntCheckCtx *pCtx, char Ch)
{
if ((pCtx->ExprLen > 2)
&& (*pCtx->pExpr == '0')
&& (RadixBase <= Ch - 'A' + 10)
&& (as_toupper(pCtx->pExpr[1]) == Ch))
{
const char *pRun;
for (pRun = pCtx->pExpr + 2; pRun < pCtx->pExpr + pCtx->ExprLen; pRun++)
if (DigitVal(*pRun, 2) < 0)
return False;
pCtx->pExpr += 2;
pCtx->ExprLen -= 2;
return True;
}
return False;
}
static Boolean ChkIntFormatMot(tIntCheckCtx *pCtx, char Ch)
{
if ((pCtx->ExprLen > 1)
&& (*pCtx->pExpr == Ch))
{
pCtx->pExpr++;
pCtx->ExprLen--;
return True;
}
return False;
}
static Boolean ChkIntFormatInt(tIntCheckCtx *pCtx, char Ch)
{
if ((pCtx->ExprLen < 2) || !as_isdigit(*pCtx->pExpr))
return False;
if ((RadixBase <= Ch - 'A' + 10)
&& (as_toupper(pCtx->pExpr[pCtx->ExprLen - 1]) == Ch))
{
pCtx->ExprLen--;
return True;
}
return False;
}
static Boolean ChkIntFormatIBM(tIntCheckCtx *pCtx, char Ch)
{
if ((pCtx->ExprLen < 3)
|| (as_toupper(*pCtx->pExpr) != Ch)
|| (pCtx->pExpr[1] != '\''))
return False;
if ((pCtx->ExprLen > 3) && (pCtx->pExpr[pCtx->ExprLen - 1] == '\''))
{
pCtx->pExpr += 2;
pCtx->ExprLen -= 3;
return True;
}
else if (IntConstModeIBMNoTerm)
{
pCtx->pExpr += 2;
pCtx->ExprLen -= 2;
return True;
}
return False;
}
static Boolean ChkIntFormatCOct(tIntCheckCtx *pCtx, char Ch)
{
const char *pRun;
UNUSED(Ch);
if ((pCtx->ExprLen < 2)
|| (*pCtx->pExpr != '0'))
return False;
for (pRun = pCtx->pExpr + 1; pRun < pCtx->pExpr + pCtx->ExprLen; pRun++)
if (DigitVal(*pRun, 8) < 0)
return False;
return True;
}
static Boolean ChkIntFormatNatHex(tIntCheckCtx *pCtx, char Ch)
{
const char *pRun;
UNUSED(Ch);
if ((pCtx->ExprLen < 2)
|| (*pCtx->pExpr != '0'))
return False;
for (pRun = pCtx->pExpr + 1; pRun < pCtx->pExpr + pCtx->ExprLen; pRun++)
if (!as_isxdigit(*pRun))
return False;
return True;
}
static Boolean ChkIntFormatDef(tIntCheckCtx *pCtx, char Ch)
{
UNUSED(pCtx);
UNUSED(Ch);
return True;
}
static const tIntFormatList IntFormatList_All[] =
{
{ ChkIntFormatCHex , eIntFormatCHex, 16, 'X', "0xhex" },
{ ChkIntFormatCBin , eIntFormatCBin, 2, 'B', "0bbin" },
{ ChkIntFormatMot , eIntFormatMotHex, 16, '$', "$hex" },
{ ChkIntFormatMot , eIntFormatMotBin, 2, '%', "%bin" },
{ ChkIntFormatMot , eIntFormatMotOct, 8, '@', "@oct" },
{ ChkIntFormatInt , eIntFormatIntHex, 16, 'H', "hexh" },
{ ChkIntFormatInt , eIntFormatIntBin, 2, 'B', "binb" },
{ ChkIntFormatInt , eIntFormatIntOOct, 8, 'O', "octo" },
{ ChkIntFormatInt , eIntFormatIntQOct, 8, 'Q', "octq" },
{ ChkIntFormatIBM , eIntFormatIBMHHex, 16, 'H', "h'hex'" },
{ ChkIntFormatIBM , eIntFormatIBMXHex, 16, 'X', "x'hex'" },
{ ChkIntFormatIBM , eIntFormatIBMBin, 2, 'B', "b'bin'" },
{ ChkIntFormatIBM , eIntFormatIBMOct, 8, 'O', "o'oct'" },
{ ChkIntFormatIBM , eIntFormatIBMAsc, 256, 'A', "a'asc'" },
{ ChkIntFormatCOct , eIntFormatCOct, 8, '0', "0oct" },
{ ChkIntFormatNatHex, eIntFormatNatHex, 16, '0', "0hex" },
{ ChkIntFormatDef , eIntFormatDefRadix,-1, '\0', "dec" }, /* -1 -> RadixBase */
{ NULL , (tIntFormatId)0, 0, '\0', "" }
};
/*!------------------------------------------------------------------------
* \fn GetIntConstIntelSuffix(unsigned Radix)
* \brief return Intel-style suffix letter fitting to number system
* \param Radix req'd number system
* \return * to suffix string (may be empty)
* ------------------------------------------------------------------------ */
const char *GetIntConstIntelSuffix(unsigned Radix)
{
static const char BaseLetters[3] =
{
'B', 'O', 'H'
};
unsigned BaseIdx;
for (BaseIdx = 0; BaseIdx < as_array_size(BaseLetters); BaseIdx++)
if (Radix == BaseVals[BaseIdx])
{
static char Result[2] = { '\0', '\0' };
Result[0] = BaseLetters[BaseIdx] + (HexStartCharacter - 'A');
return Result;
}
return "";
}
/*!------------------------------------------------------------------------
* \fn GetIntConstMotoPrefix(unsigned Radix)
* \brief return Motorola-style prefix letter fitting to number system
* \param Radix req'd number system
* \return * to prefix string (may be empty)
* ------------------------------------------------------------------------ */
const char *GetIntConstMotoPrefix(unsigned Radix)
{
static const char BaseIds[3] =
{
'%', '@', '$'
};
unsigned BaseIdx;
for (BaseIdx = 0; BaseIdx < as_array_size(BaseIds); BaseIdx++)
if (Radix == BaseVals[BaseIdx])
{
static char Result[2] = { '\0', '\0' };
Result[0] = BaseIds[BaseIdx];
return Result;
}
return "";
}
/*!------------------------------------------------------------------------
* \fn GetIntConstCPrefix(unsigned Radix)
* \brief return C-style prefix letter fitting to number system
* \param Radix req'd number system
* \return * to prefix string (may be empty)
* ------------------------------------------------------------------------ */
const char *GetIntConstCPrefix(unsigned Radix)
{
static const char BaseIds[3][3] =
{
"0b", "0", "0x"
};
unsigned BaseIdx;
for (BaseIdx = 0; BaseIdx < as_array_size(BaseIds); BaseIdx++)
if (Radix == BaseVals[BaseIdx])
return BaseIds[BaseIdx];;
return "";
}
/*!------------------------------------------------------------------------
* \fn GetIntConstIBMPrefix(unsigned Radix)
* \brief return IBM-style prefix letter fitting to number system
* \param Radix req'd number system
* \return * to prefix string (may be empty)
* ------------------------------------------------------------------------ */
const char *GetIntConstIBMPrefix(unsigned Radix)
{
static const char BaseIds[4] =
{
'B', 'O', 'X', 'A'
};
unsigned BaseIdx;
for (BaseIdx = 0; BaseIdx < as_array_size(BaseIds); BaseIdx++)
if (Radix == BaseVals[BaseIdx])
{
static char Result[3] = { '\0', '\'', '\0' };
Result[0] = BaseIds[BaseIdx] + (HexStartCharacter - 'A');
return Result;
}
return "";
}
/*!------------------------------------------------------------------------
* \fn GetIntConstIBMSuffix(unsigned Radix)
* \brief return IBM-style suffix fitting to number system
* \param Radix req'd number system
* \return * to prefix string (may be empty)
* ------------------------------------------------------------------------ */
const char *GetIntConstIBMSuffix(unsigned Radix)
{
unsigned BaseIdx;
for (BaseIdx = 0; BaseIdx < as_array_size(BaseVals); BaseIdx++)
if (Radix == BaseVals[BaseIdx])
return "\'";
return "";
}
/*!------------------------------------------------------------------------
* \fn SetIntConstModeByMask(LongWord Mask)
* \brief set new (non-relaxed) integer constant mode by bit mask
* \param Mask modes to set
* ------------------------------------------------------------------------ */
void SetIntConstModeByMask(LongWord Mask)
{
const tIntFormatList *pSrc;
tIntFormatList *pDest;
if (!IntFormatList)
IntFormatList
= (tIntFormatList
*)malloc(sizeof(IntFormatList_All
));
for (pDest = IntFormatList, pSrc = IntFormatList_All; pSrc->Check; pSrc++)
{
if (!((Mask >> pSrc->Id) & 1))
continue;
*pDest++ = *pSrc;
}
memset(pDest
, 0, sizeof(*pDest
));
}
/*!------------------------------------------------------------------------
* \fn ModifyIntConstModeByMask(LongWord ANDMask, LongWord ORMask)
* \brief add or remove integer notations to/from native list
* \param ANDMask notations to remove
* \param ORMask notations to add
* \return True if mask was set up successfully
* ------------------------------------------------------------------------ */
#define BadMask ((1ul << eIntFormatCOct) | (1ul << eIntFormatNatHex))
Boolean ModifyIntConstModeByMask(LongWord ANDMask, LongWord ORMask)
{
LongWord NewMask = (NativeIntConstModeMask & ~ANDMask) | ORMask;
if ((NewMask & BadMask) == BadMask)
return False;
else
{
NativeIntConstModeMask = NewMask;
SetIntConstModeByMask(NativeIntConstModeMask | (RelaxedMode ? OtherIntConstModeMask : 0));
return True;
}
}
/*!------------------------------------------------------------------------
* \fn SetIntConstMode(tIntConstMode Mode)
* \brief set new (non-relaxed) integer constant mode
* \param Mode mode to set
* ------------------------------------------------------------------------ */
void SetIntConstMode(tIntConstMode Mode)
{
IntConstMode = Mode;
switch (Mode)
{
case eIntConstModeC:
NativeIntConstModeMask = eIntFormatMaskC;
OtherIntConstModeMask = eIntFormatMaskIntel | eIntFormatMaskMoto | eIntFormatMaskIBM;
break;
case eIntConstModeIntel:
NativeIntConstModeMask = eIntFormatMaskIntel;
OtherIntConstModeMask = eIntFormatMaskC | eIntFormatMaskMoto | eIntFormatMaskIBM;
break;
case eIntConstModeMoto:
NativeIntConstModeMask = eIntFormatMaskMoto;
OtherIntConstModeMask = eIntFormatMaskC | eIntFormatMaskIntel | eIntFormatMaskIBM;
break;
case eIntConstModeIBM:
NativeIntConstModeMask = eIntFormatMaskIBM;
OtherIntConstModeMask = eIntFormatMaskC | eIntFormatMaskIntel | eIntFormatMaskMoto;
break;
default:
NativeIntConstModeMask = 0;
}
NativeIntConstModeMask |= (1ul << eIntFormatDefRadix);
SetIntConstModeByMask(NativeIntConstModeMask | (RelaxedMode ? OtherIntConstModeMask : 0));
}
/*!------------------------------------------------------------------------
* \fn SetIntConstRelaxedMode(Boolean NewRelaxedMode)
* \brief update relaxed mode - parser list
* \param NewRelaxedMode mode to set
* ------------------------------------------------------------------------ */
void SetIntConstRelaxedMode(Boolean NewRelaxedMode)
{
SetIntConstModeByMask(NativeIntConstModeMask | (NewRelaxedMode ? OtherIntConstModeMask : 0));
}
/*!------------------------------------------------------------------------
* \fn GetIntFormatId(const char *pIdent)
* \brief transform identifier to id
* \param pIdent textual identifier
* \return resulting Id or None if not found
* ------------------------------------------------------------------------ */
tIntFormatId GetIntFormatId(const char *pIdent)
{
const tIntFormatList *pList;
for (pList = IntFormatList_All; pList->Check; pList++)
if (!as_strcasecmp(pIdent, pList->Ident))
return (tIntFormatId)pList->Id;
return eIntFormatNone;
}
/*!------------------------------------------------------------------------
* \fn intformat_init(void)
* \brief module initialization
* ------------------------------------------------------------------------ */
void intformat_init(void)
{
/* Allow all int const modes for handling possible -D options: */
RelaxedMode = True;
SetIntConstMode(eIntConstModeC);
}