/* asmif.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Befehle zur bedingten Assemblierung */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include <ctype.h>
#include "bpemu.h"
#include "chunks.h"
#include "strutil.h"
#include "errmsg.h"
#include "asmdef.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmif.h"
PIfSave FirstIfSave;
Boolean IfAsm; /* FALSE: in einer neg. IF-Sequenz-->kein Code */
static Boolean ActiveIF;
/*!------------------------------------------------------------------------
* \fn ifsave_create(tIfState if_state, Boolean case_found)
* \brief create new IF stack element
* \param if_state initial state of related construct
* \param case_found in block enabled by IF/CASE?
* \return * to new element
* ------------------------------------------------------------------------ */
static PIfSave ifsave_create(tIfState if_state, Boolean case_found)
{
PIfSave p_save;
p_save
= (PIfSave
) malloc(sizeof(TIfSave
));
if (p_save)
{
p_save->Next = NULL;
p_save->NestLevel = SaveIFs() + 1;
p_save->SaveIfAsm = IfAsm;
as_tempres_ini(&p_save->SaveExpr);
p_save->CaseFound = case_found;
p_save->State = if_state;
p_save->StartLine = CurrLine;
}
return p_save;
}
/*!------------------------------------------------------------------------
* \fn ifsave_free(PIfSave p_save)
* \brief destroy IF stack element
* \param p_save element to destroy
* ------------------------------------------------------------------------ */
static void ifsave_free(PIfSave p_save)
{
as_tempres_free(&p_save->SaveExpr);
}
static LongInt GetIfVal(const tStrComp *pCond)
{
Boolean IfOK;
tSymbolFlags Flags;
LongInt Tmp;
Tmp = EvalStrIntExpressionWithFlags(pCond, Int32, &IfOK, &Flags);
if (mFirstPassUnknown(Flags) || !IfOK)
{
Tmp = 1;
if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
}
return Tmp;
}
static void AddBoolFlag(Boolean Flag)
{
strmaxcpy(ListLine, Flag ? "=>TRUE" : "=>FALSE", STRINGSIZE);
}
static void PushIF(LongInt IfExpr)
{
PIfSave NewSave = ifsave_create(IfState_IFIF, IfExpr != 0);
NewSave->Next = FirstIfSave;
FirstIfSave = NewSave;
IfAsm = IfAsm && NewSave->CaseFound;
}
static void CodeIF(void)
{
LongInt IfExpr;
ActiveIF = IfAsm;
if (!IfAsm)
IfExpr = 1;
else if (!ChkArgCnt(1, 1))
IfExpr = 1;
else
IfExpr = GetIfVal(&ArgStr[1]);
if (IfAsm)
AddBoolFlag(IfExpr != 0);
PushIF(IfExpr);
}
static void CodeIFDEF(Word Negate)
{
LongInt IfExpr;
Boolean Defined;
ActiveIF = IfAsm;
if (!IfAsm) IfExpr = 1;
else if (!ChkArgCnt(1, 1))
IfExpr = 1;
else
{
Defined = IsSymbolDefined(&ArgStr[1]);
if (IfAsm)
strmaxcpy(ListLine, (Defined) ? "=>DEFINED" : "=>UNDEFINED", STRINGSIZE);
if (!Negate)
IfExpr = (Defined) ? 1 : 0;
else
IfExpr = (Defined) ? 0 : 1;
}
PushIF(IfExpr);
}
static void CodeIFUSED(Word Negate)
{
LongInt IfExpr;
Boolean Used;
ActiveIF = IfAsm;
if (!IfAsm)
IfExpr = 1;
else if (!ChkArgCnt(1, 1))
IfExpr = 1;
else
{
Used = IsSymbolUsed(&ArgStr[1]);
if (IfAsm)
strmaxcpy(ListLine, (Used) ? "=>USED" : "=>UNUSED", STRINGSIZE);
if (!Negate)
IfExpr = (Used) ? 1 : 0;
else
IfExpr = (Used) ? 0 : 1;
}
PushIF(IfExpr);
}
void CodeIFEXIST(Word Negate)
{
LongInt IfExpr;
Boolean Found;
String NPath;
ActiveIF = IfAsm;
if (!IfAsm)
IfExpr = 1;
else if (!ChkArgCnt(1, 1))
IfExpr = 1;
else
{
String FileName, Dummy;
strmaxcpy(FileName, (ArgStr[1].str.p_str[0] == '"') ? ArgStr[1].str.p_str + 1 : ArgStr[1].str.p_str, STRINGSIZE);
if (FileName
[strlen(FileName
) - 1] == '"')
FileName
[strlen(FileName
) - 1] = '\0';
AddSuffix(FileName, IncSuffix);
strmaxcpy(NPath, IncludeList, STRINGSIZE);
strmaxprep(NPath, SDIRSEP, STRINGSIZE);
strmaxprep(NPath, ".", STRINGSIZE);
Found = !FSearch(Dummy, sizeof(Dummy), FileName, CurrFileName, NPath);
if (IfAsm)
strmaxcpy(ListLine, Found ? "=>FOUND" : "=>NOT FOUND", STRINGSIZE);
IfExpr = Negate ? !Found : Found;
}
PushIF(IfExpr);
}
static void CodeIFB(Word Negate)
{
Boolean Blank = True;
LongInt IfExpr;
int z;
ActiveIF = IfAsm;
if (!IfAsm)
IfExpr = 1;
else
{
for (z = 1; z <= ArgCnt; z++)
if (strlen(ArgStr
[z
++].
str.
p_str) > 0)
Blank = False;
if (IfAsm)
strmaxcpy(ListLine, (Blank) ? "=>BLANK" : "=>NOT BLANK", STRINGSIZE);
IfExpr = Negate ? !Blank : Blank;
}
PushIF(IfExpr);
}
static void CodeELSEIF(void)
{
LongInt IfExpr;
if (!FirstIfSave || (FirstIfSave->State != IfState_IFIF)) WrError(ErrNum_MissingIf);
else if (ArgCnt == 0)
{
if (FirstIfSave->SaveIfAsm)
AddBoolFlag(IfAsm = (!FirstIfSave->CaseFound));
FirstIfSave->State = IfState_IFELSE;
}
else if (ArgCnt == 1)
{
if (!FirstIfSave->SaveIfAsm)
IfExpr = 1;
else if (FirstIfSave->CaseFound)
IfExpr = 0;
else
IfExpr = GetIfVal(&ArgStr[1]);
IfAsm = ((FirstIfSave->SaveIfAsm) && (IfExpr != 0) && (!FirstIfSave->CaseFound));
if (FirstIfSave->SaveIfAsm)
AddBoolFlag(IfExpr != 0);
if (IfExpr != 0)
FirstIfSave->CaseFound = True;
}
else
(void)ChkArgCnt(0, 1);
ActiveIF = (!FirstIfSave) || (FirstIfSave->SaveIfAsm);
}
static void CodeENDIF(void)
{
if (!ChkArgCnt(0, 0));
else if (!FirstIfSave || ((FirstIfSave->State != IfState_IFIF) && (FirstIfSave->State != IfState_IFELSE))) WrError(ErrNum_MissingIf);
else
{
PIfSave NewSave;
IfAsm = FirstIfSave->SaveIfAsm;
NewSave = FirstIfSave;
FirstIfSave = NewSave->Next;
as_snprintf(ListLine, STRINGSIZE, "[%u]", (unsigned)NewSave->StartLine);
ifsave_free(NewSave);
}
ActiveIF = IfAsm;
}
static void EvalIfExpression(const tStrComp *pCond, TempResult *erg)
{
EvalStrExpression(pCond, erg);
if ((erg->Typ == TempNone) || mFirstPassUnknown(erg->Flags))
{
as_tempres_set_int(erg, 1);
if (mFirstPassUnknown(erg->Flags))
WrError(ErrNum_FirstPassCalc);
}
}
static void CodeSWITCH(void)
{
PIfSave NewSave = ifsave_create(IfState_CASESWITCH, False);
ActiveIF = IfAsm;
if (ArgCnt != 1)
{
as_tempres_set_int(&NewSave->SaveExpr, 1);
if (IfAsm)
(void)ChkArgCnt(1, 1);
}
else
{
EvalIfExpression(&ArgStr[1], &NewSave->SaveExpr);
SetListLineVal(&NewSave->SaveExpr);
}
NewSave->Next = FirstIfSave;
FirstIfSave = NewSave;
}
static void CodeCASE(void)
{
Boolean eq;
int z;
if (!FirstIfSave) WrError(ErrNum_MissingIf);
else if (ChkArgCnt(1, ArgCntMax))
{
if ((FirstIfSave->State != IfState_CASESWITCH) && (FirstIfSave->State != IfState_CASECASE)) WrError(ErrNum_InvIfConst);
else
{
if (!FirstIfSave->SaveIfAsm)
eq = True;
else if (FirstIfSave->CaseFound)
eq = False;
else
{
TempResult t;
as_tempres_ini(&t);
eq = False;
z = 1;
do
{
EvalIfExpression(&ArgStr[z], &t);
eq = (FirstIfSave->SaveExpr.Typ == t.Typ);
if (eq)
switch (t.Typ)
{
case TempInt:
eq = (t.Contents.Int == FirstIfSave->SaveExpr.Contents.Int);
break;
case TempFloat:
eq = (t.Contents.Float == FirstIfSave->SaveExpr.Contents.Float);
break;
case TempString:
eq = (as_nonz_dynstr_cmp(&t.Contents.str, &FirstIfSave->SaveExpr.Contents.str) == 0);
break;
default:
eq = False;
break;
}
z++;
}
while (!eq && (z <= ArgCnt));
as_tempres_free(&t);
}
IfAsm = (FirstIfSave->SaveIfAsm && eq & !FirstIfSave->CaseFound);
if (FirstIfSave->SaveIfAsm)
AddBoolFlag(eq && !FirstIfSave->CaseFound);
if (eq)
FirstIfSave->CaseFound = True;
FirstIfSave->State = IfState_CASECASE;
}
}
ActiveIF = !FirstIfSave || FirstIfSave->SaveIfAsm;
}
static void CodeELSECASE(void)
{
if (ChkArgCnt(0, 0))
{
if ((FirstIfSave->State != IfState_CASESWITCH) && (FirstIfSave->State != IfState_CASECASE)) WrError(ErrNum_InvIfConst);
else
IfAsm = (FirstIfSave->SaveIfAsm && (!FirstIfSave->CaseFound));
if (FirstIfSave->SaveIfAsm)
AddBoolFlag(!FirstIfSave->CaseFound);
FirstIfSave->CaseFound = True;
FirstIfSave->State = IfState_CASEELSE;
}
ActiveIF = (!FirstIfSave) || (FirstIfSave->SaveIfAsm);
}
static void CodeENDCASE(void)
{
if (!ChkArgCnt(0, 0));
else if (!FirstIfSave) WrError(ErrNum_MissingIf);
else
{
if ((FirstIfSave->State != IfState_CASESWITCH)
&& (FirstIfSave->State != IfState_CASECASE)
&& (FirstIfSave->State != IfState_CASEELSE)) WrError(ErrNum_InvIfConst);
else
{
PIfSave NewSave;
IfAsm = FirstIfSave->SaveIfAsm;
if (!FirstIfSave->CaseFound) WrError(ErrNum_NoCaseHit);
NewSave = FirstIfSave;
FirstIfSave = NewSave->Next;
as_snprintf(ListLine, STRINGSIZE, "[%u]", (unsigned)NewSave->StartLine);
ifsave_free(NewSave);
}
}
ActiveIF = IfAsm;
}
Boolean CodeIFs(void)
{
Boolean Result = True;
ActiveIF = False;
switch (as_toupper(*OpPart.str.p_str))
{
case 'I':
if (Memo("IF")) CodeIF();
else if (Memo("IFDEF")) CodeIFDEF(False);
else if (Memo("IFNDEF")) CodeIFDEF(True);
else if (Memo("IFUSED")) CodeIFUSED(False);
else if (Memo("IFNUSED")) CodeIFUSED(True);
else if (Memo("IFEXIST")) CodeIFEXIST(False);
else if (Memo("IFNEXIST")) CodeIFEXIST(True);
else if (Memo("IFB")) CodeIFB(False);
else if (Memo("IFNB")) CodeIFB(True);
else Result = False;
break;
case 'E':
if ((Memo("ELSE")) || (Memo("ELSEIF"))) CodeELSEIF();
else if (Memo("ENDIF")) CodeENDIF();
else if (Memo("ELSECASE")) CodeELSECASE();
else if (Memo("ENDCASE")) CodeENDCASE();
else Result = False;
break;
case 'S':
if (memo_switch_pseudo()) CodeSWITCH();
else if (Memo("SELECT") && SwitchIsOccupied) CodeSWITCH();
else Result = False;
break;
case 'C':
if (Memo("CASE")) CodeCASE();
else Result = False;
break;
case '.':
if (Memo(".SWITCH")) CodeSWITCH();
else Result = False;
break;
default:
Result = False;
}
return Result;
}
Integer SaveIFs(void)
{
return (!FirstIfSave) ? 0 : FirstIfSave->NestLevel;
}
void RestoreIFs(Integer Level)
{
PIfSave OldSave;
while (FirstIfSave && (FirstIfSave->NestLevel != Level))
{
OldSave = FirstIfSave;
FirstIfSave = OldSave->Next;
IfAsm = OldSave->SaveIfAsm;
ifsave_free(OldSave);
}
}
Boolean IFListMask(void)
{
switch (ListOn)
{
case 0:
return True;
case 1:
return False;
case 2:
return ((!ActiveIF) && (!IfAsm));
case 3:
return (ActiveIF || (!IfAsm));
}
return True;
}
void AsmIFInit(void)
{
IfAsm = True;
}
void asmif_init(void)
{
}