/* asmallg.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* von allen Codegeneratoren benutzte Pseudobefehle                          */
/*                                                                           */
/*****************************************************************************/

#include "stdinc.h"
#include <string.h>
#include <ctype.h>

#include "nls.h"
#include "strutil.h"
#include "stringlists.h"
#include "bpemu.h"
#include "console.h"
#include "chunks.h"
#include "asmdef.h"
#include "asmsub.h"
#include "errmsg.h"
#include "as.h"
#include "as.rsc"
#include "function.h"
#include "asmpars.h"
#include "asmmac.h"
#include "asmlist.h"
#include "asmstructs.h"
#include "asmcode.h"
#include "asmrelocs.h"
#include "cpu2phys.h"
#include "asmitree.h"
#include "assume.h"
#include "operator.h"
#include "codepseudo.h"
#include "nlmessages.h"
#include "literals.h"
#include "msg_level.h"
#include "dyn_array.h"
#include "fwd_sym.h"
#include "codenone.h"
#include "cmdarg.h"
#include "headids.h"

#include "asmallg.h"

#define LEAVE goto func_exit

/*--------------------------------------------------------------------------*/


static PInstTable PseudoTable = NULL,
                  ONOFFTable  = NULL;
static inst_fnc_table_t *pseudo_inst_fnc_table = NULL;

/*--------------------------------------------------------------------------*/

static Boolean DefChkPC(LargeWord Addr)
{
  if (!((1 << ActPC) & ValidSegs))
    return False;
  else
    return (Addr <= SegLimits[ActPC]);
}

/*!------------------------------------------------------------------------
 * \fn     ParseCPUArgs(tStrComp *pArgs, const tCPUArg *pCPUArgs)
 * \brief  parse possible arguments of CPU
 * \param  pArgs arguments set by user (may be NULL)
 * \param  pCPUArgs arguments provided by target (may be NULL)
 * ------------------------------------------------------------------------ */

static void ParseCPUArgs(const tStrComp *pArgs, const tCPUArg *pCPUArgs)
{
  const tCPUArg *pCPUArg;
  char *pNext, *pSep;
  tStrComp Args, Remainder, NameComp, ValueComp;
  LongInt VarValue;
  Boolean OK;
  String ArgStr;

  /* always reset to defaults, also when no user arguments are given */

  if (!pCPUArgs)
    return;
  for (pCPUArg = pCPUArgs; pCPUArg->pName; pCPUArg++)
    *pCPUArg->pValue = pCPUArg->DefValue;

  if (!pArgs || !*pArgs->str.p_str)
    return;
  StrCompMkTemp(&Args, ArgStr, sizeof(ArgStr));
  StrCompCopy(&Args, pArgs);
  do
  {
    pNext = strchr(Args.str.p_str, ':');
    if (pNext)
      StrCompSplitRef(&Args, &Remainder, &Args, pNext);
    pSep = strchr(Args.str.p_str, '=');
    if (!pSep) WrStrErrorPos(ErrNum_ArgValueMissing, &Args);
    else
    {
      StrCompSplitRef(&NameComp, &ValueComp, &Args, pSep);
      KillPrefBlanksStrCompRef(&NameComp); KillPostBlanksStrComp(&NameComp);
      KillPrefBlanksStrCompRef(&ValueComp); KillPostBlanksStrComp(&ValueComp);

      VarValue = EvalStrIntExpression(&ValueComp, Int32, &OK);
      if (OK)
      {
        for (pCPUArg = pCPUArgs; pCPUArg->pName; pCPUArg++)
        if (!as_strcasecmp(NameComp.str.p_str, pCPUArg->pName))
          break;
        if (!pCPUArg->pName) WrStrErrorPos(ErrNum_UnknownArg, &NameComp);
        else if (ChkRange(VarValue, pCPUArg->Min, pCPUArg->Max))
          *pCPUArg->pValue = VarValue;
      }
    }
    if (pNext)
      Args = Remainder;
  }
  while (pNext);
}

/*!------------------------------------------------------------------------
 * \fn     SetNSeg(as_addrspace_t NSeg, Boolean force_setup)
 * \brief  preparations when segment was switched
 * \param  NSeg new segment to set
 * \param  force_setup perform setup operations even if segment remains same
 * ------------------------------------------------------------------------ */

static void SetNSeg(as_addrspace_t NSeg, Boolean force_setup)
{
  if ((ActPC != NSeg) || !PCsUsed[ActPC] || force_setup)
  {
    flush_bytes();
    ActPC = NSeg;
    if (!PCsUsed[ActPC])
      PCs[ActPC] = SegInits[ActPC];
    PCsUsed[ActPC] = True;
    DontPrint = True;
    as_list_set_max_pc(SegLimits[ActPC]);
  }
}

static void SetCPUCore(const tCPUDef *pCPUDef, const tStrComp *pCPUArgs)
{
  LargeInt HCPU;
  int Digit, Base;
  const char *pRun;

  tStrComp TmpComp;
  static const char Default_CommentLeadIn[] = { ';', '\0', '\0' };
  String TmpCompStr;
  StrCompMkTemp(&TmpComp, TmpCompStr, sizeof(TmpCompStr));

  strmaxcpy(MomCPUIdent, pCPUDef->Name, sizeof(MomCPUIdent));
  MomCPU = pCPUDef->Orig;
  MomVirtCPU = pCPUDef->Number;
  HCPU = 0;
  Base = 10;
  for (pRun = MomCPUIdent; *pRun; pRun++)
  {
    if (isdigit(*pRun))
      Base = 16;
    Digit = DigitVal(*pRun, Base);
    if (Digit >= 0)
      HCPU = (HCPU << 4) + Digit;
  }

  strmaxcpy(TmpCompStr, MomCPUName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, HCPU, SegNone, True);
  strmaxcpy(TmpCompStr, MomCPUIdentName, sizeof(TmpCompStr)); EnterStringSymbol(&TmpComp, MomCPUIdent, True);

  InternSymbol = Default_InternSymbol;
  IntConstModeIBMNoTerm = False;
  DissectBit = Default_DissectBit;
  DissectReg = NULL;
  QualifyQuote = NULL;
  target_operators = no_operators;
  SetIsOccupiedFnc =
  SaveIsOccupiedFnc =
  RestoreIsOccupiedFnc = NULL;
  multi_char_le = False;
  label_leading_colon = False;
  DecodeAttrPart = NULL;
  SwitchIsOccupied =
  PageIsOccupied =
  ShiftIsOccupied = False;
  ChkPC = DefChkPC;
  cpu_2_phys_set_current_check(NULL);
  assume_set(NULL, 0);
  pASSUMEOverride = NULL;
  pCommentLeadIn = Default_CommentLeadIn;
  p_extra_comment_leadin = NULL;
  UnsetCPU();
  strmaxcpy(MomCPUArgs, pCPUArgs ? pCPUArgs->str.p_str : "", STRINGSIZE);

  ParseCPUArgs(pCPUArgs, pCPUDef->pArgs);
  pCPUDef->SwitchProc(pCPUDef->pUserData);

#if 0
  {
    as_addrspace_t addr_space;
    const TFamilyDescr *p_descr = FindFamilyById(HeaderID);

    if (p_descr)
    {
      for (addr_space = SegCode; addr_space <= SegEEData; addr_space++)
        if (((ValidSegs >> addr_space) & 1)
         && (Grans[addr_space] != p_descr->get_granularity(addr_space)))
        {
          fprintf(stderr, "Family %s, segment %d, granularity inconsistent\n",
                  p_descr->Name, addr_space);
        }
    }
  }
#endif

  if (pCPUDef->Number)
    none_target_seglimit = SegLimits[SegCode];

  as_rebuild_main_inst_tables();

  DontPrint = True;
}

void SetCPUByType(CPUVar NewCPU, const tStrComp *pCPUArgs)
{
  const tCPUDef *pCPUDef;

  pCPUDef = LookupCPUDefByVar(NewCPU);
  if (pCPUDef)
  {
    SetCPUCore(pCPUDef, pCPUArgs);
    SetNSeg(SegCode, True);
  }
}

Boolean SetCPUByName(const tStrComp *pName)
{
  const tCPUDef *pCPUDef;

  pCPUDef = LookupCPUDefByName(pName->str.p_str);
  if (!pCPUDef)
    return False;
  else
  {
    int l = strlen(pCPUDef->Name);

    if (pName->str.p_str[l] == ':')
    {
      tStrComp ArgComp;

      StrCompRefRight(&ArgComp, pName, l + 1);
      SetCPUCore(pCPUDef, &ArgComp);
    }
    else
      SetCPUCore(pCPUDef, NULL);
    SetNSeg(SegCode, True);
    return True;
  }
}

/*!------------------------------------------------------------------------
 * \fn     UnsetCPU(void)
 * \brief  Cleanups when switching away from a target
 * ------------------------------------------------------------------------ */

void UnsetCPU(void)
{
  as_addrspace_t seg;

  flush_bytes();
  for (seg = SegNone; seg < SegCountPlusStruct; seg++)
    grans_bits_unused[seg] =
    list_grans_bits_unused[seg] = 0;
  literals_chk_alldone();
  if (SwitchFrom)
  {
    ClearONOFF();
    SwitchFrom();
    SwitchFrom = NULL;
  }
}

static void IntLine(char *pDest, size_t DestSize, LargeWord Inp, tIntConstMode ThisConstMode)
{
  switch (ThisConstMode)
  {
    case eIntConstModeIntel:
      as_snprintf(pDest, DestSize, "%lllx%s", Inp, GetIntConstIntelSuffix(16));
      if (*pDest > '9')
        strmaxprep(pDest, "0", DestSize);
      break;
    case eIntConstModeMoto:
      as_snprintf(pDest, DestSize, "%s%lllx", GetIntConstMotoPrefix(16), Inp);
      break;
    case eIntConstModeC:
      as_snprintf(pDest, DestSize, "0x%lllx", Inp);
      break;
    case eIntConstModeIBM:
      as_snprintf(pDest, DestSize, "x'%lllx'", Inp);
      break;
  }
}


static void CodeSECTION(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    PSaveSection Neu;
    String exp_name_buf;
    tStrComp exp_name;
    const tStrComp *p_exp_name;
    StrCompMkTemp(&exp_name, exp_name_buf, sizeof(exp_name_buf));

    p_exp_name = ExpandStrSymbol(&exp_name, &ArgStr[1], !CaseSensitive);
    if (p_exp_name)
    {
      if (!ChkSymbName(p_exp_name->str.p_str)) WrStrErrorPos(ErrNum_InvSymName, &ArgStr[1]);
      else if ((PassNo == 1) && (GetSectionHandle(p_exp_name->str.p_str, False, MomSectionHandle) != -2)) WrError(ErrNum_DoubleSection);
      else
      {
        Neu = (PSaveSection) malloc(sizeof(TSaveSection));
        Neu->Next = SectionStack;
        Neu->Handle = MomSectionHandle;
        Neu->LocSyms = NULL;
        Neu->GlobSyms = NULL;
        Neu->ExportSyms = NULL;
        SetMomSection(GetSectionHandle(p_exp_name->str.p_str, True, MomSectionHandle));
        SectionStack = Neu;
      }
    }
  }
}


static void CodeENDSECTION_ChkEmptList(as_fwd_sym_t **pp_root)
{
  as_fwd_sym_t *p_tmp;
  String XError;

  while (*pp_root)
  {
    p_tmp = (*pp_root); *pp_root = p_tmp->p_next;
    strmaxcpy(XError, p_tmp->p_name, STRINGSIZE);
    strmaxcat(XError, ", ", STRINGSIZE);
    strmaxcat(XError, p_tmp->p_error_pos, STRINGSIZE);
    WrXError(ErrNum_UndefdForward, XError);
    as_fwd_sym_free(p_tmp);
  }
}

static void CodeENDSECTION(Word Index)
{
  UNUSED(Index);

  if (!SectionStack) WrError(ErrNum_NotInSection);
  else
    switch (ArgCnt)
    {
      case 0:
        goto section_ok;
      case 1:
      {
        String exp_name_buf;
        tStrComp exp_name;
        const tStrComp *p_exp_name;

        StrCompMkTemp(&exp_name, exp_name_buf, sizeof(exp_name_buf));
        p_exp_name = ExpandStrSymbol(&exp_name, &ArgStr[1], !CaseSensitive);
        if (!p_exp_name);
        else if (GetSectionHandle(exp_name.str.p_str, False, SectionStack->Handle) != MomSectionHandle) WrStrErrorPos(ErrNum_WrongEndSect, &ArgStr[1]);
        else
          goto section_ok;
        break;
      }
      default:
        (void)ChkArgCnt(0, 1);
        break;
      section_ok:
      {
        PSaveSection Tmp = SectionStack;
        SectionStack = Tmp->Next;
        CodeENDSECTION_ChkEmptList(&(Tmp->LocSyms));
        CodeENDSECTION_ChkEmptList(&(Tmp->GlobSyms));
        CodeENDSECTION_ChkEmptList(&(Tmp->ExportSyms));
        if (ArgCnt == 0)
          as_snprintf(ListLine, STRINGSIZE, "[%s]", GetSectionName(MomSectionHandle));
        SetMomSection(Tmp->Handle);
        free(Tmp);
      }
    }
}


static void CodeCPU(Word Index)
{
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else
  {
    NLS_UpString(ArgStr[1].str.p_str);
    if (!SetCPUByName(&ArgStr[1]))
      WrStrErrorPos(ErrNum_InvCPUType, &ArgStr[1]);
  }
}

/*!------------------------------------------------------------------------
 * \fn     CodeORG_Core(const tStrComp *pArg)
 * \brief  core function of ORG statement
 * \param  pArg source argument holding new address
 * ------------------------------------------------------------------------ */

static void CodeORG_Core(const tStrComp *pArg)
{
  LargeWord HVal;
  Boolean ValOK;
  tSymbolFlags Flags;

  HVal = EvalStrIntExpressionWithFlags(pArg, LargeUIntType, &ValOK, &Flags);
  if (ValOK)
  {
    if (mFirstPassUnknown(Flags)) WrStrErrorPos(ErrNum_FirstPassCalc, pArg);
    else if (PCs[ActPC] != HVal)
    {
      PCs[ActPC] = HVal;
      DontPrint = True;
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     CodeORG(Word Index)
 * \brief  handle ORG statement
 * ------------------------------------------------------------------------ */

static void CodeORG(Word Index)
{
  UNUSED(Index);

  if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else if (ChkArgCnt(1, 1))
    CodeORG_Core(&ArgStr[1]);
}

/*!------------------------------------------------------------------------
 * \fn     CodeSETEQU(Word MayChange)
 * \brief  handle EQU/SET/EVAL statements
 * \param  MayChange 0 for EQU, 1 for SET/EVAL
 * ------------------------------------------------------------------------ */

static void CodeSETEQU(Word MayChange)
{
  const tStrComp *pName = *LabPart.str.p_str ? &LabPart : &ArgStr[1];
  int ValIndex = *LabPart.str.p_str ? 1 : 2;

  if ((ArgCnt == ValIndex) && !strcmp(pName->str.p_str, PCSymbol))
    CodeORG_Core(&ArgStr[ValIndex]);
  else if (ChkArgCnt(ValIndex, ValIndex + 1))
  {
    TempResult t;
    as_addrspace_t DestSeg;

    as_tempres_ini(&t);
    EvalStrExpression(&ArgStr[ValIndex], &t);
    if (!mFirstPassUnknown(t.Flags))
    {
      if (ArgCnt == ValIndex)
        DestSeg = SegNone;
      else
      {
        NLS_UpString(ArgStr[ValIndex + 1].str.p_str);
        if (!strcmp(ArgStr[ValIndex + 1].str.p_str, "MOMSEGMENT"))
          DestSeg = (as_addrspace_t)ActPC;
        else if (*ArgStr[ValIndex + 1].str.p_str == '\0')
          DestSeg = SegNone;
        else
          DestSeg = addrspace_lookup(ArgStr[ValIndex + 1].str.p_str);
      }
      if (DestSeg >= SegCount) WrStrErrorPos(ErrNum_UnknownSegment, &ArgStr[ValIndex + 1]);
      else
      {
        SetListLineVal(&t);
        PushLocHandle(-1);
        switch (t.Typ)
        {
          case TempInt:
            EnterIntSymbol(pName, t.Contents.Int, DestSeg, MayChange);
            if (AttrPartOpSize[0] != eSymbolSizeUnknown)
              SetSymbolOrStructElemSize(pName, AttrPartOpSize[0]);
            break;
          case TempFloat:
            EnterFloatSymbol(pName, t.Contents.Float, MayChange);
            break;
          case TempString:
            EnterNonZStringSymbolWithFlags(pName, &t.Contents.str, MayChange, t.Flags);
            break;
          case TempReg:
            EnterRegSymbol(pName, &t.Contents.RegDescr, t.DataSize, MayChange, False);
            break;
          default:
            break;
        }
        PopLocHandle();
      }
    }
    as_tempres_free(&t);
  }
}

static void CodeREGCore(const tStrComp *pNameArg, const tStrComp *pValueArg)
{
  TempResult t;

  as_tempres_ini(&t);
  if (InternSymbol)
    InternSymbol(pValueArg->str.p_str, &t);

  switch (t.Typ)
  {
    case TempReg:
      EnterRegSymbol(pNameArg, &t.Contents.RegDescr, t.DataSize, False, True);
      break;
    case TempNone:
    {
      tEvalResult EvalResult;
      tErrorNum ErrorNum;
      tRegDescr RegDescr;

      ErrorNum = EvalStrRegExpressionWithResult(pValueArg, &RegDescr, &EvalResult);

      switch (ErrorNum)
      {
        case ErrNum_SymbolUndef:
          /* ignore undefined symbols in first pass */
          if (PassNo <= MaxSymPass)
          {
            Repass = True;
            LEAVE;
          }
          break;
        case ErrNum_RegWrongTarget:
          /* REG is architecture-agnostic */
          EvalResult.OK = True;
          break;
        default:
          break;
      }

      if (EvalResult.OK)
        EnterRegSymbol(pNameArg, &RegDescr, EvalResult.DataSize, False, True);
      else
        WrStrErrorPos(ErrorNum, pValueArg);
      break;
    }
    default:
      WrStrErrorPos(ErrNum_ExpectReg, pValueArg);
  }

func_exit:
  as_tempres_free(&t);
}

void CodeREG(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
    CodeREGCore(&LabPart, &ArgStr[1]);
}

void CodeNAMEREG(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(2, 2))
    CodeREGCore(&ArgStr[2], &ArgStr[1]);
}

static void CodeRORG(Word Index)
{
  LargeInt HVal;
  Boolean ValOK;
  tSymbolFlags Flags;
  UNUSED(Index);

  if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else if (ChkArgCnt(1, 1))
  {
    HVal = EvalStrIntExpressionWithFlags(&ArgStr[1], LargeSIntType, &ValOK, &Flags);
    if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
    else if (ValOK)
    {
      PCs[ActPC] += HVal;
      DontPrint = True;
    }
  }
}

static void CodeSHARED_BuildComment(char *c, size_t DestSize)
{
  switch (ShareMode)
  {
    case 1:
      as_snprintf(c, DestSize, "(* %s *)", CommPart.str.p_str);
      break;
    case 2:
      as_snprintf(c, DestSize, "/* %s */", CommPart.str.p_str);
      break;
    case 3:
      as_snprintf(c, DestSize, "; %s", CommPart.str.p_str);
      break;
  }
}

static void CodeSHARED(Word Index)
{
  tStrComp *pArg;
  String s, c;
  TempResult t;
  as_symbol_entry_flags_t symbol_flags;

  UNUSED(Index);
  as_tempres_ini(&t);

  if (ShareMode == 0) WrError(ErrNum_NoShareFile);
  else if ((ArgCnt == 0) && (*CommPart.str.p_str != '\0'))
  {
    CodeSHARED_BuildComment(c, sizeof(c));
    errno = 0;
    fprintf(ShareFile, "%s\n", c); ChkIO(ErrNum_FileWriteError);
  }
  else
   forallargs (pArg, True)
   {
     LookupSymbol(pArg, &t, False, TempAll, e_eval_flag_none, &symbol_flags);

     switch (t.Typ)
     {
       case TempInt:
         switch (ShareMode)
         {
           case 1:
             IntLine(s, sizeof(s), t.Contents.Int, eIntConstModeMoto);
             break;
           case 2:
             IntLine(s, sizeof(s), t.Contents.Int, eIntConstModeC);
             break;
           case 3:
             IntLine(s, sizeof(s), t.Contents.Int, IntConstMode);
             break;
         }
         break;
       case TempFloat:
         as_snprintf(s, sizeof(s), "%0.17g", t.Contents.Float);
         break;
       case TempString:
         as_nonz_dynstr_to_c_str(s + 1, &t.Contents.str, sizeof(s) - 1);
         if (ShareMode == 1)
         {
           *s = '\'';
           strmaxcat(s, "\'", STRINGSIZE);
         }
         else
         {
           *s = '\"';
           strmaxcat(s, "\"", STRINGSIZE);
         }
         break;
       default:
         continue;
     }

     if ((pArg == ArgStr + 1) && (*CommPart.str.p_str != '\0'))
     {
       CodeSHARED_BuildComment(c, sizeof(c));
       strmaxprep(c, " ", STRINGSIZE);
     }
     else
       *c = '\0';
     errno = 0;
     switch (ShareMode)
     {
       case 1:
         fprintf(ShareFile, "%s = %s;%s\n", pArg->str.p_str, s, c);
         break;
       case 2:
         fprintf(ShareFile, "#define %s %s%s\n", pArg->str.p_str, s, c);
         break;
       case 3:
         strmaxprep(s, (symbol_flags & e_symbol_entry_flag_changeable) ? "set " : "equ ", STRINGSIZE);
         fprintf(ShareFile, "%s %s%s\n", pArg->str.p_str, s, c);
         break;
     }
     ChkIO(ErrNum_FileWriteError);
   }
  as_tempres_free(&t);
}

static void CodeEXPORT(Word Index)
{
  tStrComp *pArg;
  TempResult t;

  UNUSED(Index);
  as_tempres_ini(&t);

  forallargs (pArg, True)
  {
    LookupSymbol(pArg, &t, True, TempInt, e_eval_flag_none, NULL);
    if (TempNone == t.Typ)
      continue;
    if (t.Relocs == NULL)
      AddExport(pArg->str.p_str, t.Contents.Int, 0);
    else if ((t.Relocs->Next != NULL) || (strcmp(t.Relocs->Ref, RelName_SegStart)))
      WrStrErrorPos(ErrNum_Unexportable, pArg);
    else
      AddExport(pArg->str.p_str, t.Contents.Int, RelFlag_Relative);
    if (t.Relocs)
      FreeRelocs(&t.Relocs);
  }
  as_tempres_free(&t);
}

static void CodePAGE(Word Index)
{
  Integer LVal, WVal;
  Boolean ValOK;
  UNUSED(Index);

  if (!ChkArgCnt(1, 2));
  else if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else
  {
    LVal = EvalStrIntExpression(&ArgStr[1], UInt8, &ValOK);
    if (ValOK)
    {
      if ((LVal < 5) && (LVal != 0))
        LVal = 5;
      if (ArgCnt == 1)
      {
        WVal = 0;
        ValOK = True;
      }
      else
        WVal = EvalStrIntExpression(&ArgStr[2], UInt8, &ValOK);
      if (ValOK)
      {
        if ((WVal < 5) && (WVal != 0))
          WVal = 5;
        PageLength = LVal;
        PageWidth = WVal;
      }
    }
  }
}


static void CodeNEWPAGE(Word Index)
{
  ShortInt HVal8;
  Boolean ValOK;
  UNUSED(Index);

  if (!ChkArgCnt(0, 1));
  else if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else
  {
    if (ArgCnt == 0)
    {
      HVal8 = 0;
      ValOK = True;
    }
    else
      HVal8 = EvalStrIntExpression(&ArgStr[1], Int8, &ValOK);
    if ((ValOK) || (ArgCnt == 0))
    {
      if (HVal8 > ChapMax)
        HVal8 = ChapMax;
      else if (HVal8 < 0)
        HVal8 = 0;
      NewPage(HVal8, True);
    }
  }
}


static void CodeString(Word Index)
{
  if (ChkArgCnt(1, 1))
  {
    Boolean OK;
    as_nonz_dynstr_t tmp;

    as_nonz_dynstr_ini(&tmp, 0);
    EvalStrStringExpression(&ArgStr[1], &OK, &tmp);
    if (!OK) WrError(ErrNum_InvString);
    else
    {
      switch (Index)
      {
        case 0:
          as_nonz_dynstr_to_c_str(PrtInitString, &tmp, sizeof(PrtInitString));
          break;
        case 1:
          as_nonz_dynstr_to_c_str(PrtExitString, &tmp, sizeof(PrtExitString));
          break;
        case 2:
          as_nonz_dynstr_to_c_str(PrtTitleString, &tmp, sizeof(PrtTitleString));
          break;
      }
    }
    as_nonz_dynstr_free(&tmp);
  }
}


static void CodePHASE(Word Index)
{
  Boolean OK;
  LongWord HVal;
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (ActPC == StructSeg) WrError(ErrNum_PhaseDisallowed);
  else
  {
    HVal = EvalStrIntExpression(&ArgStr[1], Int32, &OK);
    if (OK)
    {
      tSavePhase *pSavePhase;

      pSavePhase = (tSavePhase*)calloc(1, sizeof (*pSavePhase));
      pSavePhase->SaveValue = Phases[ActPC];
      pSavePhase->pNext = pPhaseStacks[ActPC];
      pPhaseStacks[ActPC] = pSavePhase;
      Phases[ActPC] = HVal - ProgCounter();
    }
  }
}


static void CodeDEPHASE(Word Index)
{
  UNUSED(Index);

  if (!ChkArgCnt(0, 0));
  else if (ActPC == StructSeg) WrError(ErrNum_PhaseDisallowed);
  else if (pPhaseStacks[ActPC])
  {
    tSavePhase *pSavePhase;

    pSavePhase = pPhaseStacks[ActPC];
    pPhaseStacks[ActPC] = pSavePhase->pNext;
    Phases[ActPC] = pSavePhase->SaveValue;
    free(pSavePhase);
  }
  else
    Phases[ActPC] = 0;
}

enum { e_level_message, e_level_warning, e_level_error, e_level_fatal };

static void CodeMESSAGE(Word level)
{
  if (ChkArgCnt(1, 1))
  {
    as_nonz_dynstr_t mess;
    Boolean OK;

    as_nonz_dynstr_ini(&mess, 0);
    EvalStrStringExpression(&ArgStr[1], &OK, &mess);
    if (OK)
    {
      as_nonz_dynstr_append_char(&mess, '\0');
      if (level == e_level_message)
      {
        if (msg_level >= e_msg_level_normal)
          WrConsoleLine(mess.p_str, True);
        if (strcmp(LstName, "/dev/null"))
          WrLstLine(mess.p_str);
      }
      else if ((level != e_level_error) || !FindAndTakeExpectError(ErrNum_UserError))
      {
        char add[11];

        if (NumericErrors)
          as_snprintf(add, sizeof(add), " #%d", ErrNum_UserError);
        else
          *add = '\0';
        WrErrorString(mess.p_str, add, level == e_level_warning, level == e_level_fatal, NULL, NULL);
      }
    }
    as_nonz_dynstr_free(&mess);
  }
}

static void CodeCHARSET(Word Index)
{
  UNUSED(Index);

  if (!ChkArgCnt(0, 3));
  else if (ArgCnt == 0)
    as_chartrans_table_reset(CurrTransTable->p_table);
  else
  {
    TempResult t;

    as_tempres_ini(&t);
    EvalStrExpression(&ArgStr[1], &t);
    if ((t.Typ == TempString) && (t.Flags & eSymbolFlag_StringSingleQuoted))
      TempResultToInt(&t);
    switch (t.Typ)
    {
      case TempInt:
        if (mFirstPassUnknown(t.Flags))
          t.Contents.Int &= 255;
        if (ChkRange(t.Contents.Int, 0, 255))
        {
          if (ChkArgCnt(2, 3))
          {
            LongWord Start = t.Contents.Int;
            if ((ArgCnt == 2) && (!ArgStr[2].str.p_str[0]))
            {
              as_chartrans_table_unset(CurrTransTable->p_table, Start);
            }
            else
            {
              EvalStrExpression(&ArgStr[2], &t);
              if ((t.Typ == TempString) && (t.Flags & eSymbolFlag_StringSingleQuoted))
                TempResultToInt(&t);
              switch (t.Typ)
              {
                case TempInt: /* Uebersetzungsbereich als Character-Angabe */
                  if (mFirstPassUnknown(t.Flags))
                    t.Contents.Int &= 255;
                  if (ChkRange(t.Contents.Int, 0, 255))
                  {
                    if (ArgCnt == 2)
                      as_chartrans_table_set(CurrTransTable->p_table, Start, t.Contents.Int);
                    else if (!ArgStr[3].str.p_str[0])
                      as_chartrans_table_unset_mult(CurrTransTable->p_table, Start, t.Contents.Int);
                    else if (ChkRange(t.Contents.Int, Start, 255))
                    {
                      Boolean OK;
                      LongWord Stop = t.Contents.Int,
                               TStart = EvalStrIntExpression(&ArgStr[3], UInt8, &OK);
                      if (OK)
                        as_chartrans_table_set_mult(CurrTransTable->p_table, Start, Stop, TStart);
                    }
                  }
                  break;
                case TempString:
                {
                  LongWord l = t.Contents.str.len; /* Uebersetzungsstring ab Start */

                  if (Start + l > 256) WrError(ErrNum_OverRange);
                  else
                  {
                    LongWord z;

                    for (z = 0; z < l; z++)
                      as_chartrans_table_set(CurrTransTable->p_table, Start + z, t.Contents.str.p_str[z]);
                  }
                  break;
                }
                case TempFloat:
                  WrStrErrorPos(ErrNum_StringOrIntButFloat, &ArgStr[2]);
                  break;
                default:
                  break;
              }
            }
          }
        }
        break;
      case TempString:
        if (ChkArgCnt(1, 1)) /* Tabelle von Datei lesen */
        {
          String Tmp;
          FILE *f;
          unsigned char tfield[256];
          LongWord z;

          as_nonz_dynstr_to_c_str(Tmp, &t.Contents.str, sizeof(Tmp));
          f = fopen(Tmp, OPENRDMODE);
          if (!f) ChkIO(ErrNum_OpeningFile);
          if (fread(tfield, sizeof(char), 256, f) != 256) ChkIO(ErrNum_FileReadError);
          fclose(f);
          for (z = 0; z < 256; z++)
            as_chartrans_table_set(CurrTransTable->p_table, z, tfield[z]);
        }
        break;
      case TempFloat:
        WrStrErrorPos(ErrNum_StringOrIntButFloat, &ArgStr[1]);
        break;
      default:
        break;
    }
    as_tempres_free(&t);
  }
}

static void CodePRSET(Word Index)
{
  UNUSED(Index);

  as_chartrans_table_print(CurrTransTable->p_table, stdout);
}

static void CodeCODEPAGE(Word Index)
{
  PTransTable Source;
  UNUSED(Index);

  if (!ChkArgCnt(1, 2));
  else if (!ChkSymbName(ArgStr[1].str.p_str)) WrStrErrorPos(ErrNum_InvSymName, &ArgStr[1]);
  else
  {
    Source = (ArgCnt == 1) ? CurrTransTable : FindCodepage(ArgStr[2].str.p_str, NULL);
    if (!Source) WrStrErrorPos(ErrNum_UnknownCodepage, &ArgStr[2]);
    else
    {
      Source = FindCodepage(ArgStr[1].str.p_str, Source);
      if (Source)
        CurrTransTable = Source;
    }
  }
}

static void CodeFUNCTION(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, ArgCntMax))
  {
    Boolean OK;
    int z, z2;
    StringList arg_list;

    InitStringList(&arg_list);
    for (z = 1, OK = True; (z < ArgCnt) && OK; z++)
    {
      if (!ChkMacSymbName(ArgStr[z].str.p_str))
      {
        WrStrErrorPos(ErrNum_InvSymName, &ArgStr[z]);
        OK = False;
        break;
      }
      for (z2 = 1; z2 < z; z2++)
      {
        OK = CaseSensitive 
           ? !!strcmp(ArgStr[z].str.p_str, ArgStr[z2].str.p_str)
           : !!as_strcasecmp(ArgStr[z].str.p_str, ArgStr[z2].str.p_str);
        if (!OK)
        {
          WrStrErrorPos(ErrNum_DupFuncArgName, &ArgStr[z]);
          break;
        }
      }
      AddStringListLast(&arg_list, ArgStr[z].str.p_str);
    }
    if (OK)
      EnterFunction(&LabPart, ArgStr[ArgCnt].str.p_str, ArgCnt - 1, &arg_list);
    ClearStringList(&arg_list);
  }
}


static void CodeSAVE(Word Index)
{
  PSaveState Neu;
  UNUSED(Index);

  if (ChkArgCnt(0, 0))
  {
    Neu = (PSaveState) malloc(sizeof(TSaveState));
    Neu->Next = FirstSaveState;
    Neu->SaveCPU = MomCPU;
    Neu->pSaveCPUArgs = as_strdup(MomCPUArgs);
    Neu->SavePC = ActPC;
    Neu->SaveListOn = ListOn;
    Neu->SaveLstMacroExp = GetLstMacroExp();
    Neu->SaveLstMacroExpModDefault = LstMacroExpModDefault;
    Neu->SaveLstMacroExpModOverride = LstMacroExpModOverride;
    Neu->SaveTransTable = CurrTransTable;
    Neu->SaveEnumSegment = EnumSegment;
    Neu->SaveEnumIncrement = EnumIncrement;
    Neu->SaveEnumCurrentValue = EnumCurrentValue;
    FirstSaveState = Neu;
  }
}


static void CodeRESTORE(Word Index)
{
  PSaveState Old;
  UNUSED(Index);

  if (!ChkArgCnt(0, 0));
  else if (!FirstSaveState) WrError(ErrNum_NoSaveFrame);
  else
  {
    tStrComp TmpComp;
    String TmpCompStr;

    Old = FirstSaveState; FirstSaveState = Old->Next;
    if (Old->SavePC != ActPC)
    {
      ActPC = Old->SavePC;
      DontPrint = True;
    }
    if (Old->SaveCPU != MomCPU)
    {
      StrCompMkTemp(&TmpComp, Old->pSaveCPUArgs, 0);
      SetCPUByType(Old->SaveCPU, &TmpComp);
    }
    StrCompMkTemp(&TmpComp, TmpCompStr, sizeof(TmpCompStr));
    strmaxcpy(TmpCompStr, ListOnName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, ListOn = Old->SaveListOn, SegNone, True);
    SetLstMacroExp(Old->SaveLstMacroExp);
    LstMacroExpModDefault = Old->SaveLstMacroExpModDefault;
    LstMacroExpModOverride = Old->SaveLstMacroExpModOverride;
    CurrTransTable = Old->SaveTransTable;
    free(Old->pSaveCPUArgs);
    free(Old);
  }
}


static void CodeMACEXP(Word Index)
{
  /* will deprecate this in 1..2 years, 2018-01-21 */

#if 0
  if (Index & 0x10)
  {
    char Msg[70];

    as_snprintf(Msg, sizeof(Msg), getmessage(Num_ErrMsgDeprecated_Instead), "MACEXP_DFT");
    WrXError(ErrNum_Deprecated, Msg);
  }
#endif

  /* allow zero arguments for MACEXP_OVR, to remove all overrides */

  if (!ChkArgCnt((Index & 0x0f) ? 0 : 1, ArgCntMax));
  else if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else
  {
    tStrComp *pArg;
    tLstMacroExpMod LstMacroExpMod;
    tLstMacroExp Mod;
    Boolean Set;
    Boolean OK = True;

    InitLstMacroExpMod(&LstMacroExpMod);
    forallargs (pArg, True)
    {
      if (!as_strcasecmp(pArg->str.p_str, "ON"))
      {
        Mod = eLstMacroExpAll; Set = True;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "OFF"))
      {
        Mod = eLstMacroExpAll; Set = False;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "NOIF"))
      {
        Mod= eLstMacroExpIf; Set = False;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "NOMACRO"))
      {
        Mod = eLstMacroExpMacro; Set = False;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "NOREST"))
      {
        Mod = eLstMacroExpRest; Set = False;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "IF"))
      {
        Mod = eLstMacroExpIf; Set = True;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "MACRO"))
      {
        Mod = eLstMacroExpMacro; Set = True;
      }
      else if (!as_strcasecmp(pArg->str.p_str, "REST"))
      {
        Mod = eLstMacroExpRest; Set = True;
      }
      else
      {
        Mod = eLstMacroExpNone; Set = False;
      }
      if (Mod == eLstMacroExpNone)
      {
        WrStrErrorPos(ErrNum_TooManyMacExpMod, pArg);
        OK = False;
        break;
      }
      else if (!AddLstMacroExpMod(&LstMacroExpMod, Set, Mod))
      {
        WrStrErrorPos(ErrNum_TooManyArgs, pArg);
        break;
      }
    }
    if (OK)
    {
      if (!ChkLstMacroExpMod(&LstMacroExpMod)) WrError(ErrNum_ConflictingMacExpMod);
      else if (Index) /* Override */
        LstMacroExpModOverride = LstMacroExpMod;
      else
      {
        /* keep LstMacroExp and LstMacroExpModDefault in sync! */
        LstMacroExpModDefault = LstMacroExpMod;
        SetLstMacroExp(ApplyLstMacroExpMod(eLstMacroExpAll, &LstMacroExpModDefault));
      }
    }
  }
}

static Boolean DecodeSegment(const tStrComp *pArg, as_addrspace_t StartSeg, as_addrspace_t *pResult)
{
  as_addrspace_t SegZ;
  Word Mask;

  for (SegZ = StartSeg, Mask = 1 << StartSeg; SegZ < SegCount; SegZ++, Mask <<= 1)
    if ((ValidSegs & Mask) && !as_strcasecmp(pArg->str.p_str, SegNames[SegZ]))
    {
      *pResult = SegZ;
      return True;
    }
  WrStrErrorPos(ErrNum_UnknownSegment, pArg);
  return False;
}

static void CodeSEGMENT(Word Index)
{
  as_addrspace_t NewSegment;
  UNUSED(Index);

  if (ChkArgCnt(1, 1)
   && DecodeSegment(&ArgStr[1], SegCode, &NewSegment))
    SetNSeg(NewSegment, False);
}


static void CodeLABEL(Word Index)
{
  LongInt Erg;
  Boolean OK;
  tSymbolFlags Flags;
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    Erg = EvalStrIntExpressionWithFlags(&ArgStr[1], Int32, &OK, &Flags);
    if (OK && !mFirstPassUnknown(Flags))
    {
      PushLocHandle(-1);
      EnterIntSymbol(&LabPart, Erg, SegCode, False);
      *ListLine = '=';
      IntLine(ListLine + 1, STRINGSIZE - 1, Erg, IntConstMode);
      PopLocHandle();
    }
  }
}


static void CodeREAD(Word Index)
{
  LongInt SaveLocHandle;
  UNUSED(Index);

  if (ChkArgCnt(1, 2))
  {
    as_nonz_dynstr_t prompt;
    Boolean OK;

    as_nonz_dynstr_ini(&prompt, 0);
    if (ArgCnt == 2)
    {
      EvalStrStringExpression(&ArgStr[1], &OK, &prompt);
      if (OK) as_nonz_dynstr_append_char(&prompt, '\0');
    }
    else
    {
      as_snprintf(prompt.p_str, STRINGSIZE, "Read %s ? ", ArgStr[1].str.p_str);
      OK = True;
    }
    if (OK)
    {
      TempResult Erg;
      String input_str;

      as_tempres_ini(&Erg);
      printf("%s", prompt.p_str);
      fflush(stdout);
      if (!fgets(input_str, sizeof(input_str), stdin))
        OK = False;
      else
      {
        tStrComp input;
        StrCompMkTemp(&input, input_str, sizeof(input_str));
        UpString(input_str);
        EvalStrExpression(&input, &Erg);
      }
      if (OK)
      {
        SetListLineVal(&Erg);
        SaveLocHandle = MomLocHandle;
        MomLocHandle = -1;
        if (mFirstPassUnknown(Erg.Flags)) WrError(ErrNum_FirstPassCalc);
        else switch (Erg.Typ)
        {
          case TempInt:
            EnterIntSymbol(&ArgStr[ArgCnt], Erg.Contents.Int, SegNone, True);
            break;
          case TempFloat:
            EnterFloatSymbol(&ArgStr[ArgCnt], Erg.Contents.Float, True);
            break;
          case TempString:
            EnterNonZStringSymbol(&ArgStr[ArgCnt], &Erg.Contents.str, True);
            break;
          default:
            break;
        }
        MomLocHandle = SaveLocHandle;
      }
      as_tempres_free(&Erg);
    }
    as_nonz_dynstr_free(&prompt);
  }
}

static void CodeRADIX(Word Index)
{
  if (ChkArgCnt(1, 1))
  {
    const char *p_end;
    long tmp = as_cmd_strtol(ArgStr[1].str.p_str, &p_end);

    if (*p_end) WrStrErrorPos(ErrNum_ExpectInt, &ArgStr[1]);
    else if (ChkRangePos(tmp, 2, 36, &ArgStr[1]))
    {
      if (Index == 1)
        OutRadixBase = tmp;
      else
        RadixBase = tmp;
    }
  }
}

static void CodeALIGN(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, 2))
  {
    Word AlignValue;
    Byte AlignFill = 0;
    Boolean OK = True;
    tSymbolFlags Flags = eSymbolFlag_None;
    LongInt NewPC;

    if (2 == ArgCnt)
      AlignFill = EvalStrIntExpressionWithFlags(&ArgStr[2], Int8, &OK, &Flags);
    if (OK)
      AlignValue = EvalStrIntExpression(&ArgStr[1], Int16, &OK);
    if (OK)
    {
      if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
      else
      {
        NewPC = EProgCounter() + AlignValue - 1;
        NewPC -= NewPC % AlignValue;
        CodeLen = NewPC - EProgCounter();
        if (1 == ArgCnt)
        {
          DontPrint = !!CodeLen;
          BookKeeping();
        }
        else if (CodeLen > (LongInt)MaxCodeLen) WrError(ErrNum_CodeOverflow);
        else
        {
          memset(BAsmCode, AlignFill, CodeLen);
          DontPrint = False;
        }
      }
    }
  }
}

static void CodeASSUME(Word Index)
{
  int z1;
  Boolean OK;
  tSymbolFlags Flags;
  LongInt HVal;
  tStrComp RegPart, ValPart;
  char *pSep, EmptyStr[] = "";
  const as_assume_rec_t *p_rec;
  void (*pPostProcs[5])(void);
  unsigned PostProcCount = 0, z3;

  UNUSED(Index);

  /* CPU-specific override? */

  if (pASSUMEOverride)
  {
    pASSUMEOverride();
    return;
  }

  if (ChkArgCnt(1, ArgCntMax))
  {
    z1 = 1;
    OK = True;
    while ((z1 <= ArgCnt) && OK)
    {
      pSep = QuotPos(ArgStr[z1].str.p_str, ':');
      if (pSep)
        StrCompSplitRef(&RegPart, &ValPart, &ArgStr[z1], pSep);
      else
      {
        RegPart = ArgStr[z1];
        StrCompMkTemp(&ValPart, EmptyStr, 0);
      }
      NLS_UpString(RegPart.str.p_str);
      p_rec = assume_lookup(RegPart.str.p_str);
      if (!p_rec)
      {
        WrStrErrorPos(ErrNum_InvRegName, &RegPart);
        OK = False;
      }
      else
      {
        if (!as_strcasecmp(ValPart.str.p_str, "NOTHING"))
        {
          if (p_rec->nothing_value == -1) WrError(ErrNum_InvAddrMode);
          else
            *(p_rec->p_dest) = p_rec->nothing_value;
        }
        else
        {
          HVal = EvalStrIntExpressionWithFlags(&ValPart, Int32, &OK, &Flags);
          if (OK)
          {
            if (mFirstPassUnknown(Flags))
            {
              WrError(ErrNum_FirstPassCalc);
              OK = False;
            }
            else if (ChkRange(HVal, p_rec->min_value, p_rec->max_value))
              *(p_rec->p_dest) = HVal;
          }
        }
        /* collect different post procs so same proc is called only once */
        if (p_rec->p_post_proc)
        {
          for (z3 = 0; z3 < PostProcCount; z3++)
            if (p_rec->p_post_proc == pPostProcs[z3])
              break;
          if (z3 >= PostProcCount)
          {
            if (PostProcCount >= as_array_size(pPostProcs))
            {
              for (z3 = 0; z3 < PostProcCount; z3++)
                pPostProcs[z3]();
              PostProcCount = 0;
            }
            pPostProcs[PostProcCount++] = p_rec->p_post_proc;
          }
        }
      }
      z1++;
    }
    for (z3 = 0; z3 < PostProcCount; z3++)
      pPostProcs[z3]();
  }
}

static void CodeENUM(Word IsNext)
{
  int z;
  char *p = NULL;
  Boolean OK;
  tSymbolFlags Flags;
  LongInt  First = 0, Last = 0;
  tStrComp SymPart;

  if (!IsNext)
    EnumCurrentValue = 0;
  if (ChkArgCnt(1, ArgCntMax))
  {
    for (z = 1; z <= ArgCnt; z++)
    {
      p = QuotPos(ArgStr[z].str.p_str, '=');
      if (p)
      {
        StrCompSplitRef(&ArgStr[z], &SymPart, &ArgStr[z], p);
        EnumCurrentValue = EvalStrIntExpressionWithFlags(&SymPart, Int32, &OK, &Flags);
        if (!OK)
          return;
        if (mFirstPassUnknown(Flags))
        {
          WrStrErrorPos(ErrNum_FirstPassCalc, &SymPart);
          return;
        }
        *p = '\0';
      }
      EnterIntSymbol(&ArgStr[z], EnumCurrentValue, (as_addrspace_t)EnumSegment, False);
      if (z == 1)
        First = EnumCurrentValue;
      else if (z == ArgCnt)
        Last = EnumCurrentValue;
      EnumCurrentValue += EnumIncrement;
    }
  }
  *ListLine = '=';
  IntLine(ListLine + 1, STRINGSIZE - 1, First, IntConstMode);
  if (ArgCnt != 1)
  {
    int l;

    strmaxcat(ListLine, "..", STRINGSIZE);
    l = strlen(ListLine);
    IntLine(ListLine + l, STRINGSIZE - l, Last, IntConstMode);
  }
}

static void CodeENUMCONF(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, 2))
  {
    Boolean OK;
    LongInt NewIncrement;

    NewIncrement = EvalStrIntExpression(&ArgStr[1], Int32, &OK);
    if (!OK)
      return;
    EnumIncrement = NewIncrement;

    if (ArgCnt >= 2)
    {
      as_addrspace_t NewSegment;

      if (DecodeSegment(&ArgStr[2], SegNone, &NewSegment))
        EnumSegment = NewSegment;
    }
  }
}

static void CodeEND(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(0, 1))
  {
    if (ArgCnt == 1)
    {
      LongInt HVal;
      tEvalResult EvalResult;

      HVal = EvalStrIntExpressionWithResult(&ArgStr[1], Int32, &EvalResult);
      if (EvalResult.OK)
      {
        ChkSpace(SegCode, EvalResult.AddrSpaceMask);
        StartAdr = HVal;
        StartAdrPresent = True;
      }
    }
   ENDOccured = True;
  }
}


static void CodeLISTING(Word Index)
{
  UNUSED(Index);

  if (!ChkArgCnt(1, 1));
  else if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
  else
  {
    as_liston_t new_liston;

    NLS_UpString(ArgStr[1].str.p_str);
    if (!as_list_liston_to_enum(ArgStr[1].str.p_str, &new_liston))
      WrStrErrorPos(ErrNum_InvListingValue, &ArgStr[1]);
    else
      EnterIntSymbol(&ArgStr[1], ListOn = new_liston, SegNone, True);
  }
}

void INCLUDE_SearchCore(tStrComp *pDest, const tStrComp *pArg, Boolean SearchPath)
{
  size_t l = strlen(pArg->str.p_str), offs = 0;
  int this_pass;

  if (pArg->str.p_str[0] == '"')
  {
    offs++;
    if ((l > 1) && (pArg->str.p_str[l - 1]  == '"'))
      l -= 2;
    else
    {
      WrStrErrorPos(ErrNum_BrackErr, pArg);
      return;
    }
  }
  StrCompCopySub(pDest, pArg, offs, l);

  /* To keep existing functionality, first search for the file name
     possibly expanded by a suffix.  If it was extended, and not found
     with this extension, try the plain name in a second search: */

  this_pass = AddSuffix(pDest->str.p_str, IncSuffix) ? 0 : 1;

  for (; this_pass < 2; this_pass++)
  {
    if (SearchPath)
    {
      String FoundFileName;

      if (FSearch(FoundFileName, sizeof(FoundFileName), pDest->str.p_str, CurrFileName, SearchPath ? IncludeList : ""))
      {
        if (this_pass)
          ChkStrIO(ErrNum_OpeningFile, pArg);
        else
          StrCompCopySub(pDest, pArg, offs, l);
      }
      else
        FExpand(pDest->str.p_str, STRINGSIZE, FoundFileName);
    }
    else
      return;
  }
}

static void CodeBINCLUDE(Word Index)
{
  FILE *F;
  LongInt Len = -1;
  LongWord Ofs = 0, Curr, Rest, FSize;
  Word RLen;
  Boolean OK, SaveTurnWords;
  tSymbolFlags Flags;
  LargeWord OldPC;
  UNUSED(Index);

  if (!ChkArgCnt(1, 3));
  else if (ActPC == StructSeg) WrError(ErrNum_NotInStruct);
  else
  {
    if (ArgCnt == 1)
      OK = True;
    else
    {
      Ofs = EvalStrIntExpressionWithFlags(&ArgStr[2], Int32, &OK, &Flags);
      if (mFirstPassUnknown(Flags))
      {
        WrError(ErrNum_FirstPassCalc);
        OK = False;
      }
      if (OK)
      {
        if (ArgCnt == 2)
          Len = -1;
        else
        {
          Len = EvalStrIntExpressionWithFlags(&ArgStr[3], Int32, &OK, &Flags);
          if (mFirstPassUnknown(Flags))
          {
            WrError(ErrNum_FirstPassCalc);
            OK = False;
          }
        }
      }
    }
    if (OK)
    {
      tStrComp FNameArg;
      String FNameArgStr;

      StrCompMkTemp(&FNameArg, FNameArgStr, sizeof(FNameArgStr));
      INCLUDE_SearchCore(&FNameArg, &ArgStr[1], True);

      F = fopen(FNameArg.str.p_str, OPENRDMODE);
      if (F == NULL) ChkXIO(ErrNum_OpeningFile, FNameArg.str.p_str);
      errno = 0; FSize = FileSize(F); ChkIO(ErrNum_FileReadError);
      if (Len == -1)
      {
        if ((Len = FSize - Ofs) < 0)
        {
          fclose(F); WrError(ErrNum_ShortRead); return;
        }
      }
      if (!ChkPC(PCs[ActPC] + Len - 1)) WrError(ErrNum_AdrOverflow);
      else
      {
        errno = 0; fseek(F, Ofs, SEEK_SET); ChkIO(ErrNum_FileReadError);
        Rest = Len;
        SaveTurnWords = TurnWords;
        TurnWords = False;
        OldPC = ProgCounter();
        do
        {
          Curr = (Rest <= 256) ? Rest : 256;
          errno = 0; RLen = fread(BAsmCode, 1, Curr, F); ChkIO(ErrNum_FileReadError);
          CodeLen = RLen;
          as_code_write_bytes(CodeLen);
          PCs[ActPC] += CodeLen;
          Rest -= RLen;
        }
        while ((Rest != 0) && (RLen == Curr));
        if (Rest != 0) WrError(ErrNum_ShortRead);
        TurnWords = SaveTurnWords;
        DontPrint = True;
        CodeLen = ProgCounter() - OldPC;
        PCs[ActPC] = OldPC;
      }
      fclose(F);
    }
  }
}

static void CodePUSHV(Word Index)
{
  int z;
  UNUSED(Index);

  if (ChkArgCnt(2, ArgCntMax))
  {
    for (z = 2; z <= ArgCnt; z++)
      PushSymbol(&ArgStr[z], &ArgStr[1]);
  }
}

static void CodePOPV(Word Index)
{
  int z;
  UNUSED(Index);

  if (ChkArgCnt(2, ArgCntMax))
  {
    for (z = 2; z <= ArgCnt; z++)
      PopSymbol(&ArgStr[z], &ArgStr[1]);
  }
}

static void CodeSTRUCT(Word IsUnion)
{
  PStructStack NStruct;
  tStrComp *pArg;
  Boolean OK, DoExt;
  char ExtChar;
  String StructName;

  if (!ChkArgCnt(0, ArgCntMax))
    return;

  /* unnamed struct/union only allowed if embedded into at least one named struct/union */

  if (!*LabPart.str.p_str)
  {
    if (!pInnermostNamedStruct)
    {
      WrError(ErrNum_FreestandingUnnamedStruct);
      return;
    }
  }
  else
  {
    if (!ChkSymbName(LabPart.str.p_str))
    {
      WrXError(ErrNum_InvSymName, LabPart.str.p_str);
      return;
    }
    if (!CaseSensitive)
      NLS_UpString(LabPart.str.p_str);
  }

  /* compose name of nested structures */

  if (*LabPart.str.p_str)
    BuildStructName(StructName, sizeof(StructName), LabPart.str.p_str);
  else
    *StructName = '\0';

  /* If named and embedded into another struct, add as element to innermost named parent struct.
     Add up all offsets of unnamed structs in between. */

  if (StructStack && (*LabPart.str.p_str))
  {
    PStructStack pRun;
    LargeWord Offset = ProgCounter();
    PStructElem pElement = CreateStructElem(&LabPart);
    if (!pElement)
      return;

    for (pRun = StructStack; pRun && pRun != pInnermostNamedStruct; pRun = pRun->Next)
      Offset += pRun->SaveCurrPC;
    pElement->Offset = Offset;
    pElement->IsStruct = True;
    AddStructElem(pInnermostNamedStruct->StructRec, pElement);
    AddStructSymbol(LabPart.str.p_str, ProgCounter());
  }

  NStruct = (PStructStack) malloc(sizeof(TStructStack));
  NStruct->Name = as_strdup(StructName);
  NStruct->pBaseName = NStruct->Name + strlen(NStruct->Name) - strlen(LabPart.str.p_str); /* NULL -> complain too long */
  NStruct->SaveCurrPC = ProgCounter();
  DoExt = True;
  ExtChar = DottedStructs ? '.' : '_';
  NStruct->Next = StructStack;
  OK = True;
  forallargs (pArg, True)
    if (OK)
    {
      if (!as_strcasecmp(pArg->str.p_str, "EXTNAMES"))
        DoExt = True;
      else if (!as_strcasecmp(pArg->str.p_str, "NOEXTNAMES"))
        DoExt = False;
      else if (!as_strcasecmp(pArg->str.p_str, "DOTS"))
        ExtChar = '.';
      else if (!as_strcasecmp(pArg->str.p_str, "NODOTS"))
        ExtChar = '_';
      else
      {
        WrStrErrorPos(ErrNum_InvStructDir, pArg);
        OK = False;
      }
    }
  if (OK)
  {
    NStruct->StructRec = CreateStructRec();
    NStruct->StructRec->ExtChar = ExtChar;
    NStruct->StructRec->DoExt = DoExt;
    NStruct->StructRec->IsUnion = IsUnion;
    StructStack = NStruct;
    if (ActPC != StructSeg)
      StructSaveSeg = ActPC;
    if (NStruct->Name[0])
      pInnermostNamedStruct = NStruct;
    ActPC = StructSeg;
    PCs[ActPC] = 0;
    Phases[ActPC] = 0;
    Grans[ActPC] = Grans[SegCode];
    ListGrans[ActPC] = ListGrans[SegCode];
    ClearChunk(SegChunks + StructSeg);
    CodeLen = 0;
    DontPrint = True;
  }
  else
  {
    free(NStruct->Name);
    free(NStruct);
  }
}

static void CodeENDSTRUCT(Word IsUnion)
{
  Boolean OK;
  PStructStack OStruct;

  if (!ChkArgCnt(0, 1));
  else if (!StructStack) WrError(ErrNum_MissingStruct);
  else
  {
    if (IsUnion && !StructStack->StructRec->IsUnion)
      WrXError(ErrNum_STRUCTEndedByENDUNION, StructStack->Name);

    if (*LabPart.str.p_str == '\0') OK = True;
    else
    {
      if (!CaseSensitive)
        NLS_UpString(LabPart.str.p_str);
      OK = !strcmp(LabPart.str.p_str, StructStack->pBaseName);
      if (!OK) WrError(ErrNum_WrongStruct);
    }
    if (OK)
    {
      LargeWord TotLen;

      /* unchain current struct from stack */

      OStruct = StructStack;
      StructStack = OStruct->Next;

      /* resolve referenced symbols in structure */

      ResolveStructReferences(OStruct->StructRec);

      /* find new innermost named struct */

      for (pInnermostNamedStruct = StructStack;
           pInnermostNamedStruct;
           pInnermostNamedStruct = pInnermostNamedStruct->Next)
      {
        if (pInnermostNamedStruct->Name[0])
          break;
      }

      BumpStructLength(OStruct->StructRec, ProgCounter());
      TotLen = OStruct->StructRec->TotLen;

      /* add symbol for struct length if not nameless */

      if (ArgCnt == 0)
      {
        if (OStruct->Name[0])
        {
          String tmp2;
          tStrComp TmpComp;

          as_snprintf(tmp2, sizeof(tmp2), "%s%clen", OStruct->Name, OStruct->StructRec->ExtChar);
          StrCompMkTemp(&TmpComp, tmp2, sizeof(tmp2));
          EnterIntSymbol(&TmpComp, TotLen, SegNone, False);
        }
      }
      else
        EnterIntSymbol(&ArgStr[1], TotLen, SegNone, False);

      {
        TempResult t;

        as_tempres_ini(&t);
        as_tempres_set_int(&t, TotLen);
        SetListLineVal(&t);
        as_tempres_free(&t);
      }

      /* If named, store completed structure.
         Otherwise, discard temporary struct. */

      if (OStruct->Name[0])
        AddStruct(OStruct->StructRec, OStruct->Name, True);
      else
        DestroyStructRec(OStruct->StructRec);
      OStruct->StructRec = NULL;

      /* set PC back to outer's struct value, plus size of
         just completed struct, or non-struct value: */

      PCs[ActPC] = OStruct->SaveCurrPC;
      if (!StructStack)
      {
        ActPC = StructSaveSeg;
        CodeLen = 0;
      }
      else
      {
        CodeLen = TotLen;
      }

      /* free struct stack elements no longer needed */

      free(OStruct->Name);
      free(OStruct);
      ClearChunk(SegChunks + StructSeg);
      DontPrint = True;
    }
  }
}

static void CodeEXTERN(Word Index)
{
  char *Split;
  int i;
  Boolean OK;
  as_addrspace_t Type;
  UNUSED(Index);

  if (ChkArgCnt(1, ArgCntMax))
  {
    i = 1;
    OK = True;
    while ((OK) && (i <= ArgCnt))
    {
      Split = strrchr(ArgStr[i].str.p_str, ':');
      if (Split == NULL)
        Type = SegNone;
      else
      {
        *Split = '\0';
        for (Type = SegNone + 1; Type < SegCount; Type++)
          if (!as_strcasecmp(Split + 1, SegNames[Type]))
            break;
      }
      if (Type >= SegCount) WrXError(ErrNum_UnknownSegment, Split + 1);
      else
      {
        EnterExtSymbol(&ArgStr[i], 0, Type, FALSE);
      }
      i++;
    }
  }
}

static void CodeNESTMAX(Word Index)
{
  LongInt Temp;
  Boolean OK;
  tSymbolFlags Flags;
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    Temp = EvalStrIntExpressionWithFlags(&ArgStr[1], UInt32, &OK, &Flags);
    if (OK)
    {
      if (mFirstPassUnknown(Flags)) WrError(ErrNum_FirstPassCalc);
      else NestMax = Temp;
    }
  }
}

static void CodeSEGTYPE(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(0, 0))
    RelSegs = (as_toupper(*OpPart.str.p_str) == 'R');
}

static void CodePPSyms(Boolean is_forward,
                       as_fwd_sym_t **pp_orig,
                       as_fwd_sym_t **pp_alt1,
                       as_fwd_sym_t **pp_alt2)
{
  tStrComp *p_arg, exp_sym;
  String exp_sym_buf;
  LongInt section;

  StrCompMkTemp(&exp_sym, exp_sym_buf, sizeof(exp_sym_buf));
  if (ChkArgCnt(1, ArgCntMax))
    forallargs (p_arg, True)
    {
      char *p_split = QuotPos(p_arg->str.p_str, ':');
      const tStrComp *p_sym_arg;
      tStrComp sym_arg;

      if (p_split)
      {
        tStrComp section_arg;

        StrCompSplitRef(&sym_arg, &section_arg, p_arg, p_split);
        IdentifySection(&section_arg, &section);
        if (is_forward)
        {
          if (section != MomSectionHandle)
            WrStrErrorPos(ErrNum_ForwardNonCurrent, &section_arg);
          section = -1;
        }
        p_sym_arg = &sym_arg;
      }
      else
      {
        section = -1; /* SECTION_CURRENT */
        p_sym_arg = p_arg;
      }
      if (pp_orig)
      {
        if (!ExpandStrSymbol(&exp_sym, p_sym_arg, !CaseSensitive))
          return;

        if (as_fwd_sym_search(*pp_alt1, exp_sym.str.p_str)
         || as_fwd_sym_search(*pp_alt2, exp_sym.str.p_str))
          WrStrErrorPos(ErrNum_ContForward, p_arg);
        else
        {
          as_fwd_sym_t *p_sym = as_fwd_sym_search(*pp_orig, exp_sym.str.p_str);
          if (!p_sym)
          {
            p_sym = as_fwd_sym_create();
            p_sym->p_next = *pp_orig; *pp_orig = p_sym;
            p_sym->p_name = as_strdup(exp_sym.str.p_str);
            p_sym->p_error_pos = GetErrorPos();
            p_sym->dest_section = section;
          }
        }
      }

      if (!p_split && is_forward)
        EnterNoneSymbol(p_arg);
    }
}

/*------------------------------------------------------------------------*/

typedef struct
{
  Boolean Persist, *FlagAddr;
  const char *FlagName;
  const char *InstName;
} ONOFFTab;
static ONOFFTab *ONOFFList = NULL;
static size_t ONOFFCnt = 0;

Boolean CheckONOFFArg(const tStrComp *pArg, Boolean *pResult)
{
  *pResult = !as_strcasecmp(ArgStr[1].str.p_str, "ON");
  if (!*pResult && as_strcasecmp(ArgStr[1].str.p_str, "OFF"))
  {
    WrStrErrorPos(ErrNum_OnlyOnOff, pArg);
    return False;
  }
  return True;
}

static void DecodeONOFF(Word Index)
{
  ONOFFTab *Tab = ONOFFList + Index;

  if (ChkArgCnt(1, 1))
  {
    Boolean IsON;

    if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
    else if (CheckONOFFArg(&ArgStr[1], &IsON))
      SetFlag(Tab->FlagAddr, Tab->FlagName, IsON);
  }
}

void AddONOFF(const char *InstName, Boolean *Flag, const char *FlagName, Boolean Persist)
{
  dyn_array_rsv_end(ONOFFList, ONOFFTab, ONOFFCnt);
  ONOFFList[ONOFFCnt].Persist = Persist;
  ONOFFList[ONOFFCnt].FlagAddr = Flag;
  ONOFFList[ONOFFCnt].FlagName = FlagName;
  ONOFFList[ONOFFCnt].InstName = InstName;
  AddInstTable(ONOFFTable, InstName, ONOFFCnt++, DecodeONOFF);
}

void ClearONOFF(void)
{
  size_t z, z2;

  for (z = 0; z < ONOFFCnt; z++)
    if (!ONOFFList[z].Persist)
      break;

  if (z < ONOFFCnt)
  {
    for (z2 = ONOFFCnt - 1; z2 >= z; z2--)
      RemoveInstTable(ONOFFTable, ONOFFList[z2].InstName);

    dyn_array_realloc(ONOFFList, ONOFFTab, ONOFFCnt, z);
    ONOFFCnt = z;
  }
}

/*!------------------------------------------------------------------------
 * \fn     CodeRELAXED(Word Index)
 * \brief  handle RELAXED statement
 * ------------------------------------------------------------------------ */

static void CodeRELAXED(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, 1))
  {
    Boolean NewRelaxed;

    NLS_UpString(ArgStr[1].str.p_str);
    if (*AttrPart.str.p_str != '\0') WrError(ErrNum_UseLessAttr);
    else if (CheckONOFFArg(&ArgStr[1], &NewRelaxed))
    {
      SetFlag(&RelaxedMode, RelaxedName, NewRelaxed);
      SetIntConstRelaxedMode(NewRelaxed);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     CodeINTSYNTAX(Word Index)
 * \brief  process INTSYNTAX statement
 * ------------------------------------------------------------------------ */

void CodeINTSYNTAX(Word Index)
{
  UNUSED(Index);

  if (ChkArgCnt(1, ArgCntMax))
  {
    LongWord ANDMask = 0, ORMask = 0;
    tStrComp Ident, *pArg;
    tIntFormatId Id;
    Boolean OK = True;

    forallargs(pArg, OK)
    {
      StrCompRefRight(&Ident, pArg, 1);
      Id = GetIntFormatId(Ident.str.p_str);
      if (!Id)
      {
        WrStrErrorPos(ErrNum_InvIntFormat, &Ident);
        OK = False;
      }
      else switch (pArg->str.p_str[0])
      {
        case '+':
          ORMask |= 1ul << Id;
          break;
        case '-':
          ANDMask |= 1ul << Id;
          break;
        default:
          WrStrErrorPos(ErrNum_InvIntFormat, pArg);
        OK = False;
      }
    }
    if (OK)
    {
      if (!ModifyIntConstModeByMask(ANDMask, ORMask))
        WrError(ErrNum_InvIntFormatList);
    }
  }
}

/*!------------------------------------------------------------------------
 * \fn     code_set_cond(Word may_change)
 * \brief  process SET pseudo statement if no machine instruction
 * \param  may_change fixed True for SET
 * \return True if instruction was processed
 * ------------------------------------------------------------------------ */

static Boolean code_set_cond(Word may_change)
{
  if (is_set_pseudo())
  {
    CodeSETEQU(may_change);
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_save_cond(Word may_change)
 * \brief  process SAVE pseudo statement if no machine instruction
 * \param  may_change fixed 0 for SAVE
 * \return True if instruction was processed
 * ------------------------------------------------------------------------ */

static Boolean code_save_cond(Word arg)
{
  if (is_save_pseudo())
  {
    CodeSAVE(arg);
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_page_cond(Word may_change)
 * \brief  process PAGE pseudo statement if no machine instruction
 * \param  may_change fixed 0 for PAGE
 * \return True if instruction was processed
 * ------------------------------------------------------------------------ */

static Boolean code_page_cond(Word arg)
{
  if (is_page_pseudo())
  {
    CodePAGE(arg);
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_pagesize_cond(Word may_change)
 * \brief  process PAGESIZE pseudo statement if PAGE is a machine instruction
 * \param  may_change fixed 0 for PAGESIZE
 * \return True if instruction was processed
 * ------------------------------------------------------------------------ */

static Boolean code_pagesize_cond(Word arg)
{
  if (PageIsOccupied)
  {
    CodePAGE(arg);
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_restore_cond(Word may_change)
 * \brief  process RESTORE pseudo statement if no machine instruction
 * \param  may_change fixed 0 for RESTORE
 * \return True if instruction was processed
 * ------------------------------------------------------------------------ */

static Boolean code_restore_cond(Word arg)
{
  if (is_restore_pseudo())
  {
    CodeRESTORE(arg);
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_forward_cond(Word arg)
 * \brief  process FORWARD pseudo statement if within section
 * \param  arg constant 0 for FORWARD
 * \return True if processed
 * ------------------------------------------------------------------------ */

static Boolean code_forward_cond(Word arg)
{
  UNUSED(arg);

  if (PassNo <= MaxSymPass)
    CodePPSyms(True,
               SectionStack ? &(SectionStack->LocSyms) : NULL,
               SectionStack ? &(SectionStack->GlobSyms) : NULL,
               SectionStack ? &(SectionStack->ExportSyms) : NULL);
  return True;
}

/*!------------------------------------------------------------------------
 * \fn     code_public_cond(Word arg)
 * \brief  process PUBLIC pseudo statement if within section
 * \param  arg constant 0 for PUBLIC
 * \return True if processed
 * ------------------------------------------------------------------------ */

static Boolean code_public_cond(Word arg)
{
  UNUSED(arg);

  if (SectionStack)
  {
    CodePPSyms(False,
               &(SectionStack->GlobSyms),
               &(SectionStack->LocSyms),
               &(SectionStack->ExportSyms));
    return True;
  }
  else
    return False;
}

/*!------------------------------------------------------------------------
 * \fn     code_global_cond(Word arg)
 * \brief  process GLOBAL pseudo statement if within section
 * \param  arg constant 0 for GLOBAL
 * \return True if processed
 * ------------------------------------------------------------------------ */

static Boolean code_global_cond(Word arg)
{
  UNUSED(arg);

  if (SectionStack)
  {
    CodePPSyms(False,
               &(SectionStack->ExportSyms),
               &(SectionStack->LocSyms),
               &(SectionStack->GlobSyms));
    return True;
  }
  else
    return False;
}

/*------------------------------------------------------------------------*/


Boolean CodeGlobalPseudo(void)
{
  return 
      LookupInstTable(ONOFFTable, OpPart.str.p_str)
   || LookupInstTable(PseudoTable, OpPart.str.p_str)
   || inst_fnc_table_lookup(pseudo_inst_fnc_table, OpPart.str.p_str);
}

void codeallg_init(void)
{
  PseudoTable = CreateInstTable(201);
  AddInstTable(PseudoTable, "ALIGN",      0,  CodeALIGN     );
  AddInstTable(PseudoTable, "ASEG",       0,  CodeSEGTYPE   );
  AddInstTable(PseudoTable, "ASSUME",     0,  CodeASSUME    );
  AddInstTable(PseudoTable, "BINCLUDE",   0,  CodeBINCLUDE  );
  AddInstTable(PseudoTable, "CHARSET",    0,  CodeCHARSET   );
  AddInstTable(PseudoTable, "CODEPAGE",   0,  CodeCODEPAGE  );
  AddInstTable(PseudoTable, "CPU",        0,  CodeCPU       );
  AddInstTable(PseudoTable, "DEPHASE",    0,  CodeDEPHASE   );
  AddInstTable(PseudoTable, "END",        0,  CodeEND       );
  AddInstTable(PseudoTable, "ENDEXPECT",  0,  CodeENDEXPECT );
  AddInstTable(PseudoTable, "ENDS",       0,  CodeENDSTRUCT );
  AddInstTable(PseudoTable, "ENDSECTION", 0,  CodeENDSECTION);
  AddInstTable(PseudoTable, "ENDSTRUC",   0,  CodeENDSTRUCT );
  AddInstTable(PseudoTable, "ENDSTRUCT",  0,  CodeENDSTRUCT );
  AddInstTable(PseudoTable, "ENDUNION",   1,  CodeENDSTRUCT );
  AddInstTable(PseudoTable, "ENUM",       0,  CodeENUM      );
  AddInstTable(PseudoTable, "ENUMCONF",   0,  CodeENUMCONF  );
  AddInstTable(PseudoTable, "EQU",        0,  CodeSETEQU    );
  AddInstTable(PseudoTable, "ERROR",      e_level_error, CodeMESSAGE );
  AddInstTable(PseudoTable, "EXPECT",     0,  CodeEXPECT    );
  AddInstTable(PseudoTable, "EXPORT_SYM", 0,  CodeEXPORT    );
  AddInstTable(PseudoTable, "EXTERN_SYM", 0,  CodeEXTERN    );
  AddInstTable(PseudoTable, "EVAL",       1,  CodeSETEQU    );
  AddInstTable(PseudoTable, "FATAL",      e_level_fatal, CodeMESSAGE );
  AddInstTable(PseudoTable, "FUNCTION",   0,  CodeFUNCTION  );
  AddInstTable(PseudoTable, "INTSYNTAX",  0,  CodeINTSYNTAX );
  AddInstTable(PseudoTable, "LABEL",      0,  CodeLABEL     );
  AddInstTable(PseudoTable, "LISTING",    0,  CodeLISTING   );
  AddInstTable(PseudoTable, "MESSAGE",    e_level_message, CodeMESSAGE );
  AddInstTable(PseudoTable, "NEWPAGE",    0,  CodeNEWPAGE   );
  AddInstTable(PseudoTable, "NESTMAX",    0,  CodeNESTMAX   );
  AddInstTable(PseudoTable, "NEXTENUM",   1,  CodeENUM      );
  AddInstTable(PseudoTable, "ORG",        0,  CodeORG       );
  AddInstTable(PseudoTable, "OUTRADIX",   1,  CodeRADIX     );
  AddInstTable(PseudoTable, "PHASE",      0,  CodePHASE     );
  AddInstTable(PseudoTable, "POPV",       0,  CodePOPV      );
  AddInstTable(PseudoTable, "PRSET",      0,  CodePRSET     );
  AddInstTable(PseudoTable, "PRTINIT",    0,  CodeString    );
  AddInstTable(PseudoTable, "PRTEXIT",    1,  CodeString    );
  AddInstTable(PseudoTable, "TITLE",      2,  CodeString    );
  AddInstTable(PseudoTable, "PUSHV",      0,  CodePUSHV     );
  AddInstTable(PseudoTable, "RADIX",      0,  CodeRADIX     );
  AddInstTable(PseudoTable, "READ",       0,  CodeREAD      );
  AddInstTable(PseudoTable, "RELAXED",    0,  CodeRELAXED   );
  AddInstTable(PseudoTable, "MACEXP",     0x10, CodeMACEXP  );
  AddInstTable(PseudoTable, "MACEXP_DFT", 0,  CodeMACEXP    );
  AddInstTable(PseudoTable, "MACEXP_OVR", 1,  CodeMACEXP    );
  AddInstTable(PseudoTable, "RESTOREENV", 0,  CodeRESTORE   );
  AddInstTable(PseudoTable, "RORG",       0,  CodeRORG      );
  AddInstTable(PseudoTable, "RSEG",       0,  CodeSEGTYPE   );
  AddInstTable(PseudoTable, "SAVEENV",    0,  CodeSAVE      );
  AddInstTable(PseudoTable, "SECTION",    0,  CodeSECTION   );
  AddInstTable(PseudoTable, "SEGMENT",    0,  CodeSEGMENT   );
  AddInstTable(PseudoTable, "SHARED",     0,  CodeSHARED    );
  AddInstTable(PseudoTable, "STRUC",      0,  CodeSTRUCT    );
  AddInstTable(PseudoTable, "STRUCT",     0,  CodeSTRUCT    );
  AddInstTable(PseudoTable, "UNION",      1,  CodeSTRUCT    );
  AddInstTable(PseudoTable, "WARNING",    e_level_message, CodeMESSAGE );
  AddInstTable(PseudoTable, "=",          0,  CodeSETEQU    );
  AddInstTable(PseudoTable, ":=",         1,  CodeSETEQU    );

  /* NOTE: These will only be selected if the current target does
     NOT use the dot to separate an attribute part.  If it does,
     the oppart_leading_dot flag gets set and the appropriate
     rules kick in: */

  AddInstTable(PseudoTable, ".EQU",        0, CodeSETEQU );
  AddInstTable(PseudoTable, ".SET",        1, CodeSETEQU );
  AddInstTable(PseudoTable, ".SAVE",       0, CodeSAVE   );
  AddInstTable(PseudoTable, ".RESTORE",    0, CodeRESTORE);
  AddInstTable(PseudoTable, ".PAGE",       0, CodePAGE   );
  AddInstTable(PseudoTable, ".TITLE",      2, CodeString );
  AddInstTable(PseudoTable, ".END",        0, CodeEND    );

  ONOFFTable = CreateInstTable(47);
  AddONOFF("DOTTEDSTRUCTS", &DottedStructs, DottedStructsName, True);

  pseudo_inst_fnc_table = inst_fnc_table_create(103);
  inst_fnc_table_add(pseudo_inst_fnc_table, "SET", True, code_set_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "SAVE", 0, code_save_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "PAGE", 0, code_page_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "PAGESIZE", 0, code_pagesize_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "RESTORE", 0, code_restore_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "FORWARD", 0, code_forward_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "PUBLIC", 0, code_public_cond);
  inst_fnc_table_add(pseudo_inst_fnc_table, "GLOBAL", 0, code_global_cond);
}
