Top secrets sources NedoPC pentevo

Rev

Blame | Last modification | View Log | Download | RSS feed | ?url?

/* as.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
/*                                                                           */
/* AS-Portierung                                                             */
/*                                                                           */
/* Hauptmodul                                                                */
/*                                                                           */
/*****************************************************************************/

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

#include "version.h"
#include "be_le.h"
#include "bpemu.h"

#include "stdhandl.h"
#include "nls.h"
#include "nlmessages.h"
#include "as.rsc"
#ifdef _USE_MSH
# include "as.msh"
#endif
#include "ioerrs.h"
#include "strutil.h"
#include "stringlists.h"
#include "cmdarg.h"
#include "msg_level.h"
#include "asmitree.h"
#include "trees.h"
#include "chunks.h"
#include "console.h"
#include "asminclist.h"
#include "asmfnums.h"
#include "asmdef.h"
#include "cpulist.h"
#include "asmerr.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmmac.h"
#include "asmstructs.h"
#include "asmif.h"
#include "asmcode.h"
#include "asmlist.h"
#include "asmlabel.h"
#include "asmdebug.h"
#include "asmrelocs.h"
#include "literals.h"
#include "asmallg.h"
#include "onoff_common.h"
#include "codepseudo.h"
#include "as.h"

#include "codenone.h"
#include "code68k.h"
#include "code56k.h"
#include "code601.h"
#include "codepalm.h"
#include "codemcore.h"
#include "codexgate.h"
#include "code68.h"
#include "code6805.h"
#include "code6809.h"
#include "code6812.h"
#include "codes12z.h"
#include "code6816.h"
#include "code68rs08.h"
#include "codeh8_3.h"
#include "codeh8_5.h"
#include "code7000.h"
#include "codeko09.h"
#include "code65.h"
#include "codepps4.h"
#include "codeh16.h"
#include "code7700.h"
#include "codehmcs400.h"
#include "code4500.h"
#include "codem16.h"
#include "codem16c.h"
#include "codepdp11.h"
#include "codevax.h"
#include "code4004.h"
#include "code8008.h"
#include "code48.h"
#include "code51.h"
#include "code96.h"
#include "code85.h"
#include "code86.h"
#include "code960.h"
#include "code8x30x.h"
#include "code2650.h"
#include "codexa.h"
#include "codeavr.h"
#include "code29k.h"
#include "code166.h"
#include "codez80.h"
#include "codez8.h"
#include "codez8000.h"
#include "codekcpsm.h"
#include "codekcp3.h"
#include "codemic8.h"
#include "code96c141.h"
#include "code90c141.h"
#include "code87c800.h"
#include "code870c.h"
#include "code47c00.h"
#include "code97c241.h"
#include "code9331.h"
#include "code16c5x.h"
#include "code16c8x.h"
#include "code17c4x.h"
#include "codesx20.h"
#include "codepdk.h"
#include "codest6.h"
#include "codest7.h"
#include "codest9.h"
#include "code6804.h"
#include "code3201x.h"
#include "code3202x.h"
#include "code3203x.h"
#include "code3205x.h"
#include "code3254x.h"
#include "code3206x.h"
#include "code9900.h"
#include "codetms7.h"
#include "code370.h"
#include "codemsp.h"
#include "codetms1.h"
#include "codescmp.h"
#include "codeimp16.h"
#include "code807x.h"
#include "codecop4.h"
#include "codecop8.h"
#include "codesc14xxx.h"
#include "codens32k.h"
#include "codeace.h"
#include "codecp3f.h"
#include "codef8.h"
#include "code78c10.h"
#include "code75xx.h"
#include "code75k0.h"
#include "code78k0.h"
#include "code78k2.h"
#include "code78k3.h"
#include "code78k4.h"
#include "code7720.h"
#include "code77230.h"
#include "codev60.h"
#include "code53c8xx.h"
#include "codefmc8.h"
#include "codefmc16.h"
#include "codemn1610.h"
#include "codemn2610.h"
#include "codeol40.h"
#include "codeol50.h"
#include "code1802.h"
#include "codevector.h"
#include "codexcore.h"
#include "code1750.h"
#include "codekenbak.h"
#include "codecp1600.h"
#include "codenano.h"
#include "code6100.h"
#include "coderx.h"
#include "code61860.h"
#include "code62015.h"
/**          Code21xx};**/

static long StartTime, StopTime;
static Boolean GlobErrFlag;
static unsigned MacroNestLevel = 0;

/*=== Zeilen einlesen ======================================================*/


#if 0
# define dbgentry(str) printf("***enter %s\n", str);
# define dbgexit(str) printf("***exit %s\n", str);
#else
# define dbgentry(str) {}
# define dbgexit(str) {}
#endif

#define LEAVE goto func_exit

static void NULL_Restorer(PInputTag PInp)
{
  UNUSED(PInp);
}

static Boolean NULL_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  UNUSED(PInp);
  UNUSED(ActGNUErrors);

  if (DestSize)
    *dest = '\0';
  return False;
}

static Boolean INCLUDE_Processor(PInputTag PInp, as_dynstr_t *p_dest);

static PInputTag GenerateProcessor(void)
{
  PInputTag PInp = (PInputTag)malloc(sizeof(TInputTag));

  PInp->IsMacro = False;
  PInp->Next = NULL;
  PInp->First = True;
  PInp->OrigDoLst = DoLst;
  PInp->StartLine = CurrLine;
  PInp->ParCnt = 0; PInp->ParZ = 0;
  InitStringList(&(PInp->Params));
  PInp->LineCnt = PInp->ContLineCnt = 0; PInp->LineZ = 1;
  PInp->Lines = PInp->LineRun = NULL;
  StrCompMkTemp(&PInp->SpecName, PInp->SpecNameStr, sizeof(PInp->SpecNameStr));
  StrCompReset(&PInp->SpecName);
  PInp->AllArgs[0] = '\0';
  PInp->NumArgs[0] = '\0';
  PInp->IsEmpty = False;
  PInp->Buffer = NULL;
  PInp->Datei = NULL;
  PInp->IfLevel = SaveIFs();
  PInp->IncludeLevel = CurrIncludeLevel;
  PInp->Restorer = NULL_Restorer;
  PInp->GetPos = NULL_GetPos;
  PInp->Macro = NULL;
  PInp->SaveAttr[0] = '\0';
  PInp->SaveLabel[0] = '\0';
  PInp->GlobalSymbols = False;
  PInp->UsesNumArgs =
  PInp->UsesAllArgs = False;

  /* in case the input tag chain is empty, this must be the master file */

  PInp->FromFile = !FirstInputTag || (FirstInputTag->Processor == INCLUDE_Processor);

  return PInp;
}

static POutputTag GenerateOUTProcessor(SimpProc Processor, tErrorNum OpenErrMsg)
{
  POutputTag POut;

  POut = (POutputTag) malloc(sizeof(TOutputTag));
  POut->Processor = Processor;
  POut->NestLevel = 0;
  POut->Tag = NULL;
  POut->Mac = NULL;
  POut->ParamNames = NULL;
  POut->ParamDefVals = NULL;
  POut->PubSect = 0;
  POut->GlobSect = 0;
  POut->DoExport = False;
  POut->DoGlobCopy= False;
  POut->UsesNumArgs =
  POut->UsesAllArgs = False;
  *POut->GName = '\0';
  POut->OpenErrMsg = OpenErrMsg;

  return POut;
}

/*=========================================================================*/
/* Makroprozessor */

/*-------------------------------------------------------------------------*/
/* allgemein gebrauchte Subfunktionen */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* werden gebraucht, um festzustellen, ob innerhalb eines Makrorumpfes weitere
   Makroschachtelungen auftreten */


static Boolean MacroStart(void)
{
  return ((Memo("MACRO")) || (Memo("IRP")) || (Memo("IRPC")) || (Memo("REPT")) || (Memo("WHILE")));
}

static Boolean MacroEnd(void)
{
  if (Memo("ENDM"))
  {
    WasMACRO = True;
    return True;
  }
  else
    return False;
}

typedef void (*tMacroArgCallback)(Boolean CtrlArg, const tStrComp *pArg, void *pUser);

static void ProcessMacroArgs(tMacroArgCallback Callback, void *pUser)
{
  tStrComp *pArg;
  int l;

  for (pArg = ArgStr + 1; pArg <= ArgStr + ArgCnt; pArg++)
  {
    l = strlen(pArg->str.p_str);
    if ((l >= 2) && (pArg->str.p_str[0] == '{') && (pArg->str.p_str[l - 1] == '}'))
    {
      tStrComp Arg;

      StrCompRefRight(&Arg, pArg, 1);
      StrCompShorten(&Arg, 1);
      Callback(TRUE, &Arg, pUser);
    }
    else
    {
      Callback(FALSE, pArg, pUser);
    }
  }
}

/*-------------------------------------------------------------------------*/
/* Dieser Einleseprozessor dient nur dazu, eine fehlerhafte Makrodefinition
  bis zum Ende zu ueberlesen */


static void WaitENDM_Processor(void)
{
  POutputTag Tmp;

  if (MacroStart())
    FirstOutputTag->NestLevel++;
  else if (MacroEnd())
    FirstOutputTag->NestLevel--;
  if (FirstOutputTag->NestLevel <= -1)
  {
    Tmp = FirstOutputTag;
    FirstOutputTag = Tmp->Next;
    free(Tmp);
  }
}

static void AddWaitENDM_Processor(void)
{
  POutputTag Neu;

  Neu = GenerateOUTProcessor(WaitENDM_Processor, ErrNum_OpenMacro);
  Neu->Next = FirstOutputTag;
  FirstOutputTag = Neu;
}

/*-------------------------------------------------------------------------*/
/* normale Makros */

static void ComputeMacroStrings(PInputTag Tag)
{
  StringRecPtr Lauf;

  /* recompute # of params */

  if (Tag->UsesNumArgs)
    as_snprintf(Tag->NumArgs, sizeof(Tag->NumArgs), Integ32Format, Tag->ParCnt);

  /* recompute 'all string' parameter */

  if (Tag->UsesAllArgs)
  {
    Tag->AllArgs[0] = '\0';
    Lauf = Tag->Params;
    while (Lauf)
    {
      if (Tag->AllArgs[0] != '\0')
        strmaxcat(Tag->AllArgs, ",", STRINGSIZE);
      strmaxcat(Tag->AllArgs, Lauf->Content, STRINGSIZE);
      Lauf = Lauf->Next;
    }
  }
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Diese Routine leitet die Quellcodezeilen bei der Makrodefinition in den
   Makro-Record um */


static void MACRO_OutProcessor(void)
{
  POutputTag Tmp;
  int z;
  StringRecPtr l;
  PMacroRec GMacro;

  WasMACRO = True;

  /* write preprocessed output to file ? */

  if ((MacroOutput) && (FirstOutputTag->DoExport))
  {
    errno = 0;
    fprintf(MacroFile, "%s\n", OneLine.p_str);
    ChkIO(ErrNum_FileWriteError);
  }

  /* check for additional nested macros resp. end of definition */

  if (MacroStart())
    FirstOutputTag->NestLevel++;
  else if (MacroEnd())
    FirstOutputTag->NestLevel--;

  /* still lines to put into the macro body ? */

  if (FirstOutputTag->NestLevel != -1)
  {
    as_dynstr_t s;

    as_dynstr_ini_clone(&s, &OneLine);
    KillCtrl(s.p_str);

    /* compress into tokens */

    l = FirstOutputTag->ParamNames;
    for (z = 1; z <= FirstOutputTag->Mac->ParamCount; z++)
    {
      const char *p_param_name = GetStringListNext(&l);
      CompressLine(p_param_name ? p_param_name : "", z, &s, CaseSensitive);
    }

    /* reserved argument names are never case-sensitive */

    if (HasAttrs)
      CompressLine(AttrName, ArgCntMax + 1, &s, FALSE);
    if (CompressLine(ArgCName, ArgCntMax + 2, &s, FALSE) > 0)
      FirstOutputTag->UsesNumArgs = TRUE;
    if (CompressLine(AllArgName, ArgCntMax + 3, &s, FALSE) > 0)
      FirstOutputTag->UsesAllArgs = TRUE;
    if (FirstOutputTag->Mac->LocIntLabel)
      CompressLine(LabelName, ArgCntMax + 4, &s, FALSE);

    AddStringListLast(&(FirstOutputTag->Mac->FirstLine), s.p_str);
    as_dynstr_free(&s);
  }

  /* otherwise, finish definition */

  if (FirstOutputTag->NestLevel == -1)
  {
    if (IfAsm)
    {
      FirstOutputTag->Mac->UsesNumArgs = FirstOutputTag->UsesNumArgs;
      FirstOutputTag->Mac->UsesAllArgs = FirstOutputTag->UsesAllArgs;
      FirstOutputTag->Mac->ParamNames = FirstOutputTag->ParamNames;
      FirstOutputTag->ParamNames = NULL;
      FirstOutputTag->Mac->ParamDefVals = FirstOutputTag->ParamDefVals;
      FirstOutputTag->ParamDefVals = NULL;
      AddMacro(FirstOutputTag->Mac, FirstOutputTag->PubSect, True);
      if ((FirstOutputTag->DoGlobCopy) && (SectionStack))
      {
        GMacro = (PMacroRec) malloc(sizeof(MacroRec));
        GMacro->Name = as_strdup(FirstOutputTag->GName);
        GMacro->ParamCount = FirstOutputTag->Mac->ParamCount;
        GMacro->FirstLine = DuplicateStringList(FirstOutputTag->Mac->FirstLine);
        GMacro->ParamNames = DuplicateStringList(FirstOutputTag->Mac->ParamNames);
        GMacro->ParamDefVals = DuplicateStringList(FirstOutputTag->Mac->ParamDefVals);
        GMacro->UsesNumArgs = FirstOutputTag->Mac->UsesNumArgs;
        GMacro->UsesAllArgs = FirstOutputTag->Mac->UsesAllArgs;
        AddMacro(GMacro, FirstOutputTag->GlobSect, False);
      }
    }
    else
    {
      ClearMacroRec(&(FirstOutputTag->Mac), TRUE);
    }

    Tmp = FirstOutputTag;
    FirstOutputTag = Tmp->Next;
    ClearStringList(&(Tmp->ParamNames));
    ClearStringList(&(Tmp->ParamDefVals));
    free(Tmp);
  }
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Von hier her kommen bei einem Makroaufruf die expandierten Zeilen */

Boolean MACRO_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  StringRecPtr Lauf;
  int z;
  Boolean Result;

  Result = True;

  /* run to current line */

  Lauf = PInp->Lines;
  for (z = 1; z <= PInp->LineZ - 1; z++)
    Lauf = Lauf->Next;
  as_dynstr_copy_c_str(p_dest, Lauf->Content);

  /* process parameters */

  Lauf = PInp->Params;
  for (z = 1; z <= PInp->ParCnt; z++)
  {
    ExpandLine(Lauf->Content, z, p_dest);
    Lauf = Lauf->Next;
  }

  /* process special parameters */

  if (HasAttrs)
    ExpandLine(PInp->SaveAttr, ArgCntMax + 1, p_dest);
  if (PInp->UsesNumArgs)
    ExpandLine(PInp->NumArgs, ArgCntMax + 2, p_dest);
  if (PInp->UsesAllArgs)
    ExpandLine(PInp->AllArgs, ArgCntMax + 3, p_dest);
  if (PInp->Macro->LocIntLabel)
    ExpandLine(PInp->SaveLabel, ArgCntMax + 4, p_dest);

  CurrLine = PInp->StartLine;
  InMacroFlag = True;

  /* before the first line, start a new local symbol space */

  if ((PInp->LineZ == 1) && (!PInp->GlobalSymbols))
    PushLocHandle(GetLocHandle());

  /* signal the end of the macro */

  if (++(PInp->LineZ) > PInp->LineCnt)
    Result = False;

  return Result;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Initialisierung des Makro-Einleseprozesses */

static Boolean ReadMacro_SearchArg(const char *pTest, const char *pComp, Boolean *pErg)
{
  if (!as_strcasecmp(pTest, pComp))
  {
    *pErg = True;
    return True;
  }
  else if ((strlen(pTest) > 2) && (!as_strncasecmp(pTest, "NO", 2)) && (!as_strcasecmp(pTest + 2, pComp)))
  {
    *pErg = False;
    return True;
  }
  else
    return False;
}

static Boolean ReadMacro_SearchSect(char *Test_O, const char *Comp, Boolean *Erg, LongInt *Section)
{
  char *p;
  String Test, Sect;

  strmaxcpy(Test, Test_O, STRINGSIZE); KillBlanks(Test);
  p = strchr(Test, ':');
  if (!p)
    *Sect = '\0';
  else
  {
    strmaxcpy(Sect, p + 1, STRINGSIZE);
    *p = '\0';
  }
  if ((strlen(Test) > 2) && (!as_strncasecmp(Test, "NO", 2)) && (!as_strcasecmp(Test + 2, Comp)))
  {
    *Erg = False;
    return True;
  }
  else if (!as_strcasecmp(Test, Comp))
  {
    tStrComp TmpComp;

    *Erg = True;
    StrCompMkTemp(&TmpComp, Sect, sizeof(Sect));
    return (IdentifySection(&TmpComp, Section));
  }
  else
    return False;
}

typedef struct
{
  String PList;
  POutputTag pOutputTag;
  tLstMacroExpMod LstMacroExpMod;
  Boolean DoPublic, DoIntLabel, GlobalSymbols;
  Boolean ErrFlag;
  int ParamCount;
} tReadMacroContext;

static void ExpandPList(String PList, const char *pArg, Boolean CtrlArg)
{
  if (!*PList)
    strmaxcat(PList, ",", STRINGSIZE);
  if (CtrlArg)
    strmaxcat(PList, "{", STRINGSIZE);
  strmaxcat(PList, pArg, STRINGSIZE);
  if (CtrlArg)
    strmaxcat(PList, "}", STRINGSIZE);
}

static void ProcessMACROArgs(Boolean CtrlArg, const tStrComp *pArg, void *pUser)
{
  tReadMacroContext *pContext = (tReadMacroContext*)pUser;

  if (CtrlArg)
  {
    Boolean DoMacExp;

    if (ReadMacro_SearchArg(pArg->str.p_str, "EXPORT", &(pContext->pOutputTag->DoExport)));
    else if (ReadMacro_SearchArg(pArg->str.p_str, "GLOBALSYMBOLS", &pContext->GlobalSymbols));
    else if (ReadMacro_SearchArg(pArg->str.p_str, "EXPAND", &DoMacExp))
    {
      if (!AddLstMacroExpMod(&pContext->LstMacroExpMod, DoMacExp, eLstMacroExpAll))
        WrStrErrorPos(ErrNum_TooManyMacExpMod, pArg);
      ExpandPList(pContext->PList, pArg->str.p_str, CtrlArg);
    }
    else if (ReadMacro_SearchArg(pArg->str.p_str, "EXPIF", &DoMacExp))
    {
      if (!AddLstMacroExpMod(&pContext->LstMacroExpMod, DoMacExp, eLstMacroExpIf))
        WrStrErrorPos(ErrNum_TooManyMacExpMod, pArg);
      ExpandPList(pContext->PList, pArg->str.p_str, CtrlArg);
    }
    else if (ReadMacro_SearchArg(pArg->str.p_str, "EXPMACRO", &DoMacExp))
    {
      if (!AddLstMacroExpMod(&pContext->LstMacroExpMod, DoMacExp, eLstMacroExpMacro))
        WrStrErrorPos(ErrNum_TooManyMacExpMod, pArg);
      ExpandPList(pContext->PList, pArg->str.p_str, CtrlArg);
    }
    else if (ReadMacro_SearchArg(pArg->str.p_str, "EXPREST", &DoMacExp))
    {
      if (!AddLstMacroExpMod(&pContext->LstMacroExpMod, DoMacExp, eLstMacroExpRest))
        WrStrErrorPos(ErrNum_TooManyMacExpMod, pArg);
      ExpandPList(pContext->PList, pArg->str.p_str, CtrlArg);
    }
    else if (ReadMacro_SearchArg(pArg->str.p_str, "INTLABEL", &pContext->DoIntLabel))
    {
      ExpandPList(pContext->PList, pArg->str.p_str, CtrlArg);
    }
    else if (ReadMacro_SearchSect(pArg->str.p_str, "GLOBAL", &(pContext->pOutputTag->DoGlobCopy), &(pContext->pOutputTag->GlobSect)));
    else if (ReadMacro_SearchSect(pArg->str.p_str, "PUBLIC", &pContext->DoPublic, &(pContext->pOutputTag->PubSect)));
    else
    {
      WrStrErrorPos(ErrNum_UnknownMacArg, pArg);
      pContext->ErrFlag = True;
    }
  }
  else
  {
    char *pDefault;
    tStrComp Arg;

    StrCompRefRight(&Arg, pArg, 0);
    ExpandPList(pContext->PList, Arg.str.p_str, CtrlArg);
    pDefault = QuotPos(Arg.str.p_str, '=');
    if (pDefault)
    {
      Arg.Pos.Len = pDefault - Arg.str.p_str;
      *pDefault++ = '\0';
      KillPostBlanksStrComp(&Arg);
      KillPrefBlanksStrComp(&Arg);
    }
    if (!ChkMacSymbName(Arg.str.p_str))
    {
      WrStrErrorPos(ErrNum_InvSymName, &Arg);
      pContext->ErrFlag = True;
    }
    if (!CaseSensitive)
      UpString(Arg.str.p_str);
    AddStringListLast(&(pContext->pOutputTag->ParamNames), Arg.str.p_str);
    AddStringListLast(&(pContext->pOutputTag->ParamDefVals), pDefault ? pDefault : "");
    pContext->ParamCount++;
  }
}

static void ReadMacro(void)
{
  PSaveSection RunSection;
  PMacroRec OneMacro;
  tReadMacroContext Context;
  LongInt HSect;
  String macro_name_buf;
  tStrComp macro_name;
  const tStrComp *p_macro_name;

  WasMACRO = True;

  CodeLen = 0;
  Context.ErrFlag = False;

  /* Makronamen pruefen */
  /* Definition nur im ersten Pass */

  StrCompMkTemp(&macro_name, macro_name_buf, sizeof(macro_name_buf));
  if (PassNo != 1)
  {
    Context.ErrFlag = True;
    p_macro_name = &LabPart;
  }
  else
  {
    p_macro_name = ExpandStrSymbol(&macro_name, &LabPart, False);
    if (!p_macro_name)
    {
      Context.ErrFlag = True;
      p_macro_name = &LabPart;
    }
    else if (!ChkSymbName(p_macro_name->str.p_str))
    {
      WrStrErrorPos(ErrNum_InvSymName, &LabPart);
      Context.ErrFlag = True;
    }
  }

  /* create tag */

  Context.pOutputTag = GenerateOUTProcessor(MACRO_OutProcessor, ErrNum_OpenMacro);
  Context.pOutputTag->Next = FirstOutputTag;

  /* check arguments, sort out control directives */

  Context.LstMacroExpMod = LstMacroExpModDefault;
  Context.DoPublic = False;
  Context.DoIntLabel = False;
  Context.GlobalSymbols = False;
  *Context.PList = '\0';
  Context.ParamCount = 0;
  ProcessMacroArgs(ProcessMACROArgs, &Context);

  /* contradicting macro expansion? */

  if (!ChkLstMacroExpMod(&Context.LstMacroExpMod))
  {
    WrError(ErrNum_ConflictingMacExpMod);
    Context.ErrFlag = True;
  }

  /* Abbruch bei Fehler */

  if (Context.ErrFlag)
  {
    ClearStringList(&(Context.pOutputTag->ParamNames));
    ClearStringList(&(Context.pOutputTag->ParamDefVals));
    free(Context.pOutputTag);
    AddWaitENDM_Processor();
    return;
  }

  /* Bei Globalisierung Namen des Extramakros ermitteln */

  if (Context.pOutputTag->DoGlobCopy)
  {
    strmaxcpy(Context.pOutputTag->GName, MacroName, STRINGSIZE);
    RunSection = SectionStack;
    HSect = MomSectionHandle;
    while ((HSect != Context.pOutputTag->GlobSect) && (RunSection != NULL))
    {
      strmaxprep(Context.pOutputTag->GName, "_", STRINGSIZE);
      strmaxprep(Context.pOutputTag->GName, GetSectionName(HSect), STRINGSIZE);
      HSect = RunSection->Handle;
      RunSection = RunSection->Next;
    }
  }
  if (!Context.DoPublic)
    Context.pOutputTag->PubSect = MomSectionHandle;

  /* chain in */

  OneMacro = (PMacroRec) calloc(1, sizeof(MacroRec));
  OneMacro->FirstLine =
  OneMacro->ParamNames =
  OneMacro->ParamDefVals = NULL;
  Context.pOutputTag->Mac = OneMacro;

  if ((MacroOutput) && (Context.pOutputTag->DoExport))
  {
    errno = 0;
    fprintf(MacroFile, "%s MACRO %s\n",
            Context.pOutputTag->DoGlobCopy ? Context.pOutputTag->GName : MacroName,
            Context.PList);
    ChkIO(ErrNum_FileWriteError);
  }

  OneMacro->UseCounter = 0;
  OneMacro->Name = as_strdup(p_macro_name->str.p_str);
  OneMacro->ParamCount = Context.ParamCount;
  OneMacro->FirstLine = NULL;
  OneMacro->LstMacroExpMod = Context.LstMacroExpMod;
  OneMacro->LocIntLabel = Context.DoIntLabel;
  OneMacro->GlobalSymbols = Context.GlobalSymbols;

  FirstOutputTag = Context.pOutputTag;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Beendigung der Expansion eines Makros */

static void MACRO_Cleanup(PInputTag PInp)
{
  ClearStringList(&(PInp->Params));
}

static Boolean MACRO_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  UNUSED(ActGNUErrors);
  as_snprintf(dest, DestSize, "%s(%lu) ", PInp->SpecName.str.p_str, (unsigned long)(PInp->LineZ - 1));
  return False;
}

static void MACRO_Restorer(PInputTag PInp)
{
  /* discard the local symbol space */

  if (!PInp->GlobalSymbols)
    PopLocHandle();

  /* undo the recursion counter by one */

  if ((PInp->Macro) && (PInp->Macro->UseCounter > 0))
    PInp->Macro->UseCounter--;

  /* restore list flag */

  DoLst = PInp->OrigDoLst;

  /* decrement macro nesting counter only if this actually was a macro */

  if (PInp->Processor == MACRO_Processor)
    MacroNestLevel--;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Dies initialisiert eine Makroexpansion */

static void ExpandMacro(PMacroRec OneMacro)
{
  int z1, z2;
  StringRecPtr Lauf, pDefault, pParamName, pArg;
  PInputTag Tag = NULL;
  Boolean NamedArgs;
  char *p;

  CodeLen = 0;

  if ((NestMax > 0) && (OneMacro->UseCounter > NestMax)) WrError(ErrNum_RekMacro);
  else
  {
    OneMacro->UseCounter++;

    /* 1. Tag erzeugen */

    Tag = GenerateProcessor();
    Tag->Processor = MACRO_Processor;
    Tag->Restorer  = MACRO_Restorer;
    Tag->Cleanup   = MACRO_Cleanup;
    Tag->GetPos    = MACRO_GetPos;
    Tag->Macro     = OneMacro;
    Tag->GlobalSymbols = OneMacro->GlobalSymbols;
    Tag->UsesNumArgs = OneMacro->UsesNumArgs;
    Tag->UsesAllArgs = OneMacro->UsesAllArgs;
    strmaxcpy(Tag->SpecName.str.p_str, OneMacro->Name, STRINGSIZE);
    strmaxcpy(Tag->SaveAttr, AttrPart.str.p_str, STRINGSIZE);
    if (OneMacro->LocIntLabel)
      strmaxcpy(Tag->SaveLabel, LabPart.str.p_str, STRINGSIZE);
    Tag->IsMacro   = True;

    /* 2. Store special parameters - in the original form.
          Omit this if they aren't used at all in the macro's body. */


    Tag->NumArgs[0] = '\0';
    if (Tag->UsesNumArgs)
      as_snprintf(Tag->NumArgs, sizeof(Tag->NumArgs), "%d", ArgCnt);
    Tag->AllArgs[0] = '\0';
    if (Tag->UsesAllArgs)
    {
      for (z1 = 1; z1 <= ArgCnt; z1++)
      {
        if (z1 != 1) strmaxcat(Tag->AllArgs, ",", STRINGSIZE);
        strmaxcat(Tag->AllArgs, ArgStr[z1].str.p_str, STRINGSIZE);
      }
    }
    Tag->ParCnt = OneMacro->ParamCount;

    /* 3. generate argument list */

    /* 3a. initialize with empty defaults - order is irrelevant at this point: */

    for (z1 = OneMacro->ParamCount; z1 >= 1; z1--)
      AddStringListFirst(&(Tag->Params), NULL);

    /* 3b. walk over given arguments */

    NamedArgs = False;
    for (z1 = 1; z1 <= ArgCnt; z1++)
    {
      if (!CaseSensitive) UpString(ArgStr[z1].str.p_str);

      /* explicit name given? */

      p = QuotPos(ArgStr[z1].str.p_str, '=');

      /* if parameter name given... */

      if (p)
      {
        /* split it off */

        *p++ = '\0';
        KillPostBlanksStrComp(&ArgStr[z1]);
        KillPrefBlanks(p);

        /* search parameter by name */

        for (pParamName = OneMacro->ParamNames, pArg = Tag->Params;
             pParamName; pParamName = pParamName->Next, pArg = pArg->Next)
          if (!strcmp(ArgStr[z1].str.p_str, pParamName->Content))
          {
            if (pArg->Content)
            {
              WrXError(ErrNum_MacArgRedef, pParamName->Content);
              free(pArg->Content);
            }
            pArg->Content = as_strdup(p);
            break;
          }
        if (!pParamName)
          WrStrErrorPos(ErrNum_UndefKeyArg, &ArgStr[z1]);

        /* set flag that no unnamed args are any longer allowed */

        NamedArgs = True;
      }

      /* do not mix unnamed with named arguments: */

      else if (NamedArgs)
        WrError(ErrNum_NoPosArg);

      /* empty positional parameters mean using defaults - insert non-empty args here: */

      else if ((z1 <= OneMacro->ParamCount) && (strlen(ArgStr[z1].str.p_str) > 0))
      {
        pArg = Tag->Params;
        pParamName = OneMacro->ParamNames;
        for (z2 = 0; z2 < z1 - 1; z2++)
        {
          pParamName = pParamName->Next;
          pArg = pArg->Next;
        }
        if (pArg->Content)
        {
          WrXError(ErrNum_MacArgRedef, pParamName->Content);
          free(pArg->Content);
        }
        pArg->Content = as_strdup(ArgStr[z1].str.p_str);
      }

      /* excess unnamed arguments: append at end of list */

      else if (z1 > OneMacro->ParamCount)
        AddStringListLast(&(Tag->Params), ArgStr[z1].str.p_str);
    }

    /* 3c. fill in defaults */

    for (pParamName = OneMacro->ParamNames, pArg = Tag->Params, pDefault = OneMacro->ParamDefVals;
             pParamName; pParamName = pParamName->Next, pArg = pArg->Next, pDefault = pDefault->Next)
      if (!pArg->Content)
        pArg->Content = as_strdup(pDefault->Content);

    /* 4. Zeilenliste anhaengen */

    Tag->Lines = OneMacro->FirstLine;
    Tag->IsEmpty = !OneMacro->FirstLine;
    Lauf = OneMacro->FirstLine;
    while (Lauf)
    {
      Tag->LineCnt++;
      Lauf = Lauf->Next;
    }
  }

  /* 5. anhaengen */

  if (Tag)
  {
    if (IfAsm)
    {
      /* override has higher prio, so apply as second */

      NextDoLst = ApplyLstMacroExpMod(DoLst, &OneMacro->LstMacroExpMod);
      NextDoLst = ApplyLstMacroExpMod(NextDoLst, &LstMacroExpModOverride);
      Tag->Next = FirstInputTag;
      FirstInputTag = Tag;
      MacroNestLevel++;
    }
    else
    {
      ClearStringList(&(Tag->Params)); free(Tag);
    }
  }
}

/*-------------------------------------------------------------------------*/
/* vorzeitiger Abbruch eines Makros */

static void ExpandEXITM(void)
{
  WasMACRO = True;

  if (!ChkArgCnt(0, 0));
  else if (!FirstInputTag) WrError(ErrNum_EXITMOutsideMacro);
  else if (!FirstInputTag->IsMacro) WrError(ErrNum_EXITMOutsideMacro);
  else if (IfAsm)
  {
    FirstInputTag->Cleanup(FirstInputTag);
    RestoreIFs(FirstInputTag->IfLevel);
    FirstInputTag->IsEmpty = True;
  }
}

/*-------------------------------------------------------------------------*/
/* discard first argument */

static void ExpandSHIFT(void)
{
  PInputTag RunTag;

  WasMACRO = True;

  if (!ChkArgCnt(0, 0));
  else if (!FirstInputTag) WrError(ErrNum_EXITMOutsideMacro);
  else if (!FirstInputTag->IsMacro) WrError(ErrNum_EXITMOutsideMacro);
  else if (IfAsm)
  {
    for (RunTag = FirstInputTag; RunTag; RunTag = RunTag->Next)
      if (RunTag->Processor == MACRO_Processor)
        break;

    if (RunTag && RunTag->Params)
    {
      char *p_arg = MoveAndCutStringListFirst(&RunTag->Params);
      if (p_arg)
        free(p_arg);
      RunTag->ParCnt--;
      ComputeMacroStrings(RunTag);
    }
  }
}

/*-------------------------------------------------------------------------*/
/*--- IRP (was das bei MASM auch immer heissen mag...)
      Ach ja: Individual Repeat! Danke Bernhard, jetzt hab'
      ich's gerafft! -----------------------*/


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Diese Routine liefert bei der Expansion eines IRP-Statements die expan-
  dierten Zeilen */


Boolean IRP_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  StringRecPtr Lauf;
  int z;
  Boolean Result;

  Result = True;

  /* increment line counter only if contents came from a true file */

  CurrLine = PInp->StartLine;
  if (PInp->FromFile)
    CurrLine += PInp->LineZ;

  /* first line? Then open new symbol space and reset line pointer */

  if (PInp->LineZ == 1)
  {
    if (!PInp->GlobalSymbols)
    {
      if (!PInp->First) PopLocHandle();
      PushLocHandle(GetLocHandle());
    }
    PInp->First = False;
    PInp->LineRun = PInp->Lines;
  }

  /* extract line */

  as_dynstr_copy_c_str(p_dest, PInp->LineRun->Content);
  PInp->LineRun = PInp->LineRun->Next;

  /* expand iteration parameter */

  Lauf = PInp->Params; for (z = 1; z <= PInp->ParZ - 1; z++)
    Lauf = Lauf->Next;
  ExpandLine(Lauf->Content, 1, p_dest);

  /* end of body? then reset to line 1 and exit if this was the last iteration */

  if (++(PInp->LineZ) > PInp->LineCnt)
  {
    PInp->LineZ = 1;
    if (++(PInp->ParZ) > PInp->ParCnt)
      Result = False;
  }

  return Result;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Aufraeumroutine IRP/IRPC */

static void IRP_Cleanup(PInputTag PInp)
{
  StringRecPtr Lauf;

  /* letzten Parameter sichern, wird evtl. noch fuer GetPos gebraucht!
     ... SaveAttr ist aber frei */

  if (PInp->Processor == IRP_Processor)
  {
    for (Lauf = PInp->Params; Lauf->Next; Lauf = Lauf->Next);
    strmaxcpy(PInp->SaveAttr, Lauf->Content, STRINGSIZE);
  }

  ClearStringList(&(PInp->Lines));
  ClearStringList(&(PInp->Params));
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Posisionsangabe im IRP(C) fuer Fehlermeldungen */

static Boolean IRP_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  int z, ParZ = PInp->ParZ, LineZ = PInp->LineZ;
  const char *IRPType;
  char *IRPVal, tmp[20];

  UNUSED(ActGNUErrors);

  /* LineZ/ParZ already hopped to next line - step one back: */

  if (--LineZ <= 0)
  {
    LineZ = PInp->LineCnt;
    ParZ--;
  }

  if (PInp->Processor == IRP_Processor)
  {
    IRPType = "IRP";
    if (*PInp->SaveAttr != '\0')
      IRPVal = PInp->SaveAttr;
    else
    {
      StringRecPtr Lauf = PInp->Params;

      for (z = 1; z <= ParZ - 1; z++)
        Lauf = Lauf->Next;
      IRPVal = Lauf->Content;
    }
  }
  else
  {
    IRPType = "IRPC";
    as_snprintf(tmp, sizeof(tmp), "'%c'", PInp->SpecName.str.p_str[ParZ - 1]);
    IRPVal = tmp;
  }

  as_snprintf(dest, DestSize, "%s:%s(%lu) ", IRPType, IRPVal, (unsigned long)LineZ);

  return False;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Diese Routine sammelt waehrend der Definition eines IRP(C)-Statements die
  Quellzeilen ein */


static void IRP_OutProcessor(void)
{
  POutputTag Tmp;

  WasMACRO = True;

  /* Schachtelungen mitzaehlen */

  if (MacroStart())
    FirstOutputTag->NestLevel++;
  else if (MacroEnd())
    FirstOutputTag->NestLevel--;

  /* falls noch nicht zuende, weiterzaehlen */

  if (FirstOutputTag->NestLevel > -1)
  {
    as_dynstr_t s;
    StringRecPtr Dummy;
    const char *p_first_param = GetStringListFirst(FirstOutputTag->ParamNames, &Dummy);

    as_dynstr_ini_clone(&s, &OneLine); KillCtrl(s.p_str);
    CompressLine(p_first_param ? p_first_param : "", 1, &s, CaseSensitive);
    AddStringListLast(&(FirstOutputTag->Tag->Lines), s.p_str);
    as_dynstr_free(&s);
    FirstOutputTag->Tag->LineCnt++;
  }

  /* alles zusammen? Dann umhaengen */

  if (FirstOutputTag->NestLevel == -1)
  {
    Tmp = FirstOutputTag;
    FirstOutputTag = FirstOutputTag->Next;
    Tmp->Tag->IsEmpty = !Tmp->Tag->Lines;
    if (IfAsm)
    {
      NextDoLst = ApplyLstMacroExpMod(DoLst, &LstMacroExpModDefault);
      NextDoLst = ApplyLstMacroExpMod(NextDoLst, &LstMacroExpModOverride);
      Tmp->Tag->Next = FirstInputTag;
      FirstInputTag = Tmp->Tag;
    }
    else
    {
      ClearStringList(&(Tmp->Tag->Lines));
      ClearStringList(&(Tmp->Tag->Params));
      free(Tmp->Tag);
    }
    ClearStringList(&(Tmp->ParamNames));
    free(Tmp);
  }
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Initialisierung der IRP-Bearbeitung */

typedef struct
{
  Boolean ErrFlag;
  Boolean GlobalSymbols;
  int ArgCnt;
  POutputTag pOutputTag;
  StringList Params;
} tExpandIRPContext;

static void ProcessIRPArgs(Boolean CtrlArg, const tStrComp *pArg, void *pUser)
{
  tExpandIRPContext *pContext = (tExpandIRPContext*)pUser;

  if (CtrlArg)
  {
    if (ReadMacro_SearchArg(pArg->str.p_str, "GLOBALSYMBOLS", &pContext->GlobalSymbols));
    else
    {
      WrStrErrorPos(ErrNum_UnknownMacArg, pArg);
      pContext->ErrFlag = True;
    }
  }
  else
  {
    /* differentiate placeholder & arguments */

    if (0 == pContext->ArgCnt)
    {
      if (!ChkMacSymbName(pArg->str.p_str))
      {
        WrStrErrorPos(ErrNum_InvSymName, pArg);
        pContext->ErrFlag = True;
      }
      else
        AddStringListFirst(&(pContext->pOutputTag->ParamNames), pArg->str.p_str);
    }
    else
    {
      if (!CaseSensitive)
        UpString(pArg->str.p_str);
      AddStringListLast(&(pContext->Params), pArg->str.p_str);
    }
    pContext->ArgCnt++;
  }
}

static Boolean ExpandIRP(void)
{
  PInputTag Tag;
  tExpandIRPContext Context;

  WasMACRO = True;

  /* 0. terminate if conditional assembly bites */

  if (!IfAsm)
  {
    AddWaitENDM_Processor();
    return True;
  }

  /* 1. Parameter pruefen */

  Context.ErrFlag = False;
  Context.GlobalSymbols = False;
  Context.ArgCnt = 0;
  Context.Params = NULL;

  Context.pOutputTag = GenerateOUTProcessor(IRP_OutProcessor, ErrNum_OpenIRP);
  Context.pOutputTag->Next      = FirstOutputTag;
  ProcessMacroArgs(ProcessIRPArgs, &Context);

  /* at least parameter & one arg */

  if (!ChkArgCntExt(Context.ArgCnt, 2, ArgCntMax))
    Context.ErrFlag = True;
  if (Context.ErrFlag)
  {
    ClearStringList(&(Context.pOutputTag->ParamNames));
    ClearStringList(&(Context.pOutputTag->ParamDefVals));
    ClearStringList(&(Context.Params));
    free(Context.pOutputTag);
    AddWaitENDM_Processor();
    return False;
  }

  /* 2. Tag erzeugen */

  Tag = GenerateProcessor();
  Tag->ParCnt    = Context.ArgCnt - 1;
  Tag->Params    = Context.Params;
  Tag->Processor = IRP_Processor;
  Tag->Restorer  = MACRO_Restorer;
  Tag->Cleanup   = IRP_Cleanup;
  Tag->GetPos    = IRP_GetPos;
  Tag->GlobalSymbols = Context.GlobalSymbols;
  Tag->ParZ      = 1;
  Tag->IsMacro   = True;
  *Tag->SaveAttr = '\0';
  Context.pOutputTag->Tag = Tag;

  /* 4. einbetten */

  FirstOutputTag = Context.pOutputTag;

  return True;
}

/*--- IRPC: dito fuer Zeichen eines Strings ---------------------------------*/

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Diese Routine liefert bei der Expansion eines IRPC-Statements die expan-
  dierten Zeilen */


Boolean IRPC_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  Boolean Result;
  char tmp[5];

  Result = True;

  /* increment line counter only if contents came from a true file */

  CurrLine = PInp->StartLine;
  if (PInp->FromFile)
    CurrLine += PInp->LineZ;

  /* first line? Then open new symbol space and reset line pointer */

  if (PInp->LineZ == 1)
  {
    if (!PInp->GlobalSymbols)
    {
      if (!PInp->First) PopLocHandle();
      PushLocHandle(GetLocHandle());
    }
    PInp->First = False;
    PInp->LineRun = PInp->Lines;
  }

  /* extract line */

  as_dynstr_copy_c_str(p_dest, PInp->LineRun->Content);
  PInp->LineRun = PInp->LineRun->Next;

  /* extract iteration parameter */

  *tmp = PInp->SpecName.str.p_str[PInp->ParZ - 1];
  tmp[1] = '\0';
  ExpandLine(tmp, 1, p_dest);

  /* end of body? then reset to line 1 and exit if this was the last iteration */

  if (++(PInp->LineZ) > PInp->LineCnt)
  {
    PInp->LineZ = 1;
    if (++(PInp->ParZ) > PInp->ParCnt)
      Result = False;
  }

  return Result;
}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* Initialisierung der IRPC-Bearbeitung */

typedef struct
{
  Boolean ErrFlag;
  Boolean GlobalSymbols;
  int ArgCnt;
  POutputTag pOutputTag;
  String ParameterStr;
  tStrComp Parameter;
} tExpandIRPCContext;

static void ProcessIRPCArgs(Boolean CtrlArg, const tStrComp *pArg, void *pUser)
{
  tExpandIRPCContext *pContext = (tExpandIRPCContext*)pUser;

  if (CtrlArg)
  {
    if (ReadMacro_SearchArg(pArg->str.p_str, "GLOBALSYMBOLS", &pContext->GlobalSymbols));
    else
    {
      WrStrErrorPos(ErrNum_UnknownMacArg, pArg);
      pContext->ErrFlag = True;
    }
  }
  else
  {
    if (0 == pContext->ArgCnt)
    {
      if (!ChkMacSymbName(pArg->str.p_str))
      {
        WrStrErrorPos(ErrNum_InvSymName, pArg);
        pContext->ErrFlag = True;
      }
      else
        AddStringListFirst(&(pContext->pOutputTag->ParamNames), pArg->str.p_str);
    }
    else
    {
      Boolean OK;

      EvalStrStringExpression(pArg, &OK, pContext->Parameter.str.p_str);
      pContext->Parameter.Pos = pArg->Pos;
      if (!OK)
        pContext->ErrFlag = True;
    }
    pContext->ArgCnt++;
  }
}

static Boolean ExpandIRPC(void)
{
  PInputTag Tag;
  tExpandIRPCContext Context;

  WasMACRO = True;

  /* 0. terminate if conditinal assembly bites */

  if (!IfAsm)
  {
    AddWaitENDM_Processor();
    return True;
  }

  /* 1.Parameter pruefen */

  Context.ErrFlag = False;
  Context.GlobalSymbols = False;
  Context.ArgCnt = 0;
  StrCompMkTemp(&Context.Parameter, Context.ParameterStr, sizeof(Context.ParameterStr));
  StrCompReset(&Context.Parameter);

  Context.pOutputTag = GenerateOUTProcessor(IRP_OutProcessor, ErrNum_OpenIRPC);
  Context.pOutputTag->Next = FirstOutputTag;
  ProcessMacroArgs(ProcessIRPCArgs, &Context);

  /* parameter & string */

  if (!ChkArgCntExt(Context.ArgCnt, 2, ArgCntMax))
    Context.ErrFlag = True;
  if (Context.ErrFlag)
  {
    ClearStringList(&(Context.pOutputTag->ParamNames));
    AddWaitENDM_Processor();
    return False;
  }

  /* 2. Tag erzeugen */

  Tag = GenerateProcessor();
  Tag->ParCnt    = strlen(Context.Parameter.str.p_str);
  Tag->Processor = IRPC_Processor;
  Tag->Restorer  = MACRO_Restorer;
  Tag->Cleanup   = IRP_Cleanup;
  Tag->GetPos    = IRP_GetPos;
  Tag->GlobalSymbols = Context.GlobalSymbols;
  Tag->ParZ      = 1;
  Tag->IsMacro   = True;
  *Tag->SaveAttr = '\0';
  StrCompCopy(&Tag->SpecName, &Context.Parameter);

  /* 4. einbetten */

  Context.pOutputTag->Tag = Tag;
  FirstOutputTag = Context.pOutputTag;

  return True;
}

/*--- Repetition -----------------------------------------------------------*/

static void REPT_Cleanup(PInputTag PInp)
{
  ClearStringList(&(PInp->Lines));
}

static Boolean REPT_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  int z1 = PInp->ParZ, z2 = PInp->LineZ;

  UNUSED(ActGNUErrors);

  if (--z2 <= 0)
  {
    z2 = PInp->LineCnt;
    z1--;
  }
  as_snprintf(dest, DestSize, "REPT %lu(%lu)", (unsigned long)z1, (unsigned long)z2);
  return False;
}

Boolean REPT_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  Boolean Result;

  Result = True;

  /* increment line counter only if contents came from a true file */

  CurrLine = PInp->StartLine;
  if (PInp->FromFile)
    CurrLine += PInp->LineZ;

  /* first line? Then open new symbol space and reset line pointer */

  if (PInp->LineZ == 1)
  {
    if (!PInp->GlobalSymbols)
    {
      if (!PInp->First) PopLocHandle();
      PushLocHandle(GetLocHandle());
    }
    PInp->First = False;
    PInp->LineRun = PInp->Lines;
  }

  /* extract line */

  as_dynstr_copy_c_str(p_dest, PInp->LineRun->Content);
  PInp->LineRun = PInp->LineRun->Next;

  /* last line of body? Then increment count and stop if last iteration */

  if ((++PInp->LineZ) > PInp->LineCnt)
  {
    PInp->LineZ = 1;
    if ((++PInp->ParZ) > PInp->ParCnt)
      Result = False;
  }

  return Result;
}

static void REPT_OutProcessor(void)
{
  POutputTag Tmp;

  WasMACRO = True;

  /* Schachtelungen mitzaehlen */

  if (MacroStart())
    FirstOutputTag->NestLevel++;
  else if (MacroEnd())
    FirstOutputTag->NestLevel--;

  /* falls noch nicht zuende, weiterzaehlen */

  if (FirstOutputTag->NestLevel > -1)
  {
    AddStringListLast(&(FirstOutputTag->Tag->Lines), OneLine.p_str);
    FirstOutputTag->Tag->LineCnt++;
  }

  /* alles zusammen? Dann umhaengen */

  if (FirstOutputTag->NestLevel == -1)
  {
    Tmp = FirstOutputTag;
    FirstOutputTag = FirstOutputTag->Next;
    Tmp->Tag->IsEmpty = !Tmp->Tag->Lines;
    if ((IfAsm) && (Tmp->Tag->ParCnt > 0))
    {
      NextDoLst = ApplyLstMacroExpMod(DoLst, &LstMacroExpModDefault);
      NextDoLst = ApplyLstMacroExpMod(NextDoLst, &LstMacroExpModOverride);
      Tmp->Tag->Next = FirstInputTag;
      FirstInputTag = Tmp->Tag;
    }
    else
    {
      ClearStringList(&(Tmp->Tag->Lines));
      free(Tmp->Tag);
    }
    free(Tmp);
  }
}

typedef struct
{
  Boolean ErrFlag;
  Boolean GlobalSymbols;
  int ArgCnt;
  LongInt ReptCount;
} tExpandREPTContext;

static void ProcessREPTArgs(Boolean CtrlArg, const tStrComp *pArg, void *pUser)
{
  tExpandREPTContext *pContext = (tExpandREPTContext*)pUser;

  if (CtrlArg)
  {
    if (ReadMacro_SearchArg(pArg->str.p_str, "GLOBALSYMBOLS", &pContext->GlobalSymbols));
    else
    {
      WrStrErrorPos(ErrNum_UnknownMacArg, pArg);
      pContext->ErrFlag = True;
    }
  }
  else
  {
    Boolean ValOK;
    tSymbolFlags SymbolFlags;

    pContext->ReptCount = EvalStrIntExpressionWithFlags(pArg, Int32, &ValOK, &SymbolFlags);
    if (mFirstPassUnknown(SymbolFlags))
      WrStrErrorPos(ErrNum_FirstPassCalc, pArg);
    if (!ValOK || mFirstPassUnknown(SymbolFlags))
      pContext->ErrFlag = True;
    pContext->ArgCnt++;
  }
}

static Boolean ExpandREPT(void)
{
  PInputTag Tag;
  POutputTag Neu;
  tExpandREPTContext Context;

  WasMACRO = True;

  /* 0. skip everything when conditional assembly is off */

  if (!IfAsm)
  {
    AddWaitENDM_Processor();
    return True;
  }

  /* 1. Repetitionszahl ermitteln */

  Context.GlobalSymbols = False;
  Context.ReptCount = 0;
  Context.ErrFlag = False;
  Context.ArgCnt = 0;
  ProcessMacroArgs(ProcessREPTArgs, &Context);

  /* rept count must be present only once */

  if (!ChkArgCntExt(Context.ArgCnt, 1, 1))
    Context.ErrFlag = True;
  if (Context.ErrFlag)
  {
    AddWaitENDM_Processor();
    return False;
  }

  /* 2. Tag erzeugen */

  Tag = GenerateProcessor();
  Tag->ParCnt    = Context.ReptCount;
  Tag->Processor = REPT_Processor;
  Tag->Restorer  = MACRO_Restorer;
  Tag->Cleanup   = REPT_Cleanup;
  Tag->GetPos    = REPT_GetPos;
  Tag->GlobalSymbols = Context.GlobalSymbols;
  Tag->IsMacro   = True;
  Tag->ParZ      = 1;

  /* 3. einbetten */

  Neu = GenerateOUTProcessor(REPT_OutProcessor, ErrNum_OpenREPT);
  Neu->Next      = FirstOutputTag;
  Neu->Tag       = Tag;
  FirstOutputTag = Neu;

  return True;
}

/*- bedingte Wiederholung -------------------------------------------------------*/

static void WHILE_Cleanup(PInputTag PInp)
{
  ClearStringList(&(PInp->Lines));
}

static Boolean WHILE_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  int z1 = PInp->ParZ, z2 = PInp->LineZ;

  UNUSED(ActGNUErrors);

  if (--z2 <= 0)
  {
    z2 = PInp->LineCnt;
    z1--;
  }
  as_snprintf(dest, DestSize, "WHILE %lu/%lu", (unsigned long)z1, (unsigned long)z2);
  return False;
}

Boolean WHILE_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  int z;
  Boolean OK, Result;

  /* increment line counter only if this came from a true file */

  CurrLine = PInp->StartLine;
  if (PInp->FromFile)
    CurrLine += PInp->LineZ;

  /* if this is the first line of the loop body, open a new handle
     for macro-local symbols and drop the old one if this was not the
     first pass through the body. */


  if (PInp->LineZ == 1)
  {
    if (!PInp->GlobalSymbols)
    {
      if (!PInp->First)
        PopLocHandle();
      PushLocHandle(GetLocHandle());
    }
    PInp->First = False;
    PInp->LineRun = PInp->Lines;
  }

  /* evaluate condition before first line */

  if (PInp->LineZ == 1)
  {
    z = EvalStrIntExpression(&PInp->SpecName, Int32, &OK);
    Result = (OK && (z != 0));
  }
  else
    Result = True;

  if (Result)
  {
    /* get line of body */

    as_dynstr_copy_c_str(p_dest, PInp->LineRun->Content);
    PInp->LineRun = PInp->LineRun->Next;

    /* in case this is the last line of the body, reset counters */

    if ((++PInp->LineZ) > PInp->LineCnt)
    {
      PInp->LineZ = 1;
      PInp->ParZ++;
    }
  }

  /* nasty last line... */

  else
    *p_dest->p_str = '\0';

  return Result;
}

static void WHILE_OutProcessor(void)
{
  POutputTag Tmp;
  Boolean OK;
  tSymbolFlags SymbolFlags;
  LongInt Erg;

  WasMACRO = True;

  /* Schachtelungen mitzaehlen */

  if (MacroStart())
    FirstOutputTag->NestLevel++;
  else if (MacroEnd())
    FirstOutputTag->NestLevel--;

  /* falls noch nicht zuende, weiterzaehlen */

  if (FirstOutputTag->NestLevel > -1)
  {
    AddStringListLast(&(FirstOutputTag->Tag->Lines), OneLine.p_str);
    FirstOutputTag->Tag->LineCnt++;
  }

  /* alles zusammen? Dann umhaengen */

  if (FirstOutputTag->NestLevel == -1)
  {
    Tmp = FirstOutputTag;
    FirstOutputTag = FirstOutputTag->Next;
    Tmp->Tag->IsEmpty = !Tmp->Tag->Lines;
    Erg = EvalStrIntExpressionWithFlags(&Tmp->Tag->SpecName, Int32, &OK, &SymbolFlags);
    if (mFirstPassUnknown(SymbolFlags))
    {
      WrError(ErrNum_FirstPassCalc);
      OK = False;
    }
    OK = (OK && (Erg != 0));
    if (IfAsm && OK)
    {
      NextDoLst = ApplyLstMacroExpMod(DoLst, &LstMacroExpModDefault);
      NextDoLst = ApplyLstMacroExpMod(NextDoLst, &LstMacroExpModOverride);
      Tmp->Tag->Next = FirstInputTag;
      FirstInputTag = Tmp->Tag;
    }
    else
    {
      ClearStringList(&(Tmp->Tag->Lines));
      free(Tmp->Tag);
    }
    free(Tmp);
  }
}

typedef struct
{
  Boolean ErrFlag;
  Boolean GlobalSymbols;
  int ArgCnt;
  String SpecNameStr;
  tStrComp SpecName;
} tExpandWHILEContext;

static void ProcessWHILEArgs(Boolean CtrlArg, const tStrComp *pArg, void *pUser)
{
  tExpandWHILEContext *pContext = (tExpandWHILEContext*)pUser;

  if (CtrlArg)
  {
    if (ReadMacro_SearchArg(pArg->str.p_str, "GLOBALSYMBOLS", &pContext->GlobalSymbols));
    else
    {
      WrStrErrorPos(ErrNum_UnknownMacArg, pArg);
      pContext->ErrFlag = True;
    }
  }
  else
  {
    StrCompCopy(&pContext->SpecName, pArg);
    pContext->ArgCnt++;
  }
}

static Boolean ExpandWHILE(void)
{
  PInputTag Tag;
  POutputTag Neu;
  tExpandWHILEContext Context;

  WasMACRO = True;

  /* 0. turned off ? */

  if (!IfAsm)
  {
    AddWaitENDM_Processor();
    return True;
  }

  /* 1. Bedingung ermitteln */

  Context.GlobalSymbols = False;
  Context.ErrFlag = False;
  Context.ArgCnt = 0;
  StrCompMkTemp(&Context.SpecName, Context.SpecNameStr, sizeof(Context.SpecNameStr));
  StrCompReset(&Context.SpecName);
  ProcessMacroArgs(ProcessWHILEArgs, &Context);

  /* condition must be present only once */

  if (!ChkArgCntExt(Context.ArgCnt, 1, 1))
    Context.ErrFlag = True;
  if (Context.ErrFlag)
  {
    AddWaitENDM_Processor();
    return False;
  }

  /* 2. Tag erzeugen */

  Tag = GenerateProcessor();
  Tag->Processor = WHILE_Processor;
  Tag->Restorer  = MACRO_Restorer;
  Tag->Cleanup   = WHILE_Cleanup;
  Tag->GetPos    = WHILE_GetPos;
  Tag->GlobalSymbols = Context.GlobalSymbols;
  Tag->IsMacro   = True;
  Tag->ParZ      = 1;
  StrCompCopy(&Tag->SpecName, &Context.SpecName);

  /* 3. einbetten */

  Neu = GenerateOUTProcessor(WHILE_OutProcessor, ErrNum_OpenWHILE);
  Neu->Next      = FirstOutputTag;
  Neu->Tag       = Tag;
  FirstOutputTag = Neu;

  return True;
}

/*--------------------------------------------------------------------------*/
/* Einziehen von Include-Files */

static void INCLUDE_Cleanup(PInputTag PInp)
{
  fclose(PInp->Datei);
  free(PInp->Buffer);

  /* if last line in file was continued, do not forget to add up
     continuation lines: */


  LineSum += PInp->LineZ + PInp->ContLineCnt;
  if ((*LstName != '\0') && (msg_level >= e_msg_level_normal))
  {
    String Tmp;

    as_snprintf(Tmp, sizeof(Tmp), "%s(%lu)", NamePart(CurrFileName), (unsigned long)CurrLine);
    WrConsoleLine(Tmp, True);
    fflush(stdout);
  }
  if (MakeIncludeList)
    PopInclude();
  CurrIncludeLevel = PInp->IncludeLevel;
}

static Boolean INCLUDE_GetPos(PInputTag PInp, char *dest, size_t DestSize, Boolean ActGNUErrors)
{
  UNUSED(PInp);

  as_snprintf(dest, DestSize, ActGNUErrors ? "%s:%lu" : "%s(%lu) ", NamePart(PInp->SpecName.str.p_str), (unsigned long)PInp->LineZ);
  return !GNUErrors;
}

Boolean INCLUDE_Processor(PInputTag PInp, as_dynstr_t *p_dest)
{
  Boolean Result;
  int Count = 1;

  /* add up # of continuation lines from previous source line */

  if (PInp->ContLineCnt)
  {
    CurrLine = (PInp->LineZ += PInp->ContLineCnt);
    PInp->ContLineCnt = 0;
  }

  Result = True;

  if (feof(PInp->Datei))
    *p_dest->p_str = '\0';
  else
  {
    Count = ReadLnCont(PInp->Datei, p_dest);
    /**ChkIO(ErrNum_FileReadError);**/
  }

  /* Even if we had continuation lines, only increment line counter
     by one at this place so the first line's # is the number of the
     concatenated line: */


  if (Count > 0)
  {
    PInp->LineZ++;
    CurrLine = PInp->LineZ;
    PInp->ContLineCnt = Count - 1;
  }
  if (feof(PInp->Datei))
    Result = False;

  return Result;
}

static void INCLUDE_Restorer(PInputTag PInp)
{
  CurrLine = PInp->StartLine;
  strmaxcpy(CurrFileName, PInp->SaveAttr, STRINGSIZE);
  IncDepth--;
}

/*!------------------------------------------------------------------------
 * \fn     ExpandINCLUDE_Core(const tStrComp *pArg, Boolean SearchPath)
 * \brief  The actual core code to open a source file for assembly
 * \param  pArg file's name to open
 * \param  SearchPath searhc file in include path?
 * ------------------------------------------------------------------------ */


static void ExpandINCLUDE_Core(const tStrComp *pArg, Boolean SearchPath)
{
  tStrComp FNameArg;
  String FNameArgStr;
  PInputTag Tag;

  StrCompMkTemp(&FNameArg, FNameArgStr, sizeof(FNameArgStr));
  INCLUDE_SearchCore(&FNameArg, pArg, SearchPath);

  /* Tag erzeugen */

  Tag = GenerateProcessor();
  Tag->Processor = INCLUDE_Processor;
  Tag->Restorer  = INCLUDE_Restorer;
  Tag->Cleanup   = INCLUDE_Cleanup;
  Tag->GetPos    = INCLUDE_GetPos;
  Tag->Buffer    = (void *) malloc(BufferArraySize);

  /* Sicherung alter Daten */

  Tag->StartLine = CurrLine;
  strmaxcpy(Tag->SpecName.str.p_str, FNameArg.str.p_str, STRINGSIZE);
  LineCompReset(&Tag->SpecName.Pos);
  strmaxcpy(Tag->SaveAttr, CurrFileName, STRINGSIZE);

  /* Datei oeffnen */

#ifdef __CYGWIN32__
  DeCygwinPath(FNameArg.str.p_str);
#endif
  Tag->Datei = fopen(FNameArg.str.p_str, "r");
  if (!Tag->Datei) ChkStrIO(ErrNum_OpeningFile, pArg);
  setvbuf(Tag->Datei, (char*)Tag->Buffer, _IOFBF, BufferArraySize);

  /* neu besetzen */

  strmaxcpy(CurrFileName, FNameArg.str.p_str, STRINGSIZE);
  Tag->LineZ = 0;
  AddFile(FNameArg.str.p_str);
  PushInclude(FNameArg.str.p_str);
  if (++CurrIncludeLevel > MaxIncludeLevel)
    WrStrErrorPos(ErrNum_MaxIncLevelExceeded, pArg);

  /* einhaengen */

  Tag->Next = FirstInputTag; FirstInputTag = Tag;
}

/*!------------------------------------------------------------------------
 * \fn     ExpandINCLUDE(void)
 * \brief  Handle INCLUDE statement
 * ------------------------------------------------------------------------ */


static void ExpandINCLUDE(void)
{
  if (!IfAsm)
    return;

  if (!ChkArgCnt(1, 1))
    return;

  ExpandINCLUDE_Core(&ArgStr[1], True);
  NextIncDepth++;
}

/*=========================================================================*/
/* Einlieferung von Zeilen */

static void GetNextLine(as_dynstr_t *pLine)
{
  PInputTag HTag;

  InMacroFlag = False;

  while (FirstInputTag && FirstInputTag->IsEmpty)
  {
    FirstInputTag->Cleanup(FirstInputTag);
    FirstInputTag->Restorer(FirstInputTag);
    HTag = FirstInputTag;
    FirstInputTag = HTag->Next;
    free(HTag);
  }

  if (!FirstInputTag)
  {
    *pLine->p_str = '\0';
    return;
  }

  if (!FirstInputTag->Processor(FirstInputTag, pLine))
  {
    FirstInputTag->IsEmpty = True;
  }

  MacLineSum++;
}

typedef struct
{
  char *pStr;
  size_t AllocLen;
} tAllocStr;

static void InitStr(tAllocStr *pStr)
{
  pStr->pStr = NULL;
  pStr->AllocLen = 0;
}

static void ReallocStr(tAllocStr *pStr, unsigned NewAllocLen)
{
  if (NewAllocLen > pStr->AllocLen)
  {
    char *pNewStr;

    /* round up, and implicitly avoid allocating 4/8 bytes (sizeof pointer)
       so size check in as_vsnprcatf() does not generate false positive: */


    NewAllocLen = (NewAllocLen + 15) &~15;
    pNewStr = pStr->AllocLen
            ? (char*)realloc(pStr->pStr, NewAllocLen)
            : (char*)malloc(NewAllocLen);

    if (pNewStr)
    {
      pStr->pStr = pNewStr;
      pStr->pStr[pStr->AllocLen] = '\0';
      pStr->AllocLen = NewAllocLen;
    }
  }
}

char *GetErrorPos(void)
{
  String ActPos;
  PInputTag RunTag;
  tAllocStr Str;
  int CurrStrLen, NewLen;
  Boolean Last;

  InitStr(&Str);
  CurrStrLen = 0;

  /* no file has yet been opened: */

  if (!FirstInputTag)
  {
    const char FixedName[] = "INTERNAL";

    ReallocStr(&Str, strlen(FixedName) + 1);
    strmaxcat(Str.pStr, FixedName, Str.AllocLen);
  }

  /* for GNU error message style: */

  else if (GNUErrors)
  {
    PInputTag pInnerTag = NULL;
    const char *pMsg;

    /* we only honor the include positions.  First, print the upper include layers... */

    for (RunTag = FirstInputTag; RunTag; RunTag = RunTag->Next)
      if (RunTag->GetPos == INCLUDE_GetPos)
      {
        if (!pInnerTag)
          pInnerTag = RunTag;
        else
        {
          Last = RunTag->GetPos(RunTag, ActPos, sizeof(ActPos), GNUErrors);
          if (!Str.AllocLen)
          {
            pMsg = getmessage(Num_GNUErrorMsg1);
            NewLen = strlen(pMsg) + 1 + strlen(ActPos) + 1;
            ReallocStr(&Str, NewLen);
            as_snprintf(Str.pStr, Str.AllocLen, "%s %s", pMsg, ActPos);
            CurrStrLen = NewLen;
          }
          else
          {
            pMsg = getmessage(Num_GNUErrorMsgN);
            NewLen = CurrStrLen + 2 + strlen(pMsg) + 1 + strlen(ActPos) + 1;
            ReallocStr(&Str, NewLen);
            as_snprcatf(Str.pStr, Str.AllocLen, ",\n%s %s", pMsg, ActPos);
            CurrStrLen = NewLen;
          }
        }
      }

    /* ...append something... */

    if (CurrStrLen > 0)
    {
      NewLen = CurrStrLen + 3;

      ReallocStr(&Str, NewLen);
      as_snprcatf(Str.pStr, Str.AllocLen, ":\n");
      CurrStrLen = NewLen;
    }

    /* ...then the innermost one */

    if (pInnerTag)
    {
      pInnerTag->GetPos(pInnerTag, ActPos, sizeof(ActPos), GNUErrors);
      NewLen = CurrStrLen + strlen(ActPos) + 1;
      ReallocStr(&Str, NewLen);
      as_snprcatf(Str.pStr, Str.AllocLen, "%s", ActPos);
      CurrStrLen = NewLen;
    }
  }

  /* otherwise the standard AS position generator: */

  else
  {
    int ThisLen;

    for (RunTag = FirstInputTag; RunTag; RunTag = RunTag->Next)
    {
      Last = RunTag->GetPos(RunTag, ActPos, sizeof(ActPos), GNUErrors);
      ThisLen = strlen(ActPos);
      ReallocStr(&Str, NewLen = CurrStrLen + ThisLen + 1);
      strmaxprep(Str.pStr, ActPos, Str.AllocLen);
      CurrStrLen = NewLen;
      if (Last)
        break;
    }
  }

  return Str.pStr;
}

static Boolean InputEnd(void)
{
  PInputTag Lauf;

  Lauf = FirstInputTag;
  while (Lauf)
  {
    if (!Lauf->IsEmpty)
      return False;
    Lauf = Lauf->Next;
  }

  return True;
}

/*=== Eine Quelldatei ( Haupt-oder Includedatei ) bearbeiten ===============*/

/*--- aus der zerlegten Zeile Code erzeugen --------------------------------*/

void WriteCode(void)
{
  unsigned z;

  for (z = 0; z < StopfZahl; z++)
  {
    switch (ActListGran)
    {
      case 4:
        DAsmCode[CodeLen >> 2] = NOPCode;
        break;
      case 2:
        WAsmCode[CodeLen >> 1] = NOPCode;
        break;
      case 1:
        BAsmCode[CodeLen] = NOPCode;
        break;
    }
    CodeLen += ActListGran/Granularity();
  }

  if ((ActPC != StructSeg) && (!ChkPC(PCs[ActPC] + CodeLen - 1)) && (CodeLen != 0))
  {
    WrError(ErrNum_AdrOverflow);
    CodeLen = 0;
  }
  else
  {
    LargeWord NewPC = PCs[ActPC] + CodeLen;

    if ((!DontPrint) && (ActPC != StructSeg) && (CodeLen > 0))
      BookKeeping();
    if (ActPC == StructSeg)
    {
      if ((CodeLen != 0) && (!DontPrint)) WrError(ErrNum_NotInStruct);
      if (StructStack->StructRec->IsUnion)
      {
        BumpStructLength(StructStack->StructRec, CodeLen);
        CodeLen = 0;
        NewPC = 0;
      }
    }
    else if (CodeOutput)
    {
      PCsUsed[ActPC] = True;
      if (DontPrint)
        NewRecord(PCs[ActPC] + CodeLen);
      else
        WriteBytes();
    }
    PCs[ActPC] = NewPC;
  }
}

static void Produce_Code(void)
{
  PMacroRec OneMacro;
  PStructRec OneStruct;
  Boolean SearchMacros, Found, IsMacro = False, IsStruct = False, ResetLastLabel = True;
  tStrComp non_upper_case_op_part;
  String non_upper_case_op_part_buf;
  const tStrComp *p_search_op_part;

  ActListGran = ListGran();
  WasIF = WasMACRO = False;

  /* Makrosuche unterdruecken ? */

  /* We need the OpPart also in a variant not converted to all-uppercase,
     since structure and macro names may be case sensitive: */


  StrCompMkTemp(&non_upper_case_op_part, non_upper_case_op_part_buf, sizeof(non_upper_case_op_part_buf));
  if (*OpPart.str.p_str == '!')
  {
    SearchMacros = False;
    StrCompCutLeft(&OpPart, 1);
    StrCompCopy(&non_upper_case_op_part, &OpPart);
  }
  else
  {
    const tStrComp *p_lop_part;

    SearchMacros = True;
    p_lop_part = ExpandStrSymbol(&non_upper_case_op_part, &OpPart, False);
    if (p_lop_part && (p_lop_part != &OpPart))
      as_dynstr_copy(&OpPart.str, &p_lop_part->str);
  }
  NLS_UpString(OpPart.str.p_str);
  p_search_op_part = CaseSensitive ? &non_upper_case_op_part : &OpPart;

  /* Prozessor eingehaengt ? */

  if (FirstOutputTag)
  {
    FirstOutputTag->Processor();
    return;
  }

  /* otherwise generate code: check for macro/structs here */

  IsMacro = (SearchMacros) && (FoundMacro(&OneMacro, p_search_op_part));
  if (IsMacro)
    WasMACRO = True;
  if (!IsMacro)
    IsStruct = FoundStruct(&OneStruct, p_search_op_part->str.p_str);

  /* no longer at an address right after a BSR? */

  if (EProgCounter() != AfterBSRAddr)
    AfterBSRAddr = 0;

  /* evtl. voranstehendes Label ablegen */

  if (IfAsm && (!IsMacro || !OneMacro->LocIntLabel))
  {
    if (LabelPresent())
      LabelHandle(&LabPart, EProgCounter(), False);
  }

  Found = False;
  switch (*OpPart.str.p_str)
  {
    case 'I':
      /* Makroliste ? */
      Found = True;
      if (Memo("IRP")) ResetLastLabel = !ExpandIRP();
      else if (Memo("IRPC")) ResetLastLabel = !ExpandIRPC();
      else Found = False;
      break;
    case 'R':
      /* Repetition ? */
      Found = True;
      if (Memo("REPT")) ResetLastLabel = !ExpandREPT();
      else Found = False;
      break;
    case 'W':
      /* bedingte Repetition ? */
      Found = True;
      if (Memo("WHILE")) ResetLastLabel = !ExpandWHILE();
      else Found = False;
      break;
  }

  /* bedingte Assemblierung ? */

  if (!Found)
    WasIF = Found = CodeIFs();

  if (!Found)
    switch (*OpPart.str.p_str)
    {
      case 'M':
        /* Makrodefinition ? */
        Found = True;
        if (Memo("MACRO")) ReadMacro();
        else Found = False;
        break;
      case 'E':
        /* Abbruch Makroexpansion ? */
        Found = True;
        if (Memo("EXITM")) ExpandEXITM();
        else Found = False;
        break;
      case 'S':
        /* shift macro arguments ? */
        Found = True;
        if (memo_shift_pseudo() || (ShiftIsOccupied && Memo("SHFT"))) ExpandSHIFT();
        else Found = False;
        break;
      case 'I':
        /* Includefile? */
        Found = True;
        if (Memo("INCLUDE"))
          ExpandINCLUDE();
        else
          Found = False;
        break;
    }

  if (Found);

  /* Makroaufruf ? */

  else if (IsMacro)
  {
    ResetLastLabel = False;
    if (IfAsm)
    {
      ExpandMacro(OneMacro);
      if ((MacroNestLevel > 1) && (MacroNestLevel < 100))
        as_snprintf(ListLine, STRINGSIZE, "%*s(MACRO-%u)", MacroNestLevel - 1, "", MacroNestLevel);
      else
        strmaxcpy(ListLine, "(MACRO)", STRINGSIZE);

      /* Macro call itself must not appear in expanded output.  However, a label
         in the same line that is not consumed by the macro must.  In this case,
         dump the source line with the OpPart (macro's name) muted out. */


      if (MacProOutput && (LabPart.Pos.StartCol >= 0) && !OneMacro->LocIntLabel)
        PrintOneLineMuted(MacProFile, OneLine.p_str, &OpPart.Pos, &ArgPart.Pos);
    }
  }

  else
  {
    StopfZahl = 0;
    CodeLen = 0;
    DontPrint = False;

#ifdef PROFILE_MEMO
    NumMemo = 0;
#endif

    if (IfAsm)
    {
      /* structure declaration ? */

      if (IsStruct)
      {
        ExpandStruct(OneStruct, p_search_op_part->str.p_str);
        strmaxcpy(ListLine, OneStruct->IsUnion ? "(UNION)" : "(STRUCT)", STRINGSIZE);
      }
      else
      {
        AttrPartOpSize[0] = AttrPartOpSize[1] = eSymbolSizeUnknown;
        if (DecodeAttrPart ? DecodeAttrPart() : True)
        {
          if (!CodeGlobalPseudo())
          MakeCode();
        }
      }
      if (MacProOutput && ((*OpPart.str.p_str != '\0') || (*LabPart.str.p_str != '\0') || (*CommPart.str.p_str != '\0')))
      {
        errno = 0;
        fprintf(MacProFile, "%s\n", OneLine.p_str);
        ChkIO(ErrNum_ListWrError);
      }
    }

#ifdef PROFILE_MEMO
    NumMemoSum += NumMemo;
    NumMemoCnt++;
#endif

    WriteCode();
  }

  /* reset memory about previous label if it is a non-empty instruction */

  if (*OpPart.str.p_str && ResetLastLabel)
    LabelReset();

  /* dies ueberprueft implizit, ob von der letzten Eval...-Operation noch
     externe Referenzen liegengeblieben sind. */


  SetRelocs(NULL);
}

/*--- Zeile in Listing zerteilen -------------------------------------------*/

static void adjust_copy_comp(tStrComp *p_comp, const char *p_src, size_t newsz)
{
  if (newsz + 1 > p_comp->str.capacity)
    as_dynstr_realloc(&p_comp->str, as_dynstr_roundup_len(newsz));
  p_comp->Pos.Len = strmemcpy(p_comp->str.p_str, p_comp->str.capacity, p_src, newsz);
}

static void SplitLine(void)
{
  const char *pRun, *pEnd, *pPos;

  Retracted = False;

  /* run preprocessor */

  ExpandDefines(OneLine.p_str);
  pRun = OneLine.p_str;
  pEnd = pRun + strlen(pRun);

  /* If comment is present, ignore everything after it: */

  pPos = QuotSMultPosQualify(pRun, pCommentLeadIn, QualifyQuote);
  if (pPos)
  {
    adjust_copy_comp(&CommPart, pPos, pEnd - pPos);
    CommPart.Pos.StartCol = pPos - OneLine.p_str;
    pEnd = pPos;
  }
  else
    StrCompReset(&CommPart);

  /* Non-blank character in first column is always label: */

  if ((pRun < pEnd) && *pRun && !as_isspace(*pRun))
  {
    for (pPos = pRun; pPos < pEnd; pPos++)
      if (as_isspace(*pPos) || (*pPos == ':'))
        break;
    LabPart.Pos.StartCol = pRun - OneLine.p_str;
    if (pPos >= pEnd)
    {
      LabPart.Pos.Len = strmemcpy(LabPart.str.p_str, STRINGSIZE, pRun, pEnd - pRun);
      pRun = pEnd;
    }
    else
    {
      LabPart.Pos.Len = strmemcpy(LabPart.str.p_str, STRINGSIZE, pRun, pPos - pRun);
      pRun = pPos + 1;
    }
    if ((LabPart.Pos.Len > 0) && (LabPart.str.p_str[LabPart.Pos.Len - 1] == ':')) /* needed? */
      LabPart.str.p_str[--LabPart.Pos.Len] = '\0';
  }
  else
    StrCompReset(&LabPart);

  /* Opcode & Argument trennen */

  while (True)
  {
    for (; (pRun < pEnd) && as_isspace(*pRun); pRun++);
    for (pPos = pRun; (pPos < pEnd) && !as_isspace(*pPos); pPos++);

    /* If potential OpPart starts with argument divider,
       OpPart is empty and rest of line is all-arguments: */


    if (strchr(DivideChars, *pRun))
    {
      StrCompReset(&OpPart);
      adjust_copy_comp(&ArgPart, pRun, pEnd - pRun);
      ArgPart.Pos.StartCol = pRun - OneLine.p_str;
    }
    else
    {
      /* copy out OpPart */

      OpPart.Pos.StartCol = pRun - OneLine.p_str;
      OpPart.Pos.Len = strmemcpy(OpPart.str.p_str, OpPart.str.capacity, pRun, pPos - pRun);

      /* continue after OpPart separator */

      pRun = (pPos < pEnd) ? pPos + 1 : pEnd;

      /* Falls noch kein Label da war, kann es auch ein Label sein */

      if ((*LabPart.str.p_str == '\0') && OpPart.Pos.Len && (OpPart.str.p_str[OpPart.Pos.Len - 1] == ':'))
      {
        OpPart.str.p_str[--OpPart.Pos.Len] = '\0';
        StrCompCopy(&LabPart, &OpPart);
        continue; /* -> retry finding opcode */
      }

      /* save remainder to ArgPart */

      adjust_copy_comp(&ArgPart, pRun, pEnd - pRun);
      ArgPart.Pos.StartCol = pRun - OneLine.p_str;
    }
    break;
  }

  ArgCnt = 0;

  /* trailing separator on OpPart means we have to push in another empty argument */

  if (OpPart.Pos.Len && strchr(DivideChars, OpPart.str.p_str[OpPart.Pos.Len - 1]))
  {
    const char EmptyArg[] = "";

    OpPart.str.p_str[--OpPart.Pos.Len] = '\0';
    AppendArg(strlen(EmptyArg));
    strcpy(ArgStr[ArgCnt].str.p_str, EmptyArg);
    ArgStr[ArgCnt].Pos = ArgPart.Pos;
  }

  /* Attribut abspalten */

  oppart_leading_dot = False;
  if (HasAttrs)
  {
    const char *pActAttrChar;
    char *pAttrPos, *pActAttrPos;
    int Tries = 0;

again:
    pAttrPos = NULL; AttrSplit = ' ';
    for (pActAttrChar = AttrChars; *pActAttrChar; pActAttrChar++)
    {
      pActAttrPos = strchr(OpPart.str.p_str, *pActAttrChar);
      if (pActAttrPos && ((!pAttrPos) || (pActAttrPos < pAttrPos)))
        pAttrPos = pActAttrPos;
    }
    if (pAttrPos)
    {
      AttrSplit = (*pAttrPos);
      AttrPart.Pos.StartCol = OpPart.Pos.StartCol + (pAttrPos + 1 - OpPart.str.p_str);
      AttrPart.Pos.Len = strmemcpy(AttrPart.str.p_str, STRINGSIZE, pAttrPos + 1, strlen(pAttrPos + 1));
      *pAttrPos = '\0';
      OpPart.Pos.Len = pAttrPos - OpPart.str.p_str;

      /* The dot-prefixed OpPart may itself contain an attribute (.instr.attr).  So reiterate
         splitting off attribute, but only once ;-) */


      if ((*OpPart.str.p_str == '\0') && (*AttrPart.str.p_str != '\0'))
      {
        StrCompCopy(&OpPart, &AttrPart);
        StrCompReset(&AttrPart);
        if (!Tries && (AttrSplit == '.'))
          oppart_leading_dot = True;
        if (++Tries < 2)
          goto again;
      }
    }
    else
      StrCompReset(&AttrPart);
  }
  else
    StrCompReset(&AttrPart);

  KillPostBlanksStrComp(&ArgPart);

  /* Argumente zerteilen: */

  if (*ArgPart.str.p_str)
  {
    const char *pDivPos, *pActDiv, *pActDivPos;

    pRun = ArgPart.str.p_str;
    pEnd = pRun + strlen(pRun);
    pActDivPos = NULL;

    /* A separator found in the previous iteration forces another argument,
       even if it will be empty because the separator is right at the end: */


    while ((pRun < pEnd) || pActDivPos)
    {
      while (*pRun && as_isspace(*pRun))
        pRun++;
#if 0 /* TODO: should work, but doesn't yet */
      pDivPos = QuotMultPosFixup(pRun, DivideChars, NULL);
      if (!pDivPos)
        pDivPos = pEnd;
#endif
      pDivPos = pEnd;
      for (pActDiv = DivideChars; *pActDiv; pActDiv++)
      {
        pActDivPos = QuotPosQualify(pRun, *pActDiv, QualifyQuote);
        if (pActDivPos && (pActDivPos < pDivPos))
          pDivPos = pActDivPos;
      }
      if (ArgCnt >= ArgCntMax)
      {
        WrError(ErrNum_TooManyArgs);
        break;
      }
      AppendArg(pDivPos - pRun);
      adjust_copy_comp(&ArgStr[ArgCnt], pRun, pDivPos - pRun);
      ArgStr[ArgCnt].Pos.StartCol = ArgPart.Pos.StartCol + (pRun - ArgPart.str.p_str);
      KillPostBlanksStrComp(&ArgStr[ArgCnt]);
      pRun = (pDivPos < pEnd) ? pDivPos + 1 : pEnd;
    }
  }
}

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

static void ProcessFile(char *pFileName)
{
  long NxtTime, ListTime;
  char *Run;
  tStrComp FileArg;

  dbgentry("ProcessFile");

  *OneLine.p_str = *CurrFileName = '\0';
  StrCompMkTemp(&FileArg, pFileName, 0);
  ExpandINCLUDE_Core(&FileArg, False);

  ListTime = GTime();

  while (!InputEnd() && !ENDOccured)
  {
    /* Zeile lesen */

    GetNextLine(&OneLine);

    /* Ergebnisfelder vorinitialisieren */

    DontPrint = False;
    CodeLen = 0;
    *ListLine = '\0';

    NextDoLst = DoLst;
    NextIncDepth = IncDepth;

    for (Run = OneLine.p_str; *Run != '\0'; Run++)
      if (!as_isspace(*Run))
        break;
    if (*Run == '#')
      Preprocess();
    else
    {
      SplitLine();
      Produce_Code();
    }

    MakeList(OneLine.p_str);
    DoLst = NextDoLst;
    IncDepth = NextIncDepth;
    if (MaxIncDepth < IncDepth)
      MaxIncDepth = IncDepth;

    /* Zeilenzaehler */

    if (msg_level >= e_msg_level_normal)
    {
      NxtTime = GTime();
      if (((!ListToStdout) || ((ListMask&1) == 0)) && (DTime(ListTime, NxtTime) > 50))
      {
        String Num;
        PInputTag p_input_tag;

        /* search innermost file currently being read, and request its position */

        for (p_input_tag = FirstInputTag; p_input_tag; p_input_tag = p_input_tag->Next)
          if (p_input_tag->Processor == INCLUDE_Processor)
            break;
        p_input_tag->GetPos(p_input_tag, Num, sizeof(Num), False);
        WrConsoleLine(Num, False);
        fflush(stdout);
        ListTime = NxtTime;
      }
    }

    /* bei Ende Makroprozessor ausraeumen
       OK - das ist eine Hauruckmethode... */


    if (ENDOccured)
      while (FirstInputTag)
        GetNextLine(&OneLine);
  }

  while (FirstInputTag)
    GetNextLine(&OneLine);

  /* irgendeine Makrodefinition nicht abgeschlossen ? */

  if (FirstOutputTag)
  {
    WrError(FirstOutputTag->OpenErrMsg);
  }

  dbgexit("ProcessFile");
}

/****************************************************************************/

static const char *TWrite_Plur(int n)
{
  return (n != 1) ? getmessage(Num_ListPlurName) : "";
}

static void TWrite(long DTime, char *dest, size_t DestSize)
{
  int h;

  *dest = '\0';
  h = DTime / 360000;
  DTime %= 360000;
  if (h > 0)
    as_snprcatf(dest, DestSize, "%d%s%s, ", h, getmessage(Num_ListHourName), TWrite_Plur(h));

  h = DTime / 6000;
  DTime %= 6000;
  if (h > 0)
    as_snprcatf(dest, DestSize, "%d%s%s, ", h, getmessage(Num_ListMinuName), TWrite_Plur(h));

  h = DTime / 100;
  DTime %= 100;
  as_snprcatf(dest, DestSize, "%d.%02d%s%s", h, (int)DTime, getmessage(Num_ListSecoName), TWrite_Plur(h));
}

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

static void AssembleFile_InitPass(void)
{
  static char DateS[31], TimeS[31];
  int z;
  String ArchVal;

  String TmpCompStr;
  tStrComp TmpComp;
  StrCompMkTemp(&TmpComp, TmpCompStr, sizeof(TmpCompStr));

  dbgentry("AssembleFile_InitPass");

  FirstInputTag = NULL;
  FirstOutputTag = NULL;

  MomLocHandle = -1;
  LocHandleCnt = 0;
  SectSymbolCounter = 0;

  SectionStack = NULL;
  FirstIfSave = NULL;
  FirstSaveState = NULL;
  StructStack =
  pInnermostNamedStruct = NULL;
  for (z = 0; z < SegCount; z++)
    pPhaseStacks[z] = NULL;

  InitPass();
  AsmLabelPassInit();

  ActPC = SegCode;
  PCs[ActPC] = 0;
  RelSegs = False;
  ENDOccured = False;
  ErrorCount = 0;
  WarnCount = 0;
  LineSum = 0;
  MacLineSum = 0;
  for (z = 1; z <= StructSeg; z++)
  {
    PCsUsed[z] = FALSE;
    Phases[z] = 0;
    InitChunk(SegChunks + z);
  }

  TransTables =
  CurrTransTable = (PTransTable) malloc(sizeof(TTransTable));
  CurrTransTable->Next = NULL;
  CurrTransTable->Name = as_strdup("STANDARD");
  CurrTransTable->p_table = as_chartrans_table_new();

  EnumSegment = SegNone;
  EnumIncrement = 1;
  EnumCurrentValue = 0;

  strmaxcpy(CurrFileName, "INTERNAL", STRINGSIZE);
  AddFile(CurrFileName);
  CurrLine = 0;

  IncDepth = 0;
  DoLst = eLstMacroExpAll;

  /* Pseudovariablen initialisieren */

  ResetSymbolDefines();
  ResetMacroDefines();
  ResetStructDefines();
  strmaxcpy(TmpCompStr, FlagTrueName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, 1, SegNone, True);
  strmaxcpy(TmpCompStr, FlagFalseName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, 0, SegNone, True);
  strmaxcpy(TmpCompStr, PiName, sizeof(TmpCompStr)); EnterFloatSymbol(&TmpComp, 4.0 * atan(1.0), True);
  strmaxcpy(TmpCompStr, VerName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, VerNo, SegNone, True);
  as_snprintf(ArchVal, sizeof(ArchVal), "%s-%s", ARCHPRNAME, ARCHSYSNAME);
  strmaxcpy(TmpCompStr, ArchName, sizeof(TmpCompStr)); EnterStringSymbol(&TmpComp, ArchVal, True);
  strmaxcpy(TmpCompStr, Has64Name, sizeof(TmpCompStr));
#ifdef HAS64
  EnterIntSymbol(&TmpComp, 1, SegNone, True);
#else
  EnterIntSymbol(&TmpComp, 0, SegNone, True);
#endif
  strmaxcpy(TmpCompStr, CaseSensName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, Ord(CaseSensitive), SegNone, True);
  if (PassNo == 0)
  {
    NLS_CurrDateString(DateS, sizeof(DateS));
    NLS_CurrTimeString(False, TimeS, sizeof(TimeS));
  }
  if (!FindDefSymbol(DateName))
  {
    strmaxcpy(TmpCompStr, DateName, sizeof(TmpCompStr));
    EnterStringSymbol(&TmpComp, DateS, True);
  }
  if (!FindDefSymbol(TimeName))
  {
    strmaxcpy(TmpCompStr, TimeName, sizeof(TmpCompStr));
    EnterStringSymbol(&TmpComp, TimeS, True);
  }

  if (*DefCPU == '\0')
    SetCPUByType(0, NULL);
  else
  {
    tStrComp TmpComp2;

    StrCompMkTemp(&TmpComp2, DefCPU, sizeof(DefCPU));
    if (!SetCPUByName(&TmpComp2))
      SetCPUByType(0, NULL);
  }

  strmaxcpy(TmpCompStr, ListOnName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, ListOn = 1, SegNone, True);
  SetLstMacroExp(eLstMacroExpAll);
  InitLstMacroExpMod(&LstMacroExpModOverride);
  InitLstMacroExpMod(&LstMacroExpModDefault);
  SetFlag(&RelaxedMode, RelaxedName, DefRelaxedMode);
  SetIntConstRelaxedMode(DefRelaxedMode);
  strmaxcpy(TmpCompStr, NestMaxName, sizeof(TmpCompStr)); EnterIntSymbol(&TmpComp, NestMax = DEF_NESTMAX, SegNone, True);
  CopyDefSymbols();

  /* initialize counter for temp symbols here after implicit symbols
     have been defined, so counter starts at a value as low as possible */


  InitTmpSymbols();

  ResetPageCounter();

  StartAdrPresent = False;

  AfterBSRAddr = 0;

  Repass = False;
  PassNo++;

#ifdef PROFILE_MEMO
  NumMemoSum = 0;
  NumMemoCnt = 0;
#endif

  dbgexit("AssembleFile_InitPass");
}

static void AssembleFile_ExitPass(void)
{
  tSavePhase *pSavePhase;
  int z;

#if 0
  if CurrIncludeLevel)
    WrXError(ErrNum_InternalError, "open include");
#endif

  UnsetCPU();
  ClearLocStack();
  ClearStacks();
  AsmErrPassExit();
  for (z = 0; z < SegCount; z++)
    while (pPhaseStacks[z])
    {
      pSavePhase = pPhaseStacks[z];
      pPhaseStacks[z] = pSavePhase->pNext;
      free(pSavePhase);
    }
  if (FirstIfSave)
    WrError(ErrNum_MissEndif);
  if (FirstSaveState)
    WrError(ErrNum_NoRestoreFrame);
  if (SectionStack)
    WrError(ErrNum_MissingEndSect);
  if (StructStack)
    WrXError(ErrNum_OpenStruct, StructStack->Name);
}

static void AssembleFile_WrSummary(const char *pStr)
{
  if (msg_level >= e_msg_level_normal)
    WrConsoleLine(pStr, True);
  if (ListMode == 2)
    WrLstLine(pStr);
}

static void AssembleFile(char *Name)
{
  char *p_out_name;
  String s, Tmp;

  dbgentry("AssembleFile");

  strmaxcpy(SourceFile, Name, STRINGSIZE);
  if (MakeDebug)
    fprintf(Debug, "File %s\n", SourceFile);

  /* Untermodule initialisieren */

  AsmDefInit();
  AsmParsInit();
  AsmIFInit();
  InitFileList();
  ResetStack();

  /* Kommandozeilenoptionen verarbeiten */

  p_out_name = MoveFromOutListFirst();
  strmaxcpy(OutName, p_out_name ? p_out_name : "", STRINGSIZE);
  free(p_out_name);
  if (OutName[0] == '\0')
  {
    strmaxcpy(OutName, SourceFile, STRINGSIZE);
    KillSuffix(OutName);
    AddSuffix(OutName, PrgSuffix);
  }

  if (*ErrorPath == '\0')
  {
    strmaxcpy(ErrorName, SourceFile, STRINGSIZE);
    KillSuffix(ErrorName);
    AddSuffix(ErrorName, LogSuffix);
    unlink(ErrorName);
  }

  switch (ListMode)
  {
    case 0:
      strmaxcpy(LstName, NULLDEV, STRINGSIZE);
      break;
    case 1:
      strmaxcpy(LstName, "!1", STRINGSIZE);
      break;
    case 2:
    {
      char *p_lst_name = MoveFromListOutListFirst();

      strmaxcpy(LstName, p_lst_name ? p_lst_name : "", STRINGSIZE);
      if (p_lst_name) free(p_lst_name);
      if (*LstName == '\0')
      {
        strmaxcpy(LstName, SourceFile, STRINGSIZE);
        KillSuffix(LstName);
        AddSuffix(LstName, LstSuffix);
      }
      break;
    }
  }
  ListToStdout = !strcmp(LstName, "!1");
  ListToNull = !strcmp(LstName, NULLDEV);

  if (ShareMode != 0)
  {
    char *p_share_name = MoveFromShareOutListFirst();

    strmaxcpy(ShareName, p_share_name ? p_share_name : "", STRINGSIZE);
    if (p_share_name)
      free(p_share_name);
    if (*ShareName == '\0')
    {
      strmaxcpy(ShareName, SourceFile, STRINGSIZE);
      KillSuffix(ShareName);
      switch (ShareMode)
      {
        case 1:
          AddSuffix(ShareName, ".inc");
          break;
        case 2:
          AddSuffix(ShareName, ".h");
          break;
        case 3:
          AddSuffix(ShareName, IncSuffix);
          break;
      }
    }
  }

  if (MacProOutput)
  {
    strmaxcpy(MacProName, SourceFile, STRINGSIZE);
    KillSuffix(MacProName);
    AddSuffix(MacProName, PreSuffix);
  }

  if (MacroOutput)
  {
    strmaxcpy(MacroName, SourceFile, STRINGSIZE);
    KillSuffix(MacroName);
    AddSuffix(MacroName, MacSuffix);
  }

  ClearIncludeList();
  CurrIncludeLevel = 0;

  if (DebugMode != DebugNone)
    InitLineInfo();

  /* Variablen initialisieren */

  StartTime = GTime();

  PassNo = 0;

  /* Listdatei eroeffnen */

  if (msg_level >= e_msg_level_normal)
    printf("%s%s\n", getmessage(Num_InfoMessAssembling), SourceFile);

  /* Maximum include level survives re-passing, so it can be
     used for the listing to format to the right max. depth from
     the beginning: */


  MaxIncDepth = 0;

  do
  {
    /* Durchlauf initialisieren */

    AssembleFile_InitPass();
    AsmSubPassInit();
    AsmErrPassInit();
    if (msg_level >= e_msg_level_normal)
    {
      as_snprintf(Tmp, sizeof(Tmp), "%s", getmessage(Num_InfoMessPass));
      as_snprcatf(Tmp, sizeof(Tmp), IntegerFormat, PassNo);
      WrConsoleLine(Tmp, True);
    }

    /* Dateien oeffnen */

    if (CodeOutput)
      OpenFile();

    if (ShareMode != 0)
    {
      ShareFile = fopen(ShareName, "w");
      if (!ShareFile)
        ChkXIO(ErrNum_OpeningFile, ShareName);
      errno = 0;
      switch (ShareMode)
      {
        case 1:
          fprintf(ShareFile, "(* %s-Include File for CONST Section *)\n", SourceFile);
          break;
        case 2:
          fprintf(ShareFile, "/* %s-Include File for C Program */\n", SourceFile);
          break;
        case 3:
          fprintf(ShareFile, "; %s-Include File for Assembler Program\n", SourceFile);
          break;
      }
      ChkIO(ErrNum_ListWrError);
    }

    if (MacProOutput)
    {
      MacProFile = fopen(MacProName, "w");
      if (!MacProFile)
        ChkXIO(ErrNum_OpeningFile, MacProName);
    }

    if ((MacroOutput) && (PassNo == 1))
    {
      MacroFile = fopen(MacroName, "w");
      if (!MacroFile)
        ChkXIO(ErrNum_OpeningFile, MacroName);
    }

    /* Listdatei oeffnen */

    OpenWithStandard(&LstFile, LstName);
    if (!LstFile)
      ChkXIO(ErrNum_OpeningFile, LstName);
    if (!ListToNull)
    {
      errno = 0;
      fprintf(LstFile, "%s", PrtInitString);
      ChkIO(ErrNum_ListWrError);
    }
    if ((ListMask & 1) != 0)
      NewPage(0, False);

    /* assemblieren */

    ProcessFile(SourceFile);
    AssembleFile_ExitPass();

    /* Dateien schliessen */

    if (CodeOutput)
      CloseFile();

    if (ShareMode != 0)
    {
      errno = 0;
      switch (ShareMode)
      {
        case 1:
          fprintf(ShareFile, "(* Ende Include File for CONST Section *)\n");
          break;
        case 2:
          fprintf(ShareFile, "/* Ende Include File for C Program */\n");
          break;
        case 3:
          fprintf(ShareFile, "; Ende Include File for Assembler Program\n");
          break;
      }
      ChkIO(ErrNum_ListWrError);
      CloseIfOpen(&ShareFile);
    }

    if (MacProOutput)
      CloseIfOpen(&MacProFile);
    if (MacroOutput && (PassNo == 1))
      CloseIfOpen(&MacroFile);

    /* evtl. fuer naechsten Durchlauf aufraeumen */

    if ((ErrorCount == 0) && (Repass))
    {
      CloseIfOpen(&LstFile);
      if (CodeOutput)
        unlink(OutName);
      ClearCodepages();
      if (MakeUseList)
        ClearUseList();
      if (MakeCrossList)
        ClearCrossList();
      ClearDefineList();
      if (DebugMode != DebugNone)
        ClearLineInfo();
      ClearIncludeList();
      if (DebugMode != DebugNone)
      {
        ResetAddressRanges();
        ClearSectionUsage();
      }
    }
  }
  while ((ErrorCount == 0) && (Repass));

  /* bei Fehlern loeschen */

  if (ErrorCount != 0)
  {
    if (CodeOutput)
      unlink(OutName);
    if (MacProOutput)
      unlink(MacProName);
    if ((MacroOutput) && (PassNo == 1))
      unlink(MacroName);
    if (ShareMode != 0)
      unlink(ShareName);
    GlobErrFlag = True;
  }

  /* Debug-Ausgabe muss VOR die Symbollistenausgabe, weil letztere die
     Symbolliste loescht */


  if (DebugMode != DebugNone)
  {
    if (ErrorCount == 0)
      DumpDebugInfo();
    ClearLineInfo();
  }

  /* Listdatei abschliessen */

  if  (strcmp(LstName, NULLDEV))
  {
    if (ListMask & 2)
      PrintSymbolList();

    if (ListMask & 64)
      PrintRegDefs();

    if (ListMask & 4)
      PrintMacroList();

    if (ListMask & 256)
      PrintStructList();

    if (ListMask & 8)
      PrintFunctionList();

    if (ListMask & 32)
      PrintDefineList();

    if (ListMask & 128)
      PrintCodepages();

    if (MakeUseList)
    {
      NewPage(ChapDepth, True);
      PrintUseList();
    }

    if (MakeCrossList)
    {
      NewPage(ChapDepth, True);
      PrintCrossList();
    }

    if (MakeSectionList)
      PrintSectionList();

    if (MakeIncludeList)
      PrintIncludeList();

    if (!ListToNull)
    {
      errno = 0;
      fprintf(LstFile, "%s", PrtExitString);
      ChkIO(ErrNum_ListWrError);
    }
  }

  if (MakeUseList)
    ClearUseList();

  if (MakeCrossList)
    ClearCrossList();

  ClearSectionList();

  ClearIncludeList();

  if (!*ErrorPath)
    CloseIfOpen(&ErrorFile);

  ClearUp();

  /* Statistik ausgeben */

  StopTime = GTime();
  TWrite(DTime(StartTime, StopTime), s, sizeof(s));
  strmaxcat(s, getmessage(Num_InfoMessAssTime), STRINGSIZE);
  if (msg_level >= e_msg_level_normal)
  {
    WrConsoleLine("", True);
    WrConsoleLine(s, True);
    WrConsoleLine("", True);
  }
  if (ListMode == 2)
  {
    WrLstLine("");
    WrLstLine(s);
    WrLstLine("");
  }

  as_snprintf(s, sizeof(s), "%7" PRILongInt "%s", LineSum,
              getmessage((LineSum == 1) ? Num_InfoMessAssLine : Num_InfoMessAssLines), STRINGSIZE);
  AssembleFile_WrSummary(s);

  if (LineSum != MacLineSum)
  {
    as_snprintf(s, sizeof(s), "%7" PRILongInt "%s", MacLineSum,
                getmessage((MacLineSum == 1) ? Num_InfoMessMacAssLine : Num_InfoMessMacAssLines), STRINGSIZE);
    AssembleFile_WrSummary(s);
  }

  as_snprintf(s, sizeof(s), "%7d%s", (int)PassNo,
              getmessage((PassNo == 1) ? Num_InfoMessPassCnt : Num_InfoMessPPassCnt), STRINGSIZE);
  AssembleFile_WrSummary(s);

  if ((ErrorCount > 0) && (Repass) && (ListMode != 0))
    WrLstLine(getmessage(Num_InfoMessNoPass));

#ifdef __TURBOC__
  as_snprintf(s, sizeof(s), "%7lu%s", coreleft() >> 10,
              getmessage(Num_InfoMessRemainMem));
  AssembleFile_WrSummary(s);

  as_snprintf(s, sizeof(s), "%7lu%s", (unsigned long)StackRes(),
              getmessage(Num_InfoMessRemainStack));
  AssembleFile_WrSummary(s);
#endif

  as_snprintf(s, sizeof(s), "%7u%s%s", (unsigned)ErrorCount,
              getmessage(Num_InfoMessErrCnt),
              (ErrorCount == 1) ? "" : getmessage(Num_InfoMessErrPCnt));
  AssembleFile_WrSummary(s);

  as_snprintf(s, sizeof(s), "%7u%s%s", (unsigned)WarnCount,
              getmessage(Num_InfoMessWarnCnt),
              (WarnCount == 1) ? "" : getmessage(Num_InfoMessWarnPCnt));
  AssembleFile_WrSummary(s);

#ifdef PROFILE_MEMO
  {
    unsigned long Sum = (NumMemoSum * 100) / NumMemoCnt;

    as_snprintf(s, sizeof(s), "%4lu.%02lu%s", Sum / 100, Sum % 100, " Oppart Compares");
    if (msg_level >= e_msg_level_normal)
      WrConsoleLine(s, True);
    if (ListMode == 2)
      WrLstLine(s);
  }
#endif

  CloseIfOpen(&LstFile);

  /* verstecktes */

  if (MakeDebug)
    PrintSymbolDepth();

  /* Speicher freigeben */

  ClearSymbolList();
  ClearCodepages();
  ClearMacroList();
  ClearFunctionList();
  ClearDefineList();
  ClearFileList();
  ClearStructList();

  dbgentry("AssembleFile");
}

static void AssembleGroup(const char *pFileMask)
{
  String FileMask;

  strmaxcpy(FileMask, pFileMask, sizeof(FileMask));
  AddSuffix(FileMask, SrcSuffix);
  if (!DirScan(FileMask, AssembleFile))
    fprintf(stderr, "%s%s\n", FileMask, getmessage(Num_InfoMessNFilesFound));
}

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

static int LineZ, screen_height = 0;
static Boolean write_cpu_list_exit;

static void write_console_next(const char *p_line)
{
  WrConsoleLine(p_line, True);
  if (screen_height && (++LineZ >= screen_height))
  {
    LineZ = 0;
    WrConsoleLine(getmessage(Num_KeyWaitMsg), False);
    fflush(stdout);
    while (getchar() != '\n');
    printf("%s", CursUp);
  }
}

static as_cmd_result_t CMD_SharePascal(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
    ShareMode = 1;
  else if (ShareMode == 1)
    ShareMode = 0;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_ShareC(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
    ShareMode = 2;
  else if (ShareMode == 2)
    ShareMode = 0;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_ShareAssembler(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
    ShareMode = 3;
  else if (ShareMode == 3)
    ShareMode = 0;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_DebugMode(Boolean Negate, const char *pArg)
{
  String Arg;

  strmaxcpy(Arg, pArg, STRINGSIZE);
  UpString(Arg);

  if (Negate)
  {
    if (Arg[0] != '\0')
      return e_cmd_err;
    else
    {
      DebugMode = DebugNone;
      return e_cmd_ok;
    }
  }
  else if (!strcmp(Arg, ""))
  {
    DebugMode = DebugMAP;
    return e_cmd_ok;
  }
  else if (!strcmp(Arg, "ATMEL"))
  {
    DebugMode = DebugAtmel;
    return e_cmd_arg;
  }
  else if (!strcmp(Arg, "MAP"))
  {
    DebugMode = DebugMAP;
    return e_cmd_arg;
  }
  else if (!strcmp(Arg, "NOICE"))
  {
    DebugMode = DebugNoICE;
    return e_cmd_arg;
  }
#if 0
  else if (!strcmp(Arg, "A.OUT"))
  {
    DebugMode = DebugAOUT;
    return e_cmd_arg;
  }
  else if (!strcmp(Arg, "COFF"))
  {
    DebugMode = DebugCOFF;
    return e_cmd_arg;
  }
  else if (!strcmp(Arg, "ELF"))
  {
    DebugMode = DebugELF;
    return e_cmd_arg;
  }
#endif
  else
    return e_cmd_err;

#if 0
  if (Negate)
    DebugMode = DebugNone;
  else
    DebugMode = DebugMAP;
  return e_cmd_ok;
#endif
}

static as_cmd_result_t CMD_ListConsole(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
    ListMode = 1;
  else if (ListMode == 1)
    ListMode = 0;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_ListRadix(Boolean Negate, const char *Arg)
{
  Boolean OK, new_zero_pad = False;
  LargeWord NewListRadixBase;

  if (Negate)
  {
    ListRadixBase = 16;
    ListPCZeroPad = False;
    return e_cmd_ok;
  }

  if (*Arg == '0')
  {
    new_zero_pad = True;
    Arg++;
  }
  NewListRadixBase = ConstLongInt(Arg, &OK, 10);
  if (!OK || (NewListRadixBase < 2) || (NewListRadixBase > 36))
    return e_cmd_err;
  ListRadixBase = NewListRadixBase;
  ListPCZeroPad = new_zero_pad;
  return e_cmd_arg;
}

static as_cmd_result_t CMD_screen_height(Boolean negate, const char *p_arg)
{
  Boolean ok;
  int new_screen_height;

  if (negate)
  {
    screen_height = 0;
    return e_cmd_ok;
  }
  new_screen_height = ConstLongInt(p_arg, &ok, 10);
  if (!ok)
    return e_cmd_err;
  screen_height = new_screen_height;
  return e_cmd_arg;
}

static as_cmd_result_t CMD_ListFile(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
    ListMode = 2;
  else if (ListMode == 2)
    ListMode = 0;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_SuppWarns(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  SuppWarns = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_UseList(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MakeUseList = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_CrossList(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MakeCrossList = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_SectionList(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MakeSectionList = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_BalanceTree(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  BalanceTrees = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_MakeDebug(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (!Negate)
  {
    MakeDebug = True;
    errno = 0;
    Debug = fopen("as.deb", "w");
    if (!Debug)
      ChkIO(ErrNum_ListWrError);
  }
  else if (MakeDebug)
  {
    MakeDebug = False;
    CloseIfOpen(&Debug);
  }
  return e_cmd_ok;
}

static as_cmd_result_t CMD_MacProOutput(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MacProOutput = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_MacroOutput(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MacroOutput = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_MakeIncludeList(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  MakeIncludeList = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_CodeOutput(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  CodeOutput = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_MsgIfRepass(Boolean Negate, const char *Arg)
{
  Boolean OK;
  UNUSED(Arg);

  MsgIfRepass = !Negate;
  if (MsgIfRepass)
  {
    if (Arg[0] == '\0')
    {
      PassNoForMessage = 1;
      return e_cmd_ok;
    }
    else
    {
      PassNoForMessage = ConstLongInt(Arg, &OK, 10);
      if (!OK)
      {
        PassNoForMessage = 1;
        return e_cmd_ok;
      }
      else if (PassNoForMessage < 1)
        return e_cmd_err;
      else
        return e_cmd_arg;
    }
  }
  else
    return e_cmd_ok;
}

static as_cmd_result_t CMD_Relaxed(Boolean Negate, const char *pArg)
{
  UNUSED(pArg);

  DefRelaxedMode = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_ExtendErrors(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if ((Negate) && (ExtendErrors > 0))
    ExtendErrors--;
  else if ((!Negate) && (ExtendErrors < 2))
    ExtendErrors++;

  return e_cmd_ok;
}

static as_cmd_result_t CMD_NumericErrors(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  NumericErrors = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_HexLowerCase(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  HexStartCharacter = Negate ? 'A' : 'a';
  return e_cmd_ok;
}

static as_cmd_result_t CMD_SplitByte(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  if (Negate)
  {
    SplitByteCharacter = '\0';
    return e_cmd_ok;
  }
  else if (*Arg)
  {
    if (strlen(Arg) != 1)
      return e_cmd_err;
    SplitByteCharacter = *Arg;
    return e_cmd_arg;
  }
  else
  {
    SplitByteCharacter = '.';
    return e_cmd_ok;
  }
}

static as_cmd_result_t CMD_ThrowErrors(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  ThrowErrors = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_CaseSensitive(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  CaseSensitive = !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_GNUErrors(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  GNUErrors  =  !Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_IncludeList(Boolean Negate, const char *Arg)
{
  char *p;
  String Copy, part;

  if (*Arg == '\0') return e_cmd_err;
  else
  {
    strmaxcpy(Copy, Arg, STRINGSIZE);
    do
    {
      p = strrchr(Copy, DIRSEP);
      if (!p)
      {
        strmaxcpy(part, Copy, STRINGSIZE);
        *Copy = '\0';
      }
      else
      {
        *p = '\0';
        strmaxcpy(part, p + 1, STRINGSIZE);
      }
      if (Negate)
        RemoveIncludeList(part);
      else
        AddIncludeList(part);
    }
    while (Copy[0] != '\0');
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_ListMask(Boolean Negate, const char *Arg)
{
  Word erg;
  Boolean OK;

  if (Arg[0] == '\0')
    return e_cmd_err;
  else
  {
    erg = ConstLongInt(Arg, &OK, 10);
    if ((!OK) || (erg > 511))
      return e_cmd_err;
    else
    {
      ListMask = Negate ? (ListMask & ~erg) : (ListMask | erg);
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_DefSymbol(Boolean Negate, const char *Arg)
{
  String Copy, Part, Name;
  char *p;
  as_cmd_result_t Result = e_cmd_err;

  TempResult t;
  as_tempres_ini(&t);

  if (Arg[0] == '\0')
    LEAVE;

  strmaxcpy(Copy, Arg, STRINGSIZE);
  do
  {
    p = QuotPos(Copy, ',');
    if (!p)
    {
      strmaxcpy(Part, Copy, STRINGSIZE);
      Copy[0] = '\0';
    }
    else
    {
      *p = '\0';
      strmaxcpy(Part, Copy, STRINGSIZE);
      strmov(Copy, p + 1);
    }
   if (!CaseSensitive)
     UpString(Part);
   p = QuotPos(Part, '=');
   if (!p)
   {
     strmaxcpy(Name, Part, STRINGSIZE);
     Part[0] = '\0';
   }
   else
   {
     *p = '\0';
     strmaxcpy(Name, Part, STRINGSIZE);
     strmov(Part, p + 1);
   }
   if (!ChkSymbName(Name))
     LEAVE;
   if (Negate)
     RemoveDefSymbol(Name);
   else
   {
     AsmParsInit();
     if (Part[0] != '\0')
     {
       EvalExpression(Part, &t);
       if ((t.Typ == TempNone) || mFirstPassUnknown(t.Flags))
         return e_cmd_err;
     }
     else
       as_tempres_set_int(&t, 1);
     AddDefSymbol(Name, &t);
   }
  }
  while (Copy[0] != '\0');

  Result = e_cmd_arg;
func_exit:
  as_tempres_free(&t);
  return Result;
}

static as_cmd_result_t CMD_ErrorPath(Boolean Negate, const char *Arg)
{
  if (Negate)
    return e_cmd_err;
  else if (Arg[0] == '\0')
  {
    ErrorPath[0] = '\0';
    return e_cmd_ok;
  }
  else
  {
    strmaxcpy(ErrorPath, Arg, STRINGSIZE);
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_HardRanges(Boolean Negate, const char *Arg)
{
  UNUSED(Arg);

  HardRanges = Negate;
  return e_cmd_ok;
}

static as_cmd_result_t CMD_OutFile(Boolean Negate, const char *Arg)
{
  if (Arg[0] == '\0')
  {
    if (Negate)
    {
      ClearOutList();
      return e_cmd_ok;
    }
    else
      return e_cmd_err;
  }
  else
  {
    if (Negate)
      RemoveFromOutList(Arg);
    else
      AddToOutList(Arg);
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_ShareOutFile(Boolean Negate, const char *Arg)
{
  if (Arg[0] == '\0')
  {
    if (Negate)
    {
      ClearShareOutList();
      return e_cmd_ok;
    }
    else
      return e_cmd_err;
  }
  else
  {
    if (Negate)
      RemoveFromShareOutList(Arg);
    else
      AddToShareOutList(Arg);
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_ListOutFile(Boolean Negate, const char *Arg)
{
  if (Arg[0] == '\0')
  {
    if (Negate)
    {
      ClearListOutList();
      return e_cmd_ok;
    }
    else
      return e_cmd_err;
  }
  else
  {
    if (Negate)
      RemoveFromListOutList(Arg);
    else
      AddToListOutList(Arg);
    return e_cmd_arg;
  }
}

static Boolean CMD_CPUAlias_ChkCPUName(char *s)
{
  int z;

  for (z = 0; z < (int)strlen(s); z++)
    if (!isalnum((unsigned int) s[z]))
      return False;
  return True;
}

static as_cmd_result_t CMD_CPUAlias(Boolean Negate, const char *Arg)
{
  const char *p;
  String s1, s2;

  if (Negate)
    return e_cmd_err;
  else if (Arg[0] == '\0')
    return e_cmd_err;
  else
  {
    p = strchr(Arg, '=');
    if (!p)
      return e_cmd_err;
    else
    {
      strmemcpy(s1, STRINGSIZE, Arg, p - Arg);
      UpString(s1);
      strmaxcpy(s2, p + 1, STRINGSIZE);
      UpString(s2);
      if (!(CMD_CPUAlias_ChkCPUName(s1) && CMD_CPUAlias_ChkCPUName(s2)))
        return e_cmd_err;
      else if (!AddCPUAlias(s2, s1))
        return e_cmd_err;
      else
        return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_SetCPU(Boolean Negate, const char *Arg)
{
  if (Negate)
  {
    *DefCPU = '\0';
    return e_cmd_ok;
  }
  else
  {
    if (*Arg == '\0')
      return e_cmd_err;

    if (!as_strcasecmp(Arg, "?") || !as_strcasecmp(Arg, "LIST"))
    {
      write_cpu_list_exit = True;
      return e_cmd_arg;
    }

    strmaxcpy(DefCPU, Arg, sizeof(DefCPU) - 1);
    NLS_UpString(DefCPU);

    if (!LookupCPUDefByName(DefCPU))
    {
      *DefCPU = '\0';
      return e_cmd_err;
    }
    return e_cmd_arg;
  }
}

static as_cmd_result_t CMD_NoICEMask(Boolean Negate, const char *Arg)
{
  Word erg;
  Boolean OK;

  if (Negate)
  {
    NoICEMask = 1 << SegCode;
    return e_cmd_ok;
  }
  else if (Arg[0] == '\0')
    return e_cmd_err;
  else
  {
    erg = ConstLongInt(Arg, &OK, 10);
    if (!OK || (erg >= (1 << SegCount)))
      return e_cmd_err;
    else
    {
      NoICEMask = erg;
      return e_cmd_arg;
    }
  }
}

static as_cmd_result_t CMD_MaxErrors(Boolean Negate, const char *Arg)
{
  if (Negate)
  {
    MaxErrors = 0;
    return e_cmd_ok;
  }
  else if (Arg[0] == '\0')
    return e_cmd_err;
  else
  {
    Boolean OK;
    LongWord NewMaxErrors = ConstLongInt(Arg, &OK, 10);

    if (!OK)
      return e_cmd_err;
    MaxErrors = NewMaxErrors;
    return e_cmd_arg;
  }
}

/*!------------------------------------------------------------------------
 * \fn     CMD_MaxIncludeLevel(Boolean Negate, const char *pArg)
 * \brief  set maximum include nesting level
 * \param  Negate back to default?
 * \param  pArg numeric argument
 * \return exec result
 * ------------------------------------------------------------------------ */


#define DEFAULT_MAXINCLUDELEVEL 200

static as_cmd_result_t CMD_MaxIncludeLevel(Boolean Negate, const char *pArg)
{
  if (Negate)
  {
    MaxErrors = DEFAULT_MAXINCLUDELEVEL;
    return e_cmd_ok;
  }
  else if (pArg[0] == '\0')
    return e_cmd_err;
  else
  {
    Boolean OK;
    Integer NewMaxIncludeLevel = ConstLongInt(pArg, &OK, 10);

    if (!OK)
      return e_cmd_err;
    MaxIncludeLevel = NewMaxIncludeLevel;
    return e_cmd_arg;
  }
}

static const as_cmd_rec_t ASParams[] =
{
  { "A"             , CMD_BalanceTree     },
  { "alias"         , CMD_CPUAlias        },
  { "a"             , CMD_ShareAssembler  },
  { "C"             , CMD_CrossList       },
  { "c"             , CMD_ShareC          },
  { "CPU"           , CMD_SetCPU          },
  { "D"             , CMD_DefSymbol       },
  { "E"             , CMD_ErrorPath       },
  { "g"             , CMD_DebugMode       },
  { "G"             , CMD_CodeOutput      },
  { "gnuerrors"     , CMD_GNUErrors       },
  { "h"             , CMD_HexLowerCase    },
  { "i"             , CMD_IncludeList     },
  { "I"             , CMD_MakeIncludeList },
  { "L"             , CMD_ListFile        },
  { "l"             , CMD_ListConsole     },
  { "listradix"     , CMD_ListRadix       },
  { "splitbyte"     , CMD_SplitByte       },
  { "M"             , CMD_MacroOutput     },
  { "maxerrors"     , CMD_MaxErrors       },
  { "maxinclevel"   , CMD_MaxIncludeLevel },
  { "n"             , CMD_NumericErrors   },
  { "noicemask"     , CMD_NoICEMask       },
  { "o"             , CMD_OutFile         },
  { "P"             , CMD_MacProOutput    },
  { "p"             , CMD_SharePascal     },
  { "r"             , CMD_MsgIfRepass     },
  { RelaxedName     , CMD_Relaxed         },
  { "s"             , CMD_SectionList     },
  { "screenheight"  , CMD_screen_height   },
  { "shareout"      , CMD_ShareOutFile    },
  { "olist"         , CMD_ListOutFile     },
  { "t"             , CMD_ListMask        },
  { "u"             , CMD_UseList         },
  { "U"             , CMD_CaseSensitive   },
  { "w"             , CMD_SuppWarns       },
  { "warnranges"    , CMD_HardRanges      },
  { "x"             , CMD_ExtendErrors    },
  { "X"             , CMD_MakeDebug       },
  { "Y"             , CMD_ThrowErrors     }
};

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

#ifdef __sunos__

extern void on_exit(void (*procp)(int status, caddr_t arg),caddr_t arg);

static void GlobExitProc(int status, caddr_t arg)
{
  if (MakeDebug)
    CloseIfOpen(&Debug);
}

#else

/* Might no longer need this with newer TCC versions: */

#ifdef __TINYC__
void * __dso_handle __attribute((visibility("hidden"))) = &__dso_handle;
#endif

static void GlobExitProc(void)
{
  if (MakeDebug)
    CloseIfOpen(&Debug);
}

#endif

int main(int argc, char **argv)
{
  char *Env;
  String Dummy;
  static Boolean First = TRUE;
  as_cmd_results_t cmd_results;

  if (First)
  {
    be_le_init();
    nls_init();
    bpemu_init();
    stdhandl_init();
    strutil_init();
    chunks_init();
    if (!NLS_Initialize(&argc, argv))
      exit(4);

#ifdef _USE_MSH
    nlmessages_init_buffer(as_msh_data, sizeof(as_msh_data), MsgId1, MsgId2);
#else
    nlmessages_init_file("as.msg", *argv, MsgId1, MsgId2);
#endif
    ioerrs_init(*argv);
    as_cmdarg_init(*argv);
    msg_level_init();
    as_cmd_register(ASParams, as_array_size(ASParams));

    asmfnums_init();
    asminclist_init();
    asmitree_init();

    asmdef_init();
    cpulist_init();
    asmsub_init();
    asmpars_init();
    intformat_init();

    asmmac_init();
    asmstruct_init();
    asmif_init();
    asmerr_init();
    asmcode_init();
    asmlabel_init();
    asmdebug_init();

    codeallg_init();
    onoff_common_init();
    literals_init();

#if 1
    codenone_init();
#endif
    code68k_init();
    code56k_init();
    code601_init();
    codepalm_init();
    codemcore_init();
    codexgate_init();
    code68_init();
    code6805_init();
    code6809_init();
    code6812_init();
    codes12z_init();
    code6816_init();
    code68rs08_init();
    codeh8_3_init();
    codeh8_5_init();
    code7000_init();
    codeko09_init();
    code65_init();
    codepps4_init();
    codeh16_init();
    code7700_init();
    codehmcs400_init();
    code4500_init();
    codem16_init();
    codem16c_init();
    codepdp11_init();
    codevax_init();
    code4004_init();
    code8008_init();
    code48_init();
    code51_init();
    code96_init();
    code85_init();
    code86_init();
    code960_init();
    code8x30x_init();
    code2650_init();
    codexa_init();
    codeavr_init();
    code29k_init();
    code166_init();
    codez80_init();
    codez8_init();
    codez8000_init();
    codekcpsm_init();
    codekcpsm3_init();
    codemico8_init();
    code96c141_init();
    code90c141_init();
    code87c800_init();
    code870c_init();
    code47c00_init();
    code97c241_init();
    code9331_init();
    code16c5x_init();
    code16c8x_init();
    code17c4x_init();
    codesx20_init();
    codepdk_init();
    codest6_init();
    codest7_init();
    codest9_init();
    code6804_init();
    code3201x_init();
    code3202x_init();
    code3203x_init();
    code3205x_init();
    code32054x_init();
    code3206x_init();
    code9900_init();
    codetms7_init();
    code370_init();
    codemsp_init();
    codetms1_init();
    code78c10_init();
    code75xx_init();
    code75k0_init();
    code78k0_init();
    code78k2_init();
    code78k3_init();
    code78k4_init();
    code7720_init();
    code77230_init();
    codev60_init();
    codescmp_init();
    codeimp16_init();
    code807x_init();
    codecop4_init();
    codecop8_init();
    codesc14xxx_init();
    codens32k_init();
    codeace_init();
    codecp3f_init();
    codef8_init();
    code53c8xx_init();
    codef2mc8_init();
    codef2mc16_init();
    codemn1610_init();
    codemn2610_init();
    codeolms40_init();
    codeolms50_init();
    code1802_init();
    codevector_init();
    codexcore_init();
    code1750_init();
    codekenbak_init();
    codecp1600_init();
    codenano_init();
    code6100_init();
    coderx_init();
    code61860_init();
    code62015_init();
    First = FALSE;
  }

#ifdef __sunos__
  on_exit(GlobExitProc, (caddr_t) NULL);
#else
# ifndef __MUNIX__
  atexit(GlobExitProc);
# endif
#endif

  *CursUp = '\0';
  switch (Redirected)
  {
    case NoRedir:
      Env = getenv("USEANSI");
      strmaxcpy(Dummy, Env ? Env : "Y", STRINGSIZE);
      if (as_toupper(Dummy[0]) == 'N')
      {
      }
      else
      {
        strcpy(CursUp, " [A"); CursUp[0] = Char_ESC;
      }
      break;
    case RedirToDevice:
      break;
    case RedirToFile:
      break;
  }

  ShareMode = 0;
  ListMode = 0;
  IncludeList[0] = '\0';
  SuppWarns = False;
  MakeUseList = False;
  MakeCrossList = False;
  MakeSectionList = False;
  MakeIncludeList = False;
  ListMask = 0x1ff;
  MakeDebug = False;
  ExtendErrors = 0;
  DefRelaxedMode = False;
  MacroOutput = False;
  MacProOutput = False;
  CodeOutput = True;
  strcpy(ErrorPath,  "!2");
  MsgIfRepass = False;
  NumericErrors = False;
  DebugMode = DebugNone;
  CaseSensitive = False;
  ThrowErrors = False;
  HardRanges = True;
  NoICEMask = 1 << SegCode;
  GNUErrors = False;
  MaxErrors = 0;
  ListRadixBase = 16;
  ListPCZeroPad = False;
  MaxIncludeLevel = DEFAULT_MAXINCLUDELEVEL;
  write_cpu_list_exit = False;

  LineZ = 0;
  screen_height = 0;

#if defined(INCDIR)
  CMD_IncludeList(False, INCDIR);
#endif
  if (e_cmd_err == as_cmd_process(argc, argv, EnvName, &cmd_results))
  {
    printf("%s%s\n", getmessage(cmd_results.error_arg_in_env ? Num_ErrMsgInvEnvParam : Num_ErrMsgInvParam), cmd_results.error_arg);
    exit(4);
  }

  if ((msg_level >= e_msg_level_verbose) || cmd_results.write_version_exit)
  {
    String Tmp;

    as_snprintf(Tmp, sizeof(Tmp), "%s%s", getmessage(Num_InfoMessMacroAss), Version);
    write_console_next(Tmp);
    as_snprintf(Tmp, sizeof(Tmp), "(%s-%s)", ARCHPRNAME, ARCHSYSNAME);
    write_console_next(Tmp);
    write_console_next(InfoMessCopyright);
    WriteCopyrights(write_console_next);
    write_console_next("");
  }

  if (cmd_results.write_help_exit)
  {
    char *ph1, *ph2;
    String tmp;
    as_snprintf(tmp, sizeof(tmp), "%s%s%s", getmessage(Num_InfoMessHead1), as_cmdarg_get_executable_name(), getmessage(Num_InfoMessHead2));
    write_console_next(tmp);
    for (ph1 = getmessage(Num_InfoMessHelp), ph2 = strchr(ph1, '\n'); ph2; ph1 = ph2 + 1, ph2 = strchr(ph1, '\n'))
    {
      *ph2 = '\0';
      write_console_next(ph1);
      *ph2 = '\n';
    }
  }

  if (write_cpu_list_exit)
  {
    write_console_next(getmessage(Num_InfoMessCPUList));
    PrintCPUList(write_console_next);
    ClearCPUList();
  }

  if (cmd_results.write_version_exit || write_cpu_list_exit || cmd_results.write_help_exit)
    exit(0);

  /* ListRadixBase must have been set */

  asmlist_init();

  GlobErrFlag = False;
  if (ErrorPath[0] != '\0')
  {
    strcpy(ErrorName, ErrorPath);
    unlink(ErrorName);
  }

  if (StringListEmpty(cmd_results.file_arg_list))
  {
    fprintf(stderr, "%s: %s\n", as_cmdarg_get_executable_name(), getmessage(Num_ErrMessNoInputFiles));
    exit(1);
  }
  else
  {
    char *pFile;

    while (True)
    {
      pFile = MoveAndCutStringListFirst(&cmd_results.file_arg_list);
      if (!pFile)
        break;
      if (*pFile)
        AssembleGroup(pFile);
      free(pFile);
    }
  }

  if (*ErrorPath)
    CloseIfOpen(&ErrorFile);

  ClearCPUList();

  return GlobErrFlag ? 2 : 0;
}