https://github.com/virtualagc/virtualagc
Revision 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC, committed by Ron Burkey on 07 August 2022, 15:04:04 UTC
assembly listings from yaASM and yaLEMAP. Added some debugging messages
to 'make install'.  Tweaked debugging messages that VirtualAGC embeds in
'simulate'.  Verified buildability in Mint 21, 20, 19, 17, and verified
buildability using clang in Mint 17.
1 parent 6bb1acc
Raw File
Tip revision: 078c79d8734a9ed2860303a7c1662004284fe853 authored by Ron Burkey on 07 August 2022, 15:04:04 UTC
Fixed a potential string-overflow bug in yaASM. Removed timestamps from
Tip revision: 078c79d
ParseEQUALS.c
/*
 * Copyright 2003-2004,2016 Ronald S. Burkey <info@sandroid.org>
 *
 * This file is part of yaAGC.
 *
 * yaAGC is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * yaAGC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with yaAGC; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * Filename:     ParseEQUALS.c
 * Purpose:      Assembles the EQUALS or = pseudo-op.
 * Mod History:  04/16/03 RSB   Began.
 *               07/26/04 RSB   Offset moved out of symbol and into
 *                              global variable.
 *               07/27/05 JMS   Added support for symbol debugging.
 *               11/02/16 RSB   Modified treatment of "EQUALS number", where
 *                              "number" is a large number.  Small numbers
 *                              continue to be treated as constant, while
 *                              larger ones are treated as flat addresses.
 *                              This was needed for Sunburst, and specifically
 *                              for the SAVERASE label.  Mods to the operands,
 *                              such as +1 or -25, are now treated differently,
 *                              and hopefully more-correctly, because the old
 *                              method was failing for the very large mods
 *                              found some places in SUNBURST.  However, I
 *               01/29/17 MAS   Added an address calculation tweak for
 *                              the --raytheon option.
 */

#include "yaYUL.h"
#include <stdlib.h>
#include <string.h>

//------------------------------------------------------------------------
// JMS: To properly add entries to the symbol table for debugging, we
// need the current file name and line number of the symbol, so i take the
// global variables in Pass.c. I am being lazy here, I probably should
// include this information in InputRecord_t.
extern Line_t CurrentFilename;
extern int CurrentLineInFile;

//------------------------------------------------------------------------
// Fetch a symbol value, possibly with offset.  Return 0 on success.
// The symbol value will have an Invalid field if not resolved yet.
// ... Later:  For a very long time, I simply added the offset into the
// symbol value.  However, I eventually realized that in doing this it 
// circumvents all kinds of crazy things the assembler wants to do with
// offsets --- such as converting one operand type to another.  Therefore,
// I now simply put the offset into a global variable, where it is 
// eventually added to the already-processed opcode+operand.  
int
FetchSymbolPlusOffset(Address_t *pc, char *Operand, char *Mod1,
    Address_t *Value)
{
  Symbol_t *Symbol;
  Address_t dummyAddress;
  int i, Offset;

  i = GetOctOrDec(Operand, &Offset);
  if (!i)
    {
      IncPc(pc, Offset, Value);
      return (0);
    }
  Value->Invalid = 1;
  Symbol = GetSymbol(Operand);
  if (Symbol == NULL)
    return (1);
  *Value = Symbol->Value;
  i = GetOctOrDec(Mod1, &Offset);
  if (!i)
    {
      if (Block1)
        {
          //IncPc (&Symbol->Value, Offset, Value);
          OpcodeOffset = Offset;
          // I'm not sure how to treat very big offsets.  Empirically, this works.
          if (OpcodeOffset >= 0)
            OpcodeOffset &= 07777;
          else
            OpcodeOffset = -(07777 & -OpcodeOffset);
        }
      else
        {
          PseudoToStruct(Symbol->Value.Value + Offset, &dummyAddress);
          *Value = dummyAddress;
        }
    }
  return (0);
}

//------------------------------------------------------------------------
// Return 0 on success.
int
ParseEquate(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  return (ParseEQUALS(InRecord, OutRecord));
}

int
ParseEQUALS(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  Address_t LabelValue =
    { 1 };
  int Value, i;

  OutRecord->ProgramCounter = InRecord->ProgramCounter;
  OutRecord->EBank = InRecord->EBank;
  OutRecord->SBank = InRecord->SBank;
  OutRecord->LabelValue.Invalid = 1;
  OutRecord->NumWords = 0;
  OutRecord->Equals = 1;

  // As a special case, it sometimes happens that the label is empty.
  // I *believe* that this is done only for documentation purposes, and
  // has no other effect.
  if (*InRecord->Label == 0)
    {
      OutRecord->LabelValueValid = 0;
      return (0);
    }

  // As another special case, there is sometimes no operand.  *That* means
  // that the current program counter is the value.  
  if (*InRecord->Operand == 0 && *InRecord->Mod1 == 0)
    {
      EditSymbolNew(InRecord->Label, &InRecord->ProgramCounter, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
      OutRecord->LabelValue = InRecord->ProgramCounter;
      return (0);
    }

  i = GetOctOrDec(InRecord->Operand, &Value);
  if (i)
    {
      // The operand is NOT a number.  Presumably, it's a symbol.
      if (!strcmp(InRecord->Mod1, "+") || !strcmp(InRecord->Mod1, "-"))
        {
          // Handle the case of whitespace between +/- and the actual offset. 
          if (*InRecord->Mod2 != 0)
            {
              char mod[1 + MAX_LINE_LENGTH];

              strcpy(mod, InRecord->Mod1);
              strcat(mod, InRecord->Mod2);
              i = FetchSymbolPlusOffset(&InRecord->ProgramCounter,
                  InRecord->Operand, mod, &LabelValue);
            }
          else
            {
              sprintf(OutRecord->ErrorMessage,
                  "Syntax error, invalid offset specified");
              OutRecord->Fatal = 1;
              return (0);
            }
        }
      else
        {
          //if (!strcmp(InRecord->Operand, "VPRED"))
          //  {
          //    fprintf(stderr, "Hello\n");
          //  }
          i = FetchSymbolPlusOffset(&InRecord->ProgramCounter,
              InRecord->Operand, InRecord->Mod1, &LabelValue);
        }

      if (i)
        {
          sprintf(OutRecord->ErrorMessage,
              "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
          OutRecord->Fatal = 1;
          return (0);
        }

      if (OpcodeOffset)
        {
          if (LabelValue.Constant)
            {
              LabelValue.Value += OpcodeOffset;
            }
          else
            IncPc(&LabelValue, OpcodeOffset, &LabelValue);
        }

      EditSymbolNew(InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
      OutRecord->LabelValueValid = 1;
    }
  else
    {
      // Next, it may be that the operand is simply a number.  If so, then
      // we're talking about a simple constant.  

      ParseOutput_t TempOutput;

      if (*InRecord->Operand == '+' || *InRecord->Operand == '-')
        {
          IncPc(&InRecord->ProgramCounter, Value, &LabelValue);
        }
      else
        {
          if (Value < -16383 || Value > 32767)
            {
              strcpy(OutRecord->ErrorMessage,
                  "Value out of range---truncating");
              OutRecord->Warning = 1;
              if (Value < -16383)
                Value = -16383;
              else if (Value > 32767)
                Value = 32767;
            }

          if (Raytheon && Value >= 02000 && Value < 04000)
            {
              // For Raytheon builds, shift common-fixed literals into the expected range
              Value += 010000 + InRecord->ProgramCounter.FB * 02000;
            }

          LabelValue.Invalid = 0;
          LabelValue.Constant = 1;
          LabelValue.Value = Value;

          PseudoToSegmented(Value, &TempOutput);

          if (!TempOutput.ProgramCounter.Invalid)
            {
              LabelValue = TempOutput.ProgramCounter;
              if (!strcmp(InRecord->Operator, "ERASE")
                  || (Value >= 02000 && !strcmp(InRecord->Operator, "EQUALS")))
                {
                  // Special case. This is to handle "ERASE start - end" constructs, 
                  // which should not be tagged as constants.
                  LabelValue.Constant = 0;
                }
              else
                {
                  // Otherwise mark it as a constant as well.
                  LabelValue.Constant = 1;
                }
            }
        }

      EditSymbolNew(InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
          CurrentFilename, CurrentLineInFile);
    }

  OutRecord->LabelValue = LabelValue;

  return (0);
}

back to top