/// <summary>
        /// Sets the value of a variable
        /// </summary>
        /// <param name="name">Variable name</param>
        /// <param name="value">Variable value</param>
        public void SetVariable(string name, ExpressionValue value)
        {
            // --- Search for the variable from inside out
            foreach (var scope in CurrentModule.LocalScopes)
            {
                if (scope.Symbols.TryGetValue(name, out var symbolInfo) && symbolInfo.Type == SymbolType.Var)
                {
                    symbolInfo.Value = value;
                    return;
                }
            }

            // --- Check the global scope
            if (CurrentModule.Symbols.TryGetValue(name, out var globalSymbol) &&
                globalSymbol.Type == SymbolType.Var)
            {
                globalSymbol.Value = value;
                return;
            }

            // --- The variable does not exist, create it in the current scope
            var vars = CurrentModule.LocalScopes.Count > 0
                ? CurrentModule.LocalScopes.Peek().Symbols
                : CurrentModule.Symbols;

            vars[name] = AssemblySymbolInfo.CreateVar(name, value);
        }
 /// <summary>
 /// Sets the current value of the symbol to the specified value
 /// </summary>
 /// <param name="symbol">Symbol name</param>
 /// <param name="value">Symbol value</param>
 public void SetSymbolValue(string symbol, ExpressionValue value)
 {
     if (CurrentModule.Symbols.TryGetValue(symbol, out var symbolInfo))
     {
         symbolInfo.Value = value;
     }
     else
     {
         CurrentModule.Symbols.Add(symbol, AssemblySymbolInfo.CreateLabel(symbol, value));
     }
 }
        /// <summary>
        /// Adds a symbol to the current scope
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="value"></param>
        public void AddSymbol(string symbol, ExpressionValue value)
        {
            Dictionary <string, AssemblySymbolInfo> GetSymbols() =>
            CurrentModule.LocalScopes.Count > 0
                    ? CurrentModule.LocalScopes.Peek().Symbols
                    : CurrentModule.Symbols;

            var currentScopeIsTemporary = CurrentModule.LocalScopes.Count != 0 &&
                                          CurrentModule.LocalScopes.Peek().IsTemporaryScope;
            var symbolIsTemporary = symbol.StartsWith("`");

            var lookup = GetSymbols();

            if (currentScopeIsTemporary)
            {
                if (!symbolIsTemporary)
                {
                    // --- Remove the previous temporary scope
                    var tempScope = CurrentModule.LocalScopes.Peek();
                    FixupSymbols(tempScope.Fixups, tempScope.Symbols, false);
                    CurrentModule.LocalScopes.Pop();

                    lookup = GetSymbols();
                }
            }
            else
            {
                // --- Create a new temporary scope
                CurrentModule.LocalScopes.Push(new SymbolScope()
                {
                    IsTemporaryScope = true
                });
                if (symbolIsTemporary)
                {
                    // --- Temporary symbol should go into the new temporary scope
                    lookup = GetSymbols();
                }
            }
            lookup.Add(symbol, AssemblySymbolInfo.CreateLabel(symbol, value));
        }
        /// <summary>
        /// Tries to create fixups in the specified scope
        /// </summary>
        /// <param name="fixups">Fixup entries in the scope</param>
        /// <param name="symbols">Symbols in the scope</param>
        /// <param name="signNotEvaluable">Raise error if the symbol is not evaluable</param>
        /// <returns></returns>
        private bool FixupSymbols(IReadOnlyCollection <FixupEntry> fixups,
                                  IDictionary <string, AssemblySymbolInfo> symbols,
                                  bool signNotEvaluable)
        {
            // --- #1: fix the .equ values
            var success = true;

            foreach (var equ in fixups.Where(f => f.Type == FixupType.Equ && !f.Resolved))
            {
                if (EvaluateFixupExpression(equ, false, signNotEvaluable, out var value))
                {
                    if (symbols.TryGetValue(equ.Label, out var symbolInfo))
                    {
                        symbolInfo.Value = value;
                    }
                    else
                    {
                        symbols.Add(equ.Label, AssemblySymbolInfo.CreateLabel(equ.Label, value));
                    }
                }
                else
                {
                    success = false;
                }
            }

            // --- #2: fix Bit8, Bit16, Jr, Ent, Xent
            foreach (var fixup in fixups.Where(f => !f.Resolved &&
                                               (f.Type == FixupType.Bit8 || f.Type == FixupType.Bit16 || f.Type == FixupType.Jr ||
                                                f.Type == FixupType.Ent || f.Type == FixupType.Xent)))
            {
                if (EvaluateFixupExpression(fixup, true, signNotEvaluable, out var value))
                {
                    var segment     = Output.Segments[fixup.SegmentIndex];
                    var emittedCode = segment.EmittedCode;
                    switch (fixup.Type)
                    {
                    case FixupType.Bit8:
                        emittedCode[fixup.Offset] = value.AsByte();
                        break;

                    case FixupType.Bit16:
                        emittedCode[fixup.Offset]     = value.AsByte();
                        emittedCode[fixup.Offset + 1] = (byte)(value.AsWord() >> 8);
                        break;

                    case FixupType.Jr:
                        // --- Check for Relative address
                        var currentAssemblyAddress = segment.StartAddress
                                                     + (segment.Displacement ?? 0)
                                                     + fixup.Offset;
                        var dist = value.AsWord() - (currentAssemblyAddress + 2);
                        if (dist < -128 || dist > 127)
                        {
                            ReportError(Errors.Z0022, fixup.SourceLine, dist);
                            success = false;
                            break;
                        }
                        emittedCode[fixup.Offset + 1] = (byte)dist;
                        break;

                    case FixupType.Ent:
                        Output.EntryAddress = value.AsWord();
                        break;

                    case FixupType.Xent:
                        Output.ExportEntryAddress = value.AsWord();
                        break;
                    }
                }
                else
                {
                    success = false;
                }
            }

            // --- #3: fix Struct
            foreach (var fixup in fixups.Where(f => !f.Resolved && f.Type == FixupType.Struct))
            {
                var segment     = Output.Segments[fixup.SegmentIndex];
                var emittedCode = segment.EmittedCode;

                // --- Override structure bytes
                foreach (var entry in fixup.StructBytes)
                {
                    var offset = (ushort)(fixup.Offset + entry.Key);
                    emittedCode[offset] = entry.Value;
                }
            }

            // --- #4: fix FieldBit8, and FieldBit16
            foreach (var fixup in fixups.Where(f => !f.Resolved &&
                                               (f.Type == FixupType.FieldBit8 || f.Type == FixupType.FieldBit16)))
            {
                if (EvaluateFixupExpression(fixup, true, signNotEvaluable, out var value))
                {
                    var segment     = Output.Segments[fixup.SegmentIndex];
                    var emittedCode = segment.EmittedCode;

                    switch (fixup.Type)
                    {
                    case FixupType.FieldBit8:
                        emittedCode[fixup.Offset] = value.AsByte();
                        break;

                    case FixupType.FieldBit16:
                        emittedCode[fixup.Offset]     = value.AsByte();
                        emittedCode[fixup.Offset + 1] = (byte)(value.AsWord() >> 8);
                        break;
                    }
                }
                else
                {
                    success = false;
                }
            }
            return(success);
        }
        /// <summary>
        /// Adds a symbol to the current scope
        /// </summary>
        /// <param name="symbol"></param>
        /// <param name="line">Assembly line</param>
        /// <param name="value"></param>
        public void AddSymbol(string symbol, SourceLineBase line, ExpressionValue value)
        {
            Dictionary <string, AssemblySymbolInfo> GetSymbols() =>
            CurrentModule.LocalScopes.Count > 0
                    ? CurrentModule.LocalScopes.Peek().Symbols
                    : CurrentModule.Symbols;

            if (symbol == "__SET_ATTR2")
            {
                var x = 1;
            }
            var currentScopeIsTemporary = CurrentModule.LocalScopes.Count != 0 &&
                                          CurrentModule.LocalScopes.Peek().IsTemporaryScope;
            var symbolIsTemporary = symbol.StartsWith("`");

            var lookup = GetSymbols();

            if (currentScopeIsTemporary)
            {
                if (!symbolIsTemporary)
                {
                    // --- Remove the previous temporary scope
                    var tempScope = CurrentModule.LocalScopes.Peek();
                    FixupSymbols(tempScope.Fixups, tempScope.Symbols, false);
                    CurrentModule.LocalScopes.Pop();

                    lookup = GetSymbols();
                }
            }
            else
            {
                // --- Create a new temporary scope
                CurrentModule.LocalScopes.Push(new SymbolScope {
                    IsTemporaryScope = true
                });
                if (symbolIsTemporary)
                {
                    // --- Temporary symbol should go into the new temporary scope
                    lookup = GetSymbols();
                }
            }

            if (CurrentModule.LocalScopes.Count > 0)
            {
                // --- We are in a local scope, get the next non-temporary scope
                var localScopes = CurrentModule.LocalScopes;
                var scope       = localScopes.Peek();
                if (scope.IsTemporaryScope)
                {
                    var tmpScope = localScopes.Pop();
                    scope = localScopes.Count > 0 ? localScopes.Peek() : null;
                    localScopes.Push(tmpScope);
                }

                if (scope?.LocalSymbolBookings.Count > 0)
                {
                    // --- We already booked local symbols
                    if (!scope.LocalSymbolBookings.Contains(symbol))
                    {
                        lookup = CurrentModule.Symbols;
                    }
                }
                else
                {
                    if (_options.ProcExplicitLocalsOnly)
                    {
                        lookup = CurrentModule.Symbols;
                    }
                }
            }

            // --- Check for already defined symbols
            if (lookup.TryGetValue(symbol, out var symbolInfo) && symbolInfo.Type == SymbolType.Label)
            {
                ReportError(Errors.Z0040, line, symbol);
                return;
            }

            lookup.Add(symbol, AssemblySymbolInfo.CreateLabel(symbol, value));
        }