Beispiel #1
0
int
FetchSymbolPlusOffset (Address_t *pc, char *Operand, char *Mod1,
                       Address_t *Value)
{
    Symbol_t *Symbol;
    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)
    {
        //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);
    }
    return (0);
}
Beispiel #2
0
int Parse2OCT(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
    char *s;
    int Value = 0;
    int Value1 = 0;
    int Value2 = 0;

    IncPc(&InRecord->ProgramCounter, 2, &OutRecord->ProgramCounter);
    if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow) {
        strcpy(OutRecord->ErrorMessage, "Next code may overflow storage.");
        OutRecord->Warning = 1;
    }

    OutRecord->EBank = InRecord->EBank;
    OutRecord->SBank = InRecord->SBank;
    OutRecord->Words[0] = ILLEGAL_SYMBOL_VALUE;
    OutRecord->NumWords = 2;

    s = InRecord->Operand;

    if (*s == '+' || *s == '-')
        s++;
    for (; *s; s++)
        if (*s < '0' || *s > '7')
            break;

    if (!*s && s != InRecord->Operand) {
        int Minus;

        Minus = 0;
        if (InRecord->Operand[0] == '-')
            Minus = 1;

        if (sscanf(&InRecord->Operand[Minus], "%o", &Value1) == 1) {
            if (sscanf(InRecord->Mod1, "%o", &Value2) == 1) {
                Value = ((Value1 & 077777) << 15) | (Value2 & 077777);
            } else {
                Value = (Value1 & 07777777777);
            }
            if ((Value & ~07777777777) != 0) {
                Value &= 07777777777;
                strcpy(OutRecord->ErrorMessage, "Value out of range.");
                OutRecord->Warning = 1;
            }
            if (Minus)
                Value = ~Value;
            OutRecord->Words[0] = 077777 & (Value >> 15);
            OutRecord->Words[1] = 077777 & Value;
        }
    } else {
Beispiel #3
0
//-------------------------------------------------------------------------
// Returns non-zero on unrecoverable error  We don't do a heckuva lot of 
// error-checking in this version.
int ParseOCT(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
    char *s;
    int Value;

    IncPc(&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
    if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow) {
        strcpy(OutRecord->ErrorMessage, "Next code may overflow storage.");
        OutRecord->Warning = 1;
    }

    OutRecord->EBank = InRecord->EBank;
    OutRecord->SBank = InRecord->SBank;
    OutRecord->Words[0] = ILLEGAL_SYMBOL_VALUE;
    OutRecord->NumWords = 1;

    s = InRecord->Operand;
    if (*s == '+' || *s == '-')
        s++;
    for (; *s; s++)
        if (*s < '0' || *s > '7')
            break;

    if (!*s && s != InRecord->Operand) {
        int Minus;

        Minus = 0;
        if (InRecord->Operand[0] == '-')
            Minus = 1;

        if (sscanf(&InRecord->Operand[Minus], "%o", &Value) == 1) {
            if ((Value & ~077777) != 0) {
                Value &= 077777;
                strcpy(OutRecord->ErrorMessage, "Value out of range.");
                OutRecord->Warning = 1;
            }
            if (Minus)
                Value = ~Value;
            OutRecord->Words[0] = Value;
        }
    } else {
        strcpy (OutRecord->ErrorMessage, "Not an octal number.");
        OutRecord->Fatal = 1;
    }    
    return (0);
}
Beispiel #4
0
//------------------------------------------------------------------------
// Return non-zero on unrecoverable error.
int ParseINDEX(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  Address_t Offset;
  int Value, i;
  //extern int KeepExtend;
  
  //KeepExtend = 1;
  OutRecord->Extend = InRecord->Extend;
  IncPc(&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
  if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow)
    {
      strcpy(OutRecord->ErrorMessage, "Next code may overflow storage.");
      OutRecord->Warning = 1;
    }

  OutRecord->EBank = InRecord->EBank;
  OutRecord->SBank = InRecord->SBank;
  OutRecord->NumWords = 1;
  OutRecord->IndexValid = 1;

  i = GetOctOrDec(InRecord->Operand, &Value);
  if (!i)
    {
      if (*InRecord->Operand == '+' || *InRecord->Operand == '-')
	  IncPc(&InRecord->ProgramCounter, Value, &Offset);
      else
          PseudoToStruct(Value, &Offset);
	
       if (*InRecord->Mod1 != 0)
         {
	   i = GetOctOrDec(InRecord->Mod1, &Value);
	   if (!i)
	     OpcodeOffset = Value;
	 }
      
    DoIt:  
      if (!Offset.Address && !Offset.Constant)
        {
	  strcpy(OutRecord->ErrorMessage, "Index is not an address.");
	  Offset.SReg = 0;
	  OutRecord->Fatal = 1;
	}

      if ((InRecord->Extend && (Offset.SReg & ~07777)) || (!InRecord->Extend && (Offset.SReg & ~01777)))
        {
	  strcpy(OutRecord->ErrorMessage, "Index is out of range.");
	  Offset.SReg = 0;
	  OutRecord->Fatal = 1;
	}

      if (Offset.Constant)
        OutRecord->Words[0] = OPCODE + Offset.Value;
      else
        OutRecord->Words[0] = OPCODE + Offset.SReg;
    }
  else
    {
      // The operand is NOT a number.  Presumably, it's a symbol.
      i = FetchSymbolPlusOffset(&InRecord->ProgramCounter, InRecord->Operand, InRecord->Mod1, &Offset);
      if (!i)
        goto DoIt;
      sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
      OutRecord->Fatal = 1;
      OutRecord->Words[0] = OPCODE;
    }

  if (OutRecord->Words[0] == 050017)
    OutRecord->IndexValid = 0;

  return (0);  
}
Beispiel #5
0
int 
ParseERASE (ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  int Value, i;
  IncPc (&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
  if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow)
    {
      strcpy (OutRecord->ErrorMessage, "Next code may overflow storage.");
      OutRecord->Warning = 1;
    }
  OutRecord->Bank = InRecord->Bank;
  if (InRecord->Extend && !InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by EXTEND.");
      OutRecord->Fatal = 1;
      OutRecord->Extend = 0;
    }
  if (InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by INDEX.");
      OutRecord->Fatal = 1;
      OutRecord->IndexValid = 0;
    }
  i = GetOctOrDec (InRecord->Operand, &Value);
  if (!i)
    {
      if (Value < 0)
        {
	  strcpy (OutRecord->ErrorMessage, "Address increment is negative.");
	  OutRecord->Warning = 1;
	}	
      else
        {
	  // There are really two cases here.  Normally, the operand is
	  // simply a number, and that's the end of it.  But it's also
	  // possible that Mod1 is "-", and Mod2 is another number, in 
	  // which case we want to allocate a range.
	  if (!strcmp (InRecord->Mod1, "-"))
	    {
#if 0
	      // This is the range case, "ERASE n - m".
	      i = GetOctOrDec (InRecord->Mod2, &Value2);
	      Value2++;
	      if (i)
	        {
		  strcpy (OutRecord->ErrorMessage, "End of range missing or illegal.");
		  OutRecord->Fatal = 1;
		}
	      else if (Value2 <= Value)
	        {
		  strcpy (OutRecord->ErrorMessage, "Ending address precedes starting address.");
		  OutRecord->Fatal = 1;
		}	
	      else
	        {
		  ParseOutput_t Dummy = { { 0 } }, Dummy2 = { { 0 } };
		  PseudoToSegmented (Value, &Dummy);
		  PseudoToSegmented (Value2, &Dummy2);
		  if (Dummy.Fatal || Dummy.Warning || Dummy2.Fatal || Dummy2.Warning
		      || Dummy.ProgramCounter.Invalid || !Dummy.ProgramCounter.Erasable
		      || Dummy2.ProgramCounter.Invalid || !Dummy2.ProgramCounter.Erasable
		      || Dummy.ProgramCounter.Banked != Dummy2.ProgramCounter.Banked
		      || Dummy.ProgramCounter.EB != Dummy2.ProgramCounter.EB)
		    {
		      strcpy (OutRecord->ErrorMessage, "May span bank boundary.");
		      OutRecord->Warning = 1;
		    }
		  InRecord->ProgramCounter = Dummy.ProgramCounter;
		  OutRecord->ProgramCounter = Dummy2.ProgramCounter;
		}
#else // 0
  		  char Mod1[1 + MAX_LINE_LENGTH], Mod2[1 + MAX_LINE_LENGTH];
		  strcpy (Mod1, InRecord->Mod1);
		  strcpy (Mod2, InRecord->Mod2);
		  strcpy (InRecord->Mod1, "");
		  strcpy (InRecord->Mod2, "");  
		  strcpy (InRecord->Operator, "EQUALS");            
		  ParseEQUALS (InRecord, OutRecord);
		  strcpy (InRecord->Mod1, Mod1);
		  strcpy (InRecord->Mod2, Mod2);
		  strcpy (InRecord->Operator, "ERASE");
#endif // 0
	    }
	  else
	    {  
	      // This is the normal case, "ERASE n".
	      if (0 != *InRecord->Mod1 && !OutRecord->Fatal)
	        {
		  strcpy (OutRecord->ErrorMessage, "Extra fields are present.");
		  OutRecord->Warning = 1;
		}
	      IncPc (&InRecord->ProgramCounter, 1 + Value, &OutRecord->ProgramCounter);
	      if (!OutRecord->ProgramCounter.Invalid)
		{
		  if (!OutRecord->ProgramCounter.Erasable)
		    {
		      strcpy (OutRecord->ErrorMessage, "Not in erasable memory.");
		      OutRecord->Fatal = 1;
		    }
		  else if (OutRecord->ProgramCounter.Overflow)
		    {
		      strcpy (OutRecord->ErrorMessage, "May overflow memory bank.");
		      OutRecord->Warning = 1;
		    }
		}
	    }
	}
    }
  else if (0 != *InRecord->Operand)
    {
      // Note that if the Operand field is simply missing, it's legal.
      strcpy (OutRecord->ErrorMessage, "Illegal number.");
      OutRecord->Fatal = 1;
    }  
  return (0);  
}
Beispiel #6
0
int
ParseBBCON (ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  Address_t Address, EBank;
  int Value, i;
  IncPc (&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
  if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow)
    {
      strcpy (OutRecord->ErrorMessage, "Next code may overflow storage.");
      OutRecord->Warning = 1;
    }
  OutRecord->Bank = InRecord->Bank;
  OutRecord->NumWords = 1;
  OutRecord->Words[0] = 0;
  if (InRecord->Extend && !InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by EXTEND.");
      OutRecord->Fatal = 1;
      OutRecord->Extend = 0;
    }
  if (InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by INDEX.");
      OutRecord->Fatal = 1;
      OutRecord->IndexValid = 0;
    }
  #ifdef ORIGINAL_SBANK_SURMISE
  if (!strcmp (InRecord->Operator, "BBCON*"))
    {
      OutRecord->Words[0] = 066100;
      OutRecord->Bank.CurrentSBank.Super = 1;
      return (0);
    }
  #endif
  i = GetOctOrDec (InRecord->Operand, &Value);
  if (!i && *InRecord->Mod1 == 0)
    {
      IncPc (&InRecord->ProgramCounter, Value, &Address);
    DoIt:  
      if (Address.Invalid)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination address not resolved.");
	  OutRecord->Fatal = 1;
	  return (0);
	}
      if (!Address.Address)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination is not a memory address.");
	  OutRecord->Fatal = 1;
	  return (0);
	}
      if (!Address.Fixed)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination is not in fixed memory.");
	  OutRecord->Fatal = 1;
	  return (0);
	}	
      if (Address.SReg < 02000 || Address.SReg > 07777)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination address out of range.");
	  OutRecord->Fatal = 1;
	  return (0);
	}	
      //printf ("PC=%o EB=%o,%o FB=%o SReg=%o Super=%o,%o ", 
      //        InRecord->ProgramCounter.SReg, Address.EB, InRecord->Bank.CurrentEBank.EB,
      //      Address.FB, Address.SReg,
      //      Address.Super, InRecord->Bank.CurrentSBank.Super);
      if (!Address.Banked)
        Address.Value = Address.SReg / 02000;
      else 
        Address.Value = Address.FB;
      EBank = InRecord->Bank.CurrentEBank;
      if (EBank.SReg >= 0 && EBank.SReg < 01400)
        EBank.EB = EBank.SReg / 0400;
      Address.Value = (Address.Value << 10) | EBank.EB;
      // Superbank processing.
      FixSuperbankBits (InRecord, &Address, &Address.Value);
      OutRecord->Words[0] = Address.Value;	
    }
  else
    {
      // The operand is NOT a number.  Presumably, it's a symbol.
      i = FetchSymbolPlusOffset (&InRecord->ProgramCounter, 
                                 InRecord->Operand, 
				 InRecord->Mod1, &Address);
      if (!i)
        goto DoIt;
      sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
      OutRecord->Fatal = 1;
    }
  return (0);  
}
Beispiel #7
0
int
ParseEQUALS (ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
    Address_t LabelValue = { 1 };
    int Value, i;
    OutRecord->ProgramCounter = InRecord->ProgramCounter;
    OutRecord->Bank = InRecord->Bank;
    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)
    {
        // JMS: Even though it is assigned the program counter as the current
        // value, it is still just a constant
        //EditSymbol (InRecord->Label, &InRecord->ProgramCounter);
        EditSymbolNew (InRecord->Label, &InRecord->ProgramCounter, SYMBOL_CONSTANT,
                       CurrentFilename, CurrentLineInFile);
        OutRecord->LabelValue = InRecord->ProgramCounter;
        return (0);
    }
    // Next, it may be that the operand is simply a number.  If so, then
    // we're talking about a simple constant.
    i = GetOctOrDec (InRecord->Operand, &Value);
    if (i)
    {
        // The operand is NOT a number.  Presumably, it's a symbol.
        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 0
        if (!i)
        {
            LabelValue = CONSTANT (0);
            LabelValue.Value = Value;
            EditSymbol (InRecord->Label, &LabelValue);
        }
#endif
        if (OpcodeOffset)
        {
            if (LabelValue.Constant)
            {
                LabelValue.Value += OpcodeOffset;
            }
            else
                IncPc (&LabelValue, OpcodeOffset, &LabelValue);
        }

        // JMS: This is just a constant to add to the symbol table
        //EditSymbol (InRecord->Label, &LabelValue);
        EditSymbolNew (InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
                       CurrentFilename, CurrentLineInFile);
        OutRecord->LabelValueValid = 1;
    }
    else
    {
        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;
            }
            LabelValue.Invalid = 0;
            LabelValue.Constant = 1;
            LabelValue.Value = Value;
            PseudoToSegmented (Value, &TempOutput);
        }

        // JMS: This is just a constant to add to the symbol table
        //EditSymbol (InRecord->Label, &LabelValue /*&TempOutput.ProgramCounter*/);
        EditSymbolNew (InRecord->Label, &LabelValue, SYMBOL_CONSTANT,
                       CurrentFilename, CurrentLineInFile);
    }
    OutRecord->LabelValue = LabelValue;
    return (0);
}
Beispiel #8
0
//-------------------------------------------------------------------------
// Returns non-zero on unrecoverable error.
int ParseEBANKEquals(ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
    ParseOutput_t Dummy;
    Address_t Address;
    int Value, i;

    OutRecord->Extend = InRecord->Extend;
    OutRecord->IndexValid = InRecord->IndexValid;
    OutRecord->EBank = InRecord->EBank;
    OutRecord->SBank = InRecord->SBank;
    OutRecord->NumWords = 0;
    OutRecord->ProgramCounter = InRecord->ProgramCounter;

    if (*InRecord->Mod1) {
        strcpy(OutRecord->ErrorMessage, "Extra fields.");
        OutRecord->Warning = 1;
    }

    i = GetOctOrDec(InRecord->Operand, &Value);
    if (!i) {
        PseudoToSegmented(Value, &Dummy);
        Address = Dummy.ProgramCounter;

        DoIt:
        if (Address.Invalid) {
            strcpy(OutRecord->ErrorMessage, "Destination address not resolved.");
            OutRecord->Fatal = 1;
            return (0);
        }

        if (!Address.Erasable) {
            strcpy(OutRecord->ErrorMessage, "Destination not erasable.");
            OutRecord->Fatal = 1;
            return (0);
        }

        if (Address.SReg < 0 || Address.SReg > 01777) {
            strcpy(OutRecord->ErrorMessage, "Destination address out of range.");
            OutRecord->Fatal = 1;
            return (0);
        }

        OutRecord->EBank.last = OutRecord->EBank.current;
        OutRecord->EBank.current = Address;
        OutRecord->EBank.oneshotPending = 1;
        OutRecord->LabelValue = Address;
        OutRecord->LabelValueValid = 1;
    } else {
        // The operand is NOT a number.  Presumably, it's a symbol.
        i = FetchSymbolPlusOffset(&InRecord->ProgramCounter, InRecord->Operand, "", &Address);
        if (!i) {
            IncPc(&Address, OpcodeOffset, &Address);
            goto DoIt;
        }

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

#ifdef YAYUL_TRACE
    PrintTrace(InRecord, OutRecord);
#endif

    return (0);
}
Beispiel #9
0
int
ParseCADR (ParseInput_t *InRecord, ParseOutput_t *OutRecord)
{
  Address_t Address;
  int Value, i;
  IncPc (&InRecord->ProgramCounter, 1, &OutRecord->ProgramCounter);
  if (!OutRecord->ProgramCounter.Invalid && OutRecord->ProgramCounter.Overflow)
    {
      strcpy (OutRecord->ErrorMessage, "Next code may overflow storage.");
      OutRecord->Warning = 1;
    }
  OutRecord->Bank = InRecord->Bank;
  OutRecord->NumWords = 1;
  OutRecord->Words[0] = 0;
  if (InRecord->Extend && !InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by EXTEND.");
      OutRecord->Fatal = 1;
      OutRecord->Extend = 0;
    }
  if (InRecord->IndexValid)
    {
      strcpy (OutRecord->ErrorMessage, "Illegally preceded by INDEX.");
      OutRecord->Fatal = 1;
      OutRecord->IndexValid = 0;
    }
  i = GetOctOrDec (InRecord->Operand, &Value);
  if (!i && *InRecord->Mod1 == 0)
    {
      IncPc (&InRecord->ProgramCounter, Value, &Address);
    DoIt:  
      if (Address.Invalid)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination address not resolved.");
	  OutRecord->Fatal = 1;
	  return (0);
	}
      if (!Address.Address)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination is not a memory address.");
	  OutRecord->Fatal = 1;
	  return (0);
	}
      if (!Address.Fixed || !Address.Banked)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination not in an F-bank.");
	  OutRecord->Fatal = 1;
	  return (0);
	}	
      // If this is a superbank, we massage a little more to get into the 15-bit
      // address range.
      if (Address.Super && Address.FB >= 030)
        Address.Value -= 010 * 02000;
      if (Address.Value < 010000 || Address.Value > 0107777)
        {
	  strcpy (OutRecord->ErrorMessage, "Destination address out of range.");
	  OutRecord->Fatal = 1;
	  return (0);
	}	
      OutRecord->Words[0] = Address.Value - 010000;	
    }
  else
    {
      // The operand is NOT a number.  Presumably, it's a symbol.
      i = FetchSymbolPlusOffset (&InRecord->ProgramCounter, 
                                 InRecord->Operand, 
				 InRecord->Mod1, &Address);
      if (!i)
        goto DoIt;
      sprintf(OutRecord->ErrorMessage, "Symbol \"%s\" undefined or offset bad", InRecord->Operand);
      OutRecord->Fatal = 1;
    }
  return (0);  
}
Beispiel #10
0
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
      {
          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;  
            }

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

          PseudoToSegmented(Value, &TempOutput);

          if (!TempOutput.ProgramCounter.Invalid)
            {
              LabelValue = TempOutput.ProgramCounter;
              if (!strcmp(InRecord->Operator, "ERASE"))
                {
                  // 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);  
}