/// <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)); }