diff --git a/Core6502DotNet.sln b/Core6502DotNet.sln
index c6fb68d..f535774 100644
--- a/Core6502DotNet.sln
+++ b/Core6502DotNet.sln
@@ -33,7 +33,7 @@ Global
SolutionGuid = {9BE7575F-6E99-4243-AEAA-4D1E1064DA97}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
- version = 2.8.0.1
+ version = 2.8.1.1
Policies = $0
$0.VersionControlPolicy = $1
$1.CommitMessageStyle = $2
diff --git a/Core6502DotNet/Core6502DotNet.csproj b/Core6502DotNet/Core6502DotNet.csproj
index 872de6e..07254d5 100644
--- a/Core6502DotNet/Core6502DotNet.csproj
+++ b/Core6502DotNet/Core6502DotNet.csproj
@@ -4,7 +4,7 @@
Exe
net5.0
6502.Net
- 2.8.0.1
+ 2.8.1.1
informedcitizenry
informedcitizenry
6502.Net
@@ -13,8 +13,8 @@
2.4.1
Core6502DotNet.Program
6502.Net
- 2.8.0.1
- 2.8.0.1
+ 2.8.1.1
+ 2.8.1.1
false
https://github.com/informedcitizenry/6502.Net
diff --git a/Core6502DotNet/src/Core/AssembleErrorHandler.cs b/Core6502DotNet/src/Core/AssembleErrorHandler.cs
index 4b3718f..b777416 100644
--- a/Core6502DotNet/src/Core/AssembleErrorHandler.cs
+++ b/Core6502DotNet/src/Core/AssembleErrorHandler.cs
@@ -75,7 +75,10 @@ public void HandleError(object sender, AssemblyErrorEventArgs args)
}
else if (args.Exception is BlockClosureException blockEx)
{
- _services.Log.LogEntry(blockEx.LineExpectingClosure.Instruction, blockEx.Message);
+ if (blockEx.LineExpectingClosure.Instruction != null)
+ _services.Log.LogEntry(blockEx.LineExpectingClosure.Instruction, blockEx.Message);
+ else
+ _services.Log.LogEntry(blockEx.LineExpectingClosure, 1, blockEx.Message);
}
else
{
diff --git a/Core6502DotNet/src/Core/Assembler.cs b/Core6502DotNet/src/Core/Assembler.cs
index b94b212..d318d39 100644
--- a/Core6502DotNet/src/Core/Assembler.cs
+++ b/Core6502DotNet/src/Core/Assembler.cs
@@ -18,8 +18,7 @@ public static class Assembler
#region Properties
///
- /// Gets the version of the assembler. This can and should be set
- /// by the client code.
+ /// Gets the version of the assembler.
///
public static string AssemblerVersion
{
@@ -31,8 +30,20 @@ public static string AssemblerVersion
}
///
- /// Gets the assembler (product) name. This can and should be set
- /// by the client code.
+ /// Gets the assembly product summary, including simple name and version.
+ ///
+ public static string ProductSummary
+ {
+ get
+ {
+ var product = Assembly.GetEntryAssembly().GetName();
+ return $"{product.Name} Version {product.Version}";
+ }
+ }
+
+
+ ///
+ /// Gets the assembler (product) name.
///
public static string AssemblerName
{
diff --git a/Core6502DotNet/src/Core/AssemblerBase.cs b/Core6502DotNet/src/Core/AssemblerBase.cs
index 86b9a8f..ac06db9 100644
--- a/Core6502DotNet/src/Core/AssemblerBase.cs
+++ b/Core6502DotNet/src/Core/AssemblerBase.cs
@@ -87,6 +87,7 @@ public string Assemble(RandomAccessIterator lines)
var first = lines.Current;
bool isSpecial = first.Label != null && first.Label.IsSpecialOperator();
LogicalPCOnAssemble = Services.Output.LogicalPC;
+ LongLogicalPCOnAssemble = Services.Output.LongLogicalPC;
PCOnAssemble = Services.Output.ProgramCounter;
LongPCOnAssemble = Services.Output.LongProgramCounter;
if (first.Label != null && !first.Label.Name.Equals("*"))
@@ -193,6 +194,12 @@ protected void DefineLabel(Token label, double address, bool setLocalScope)
///
protected int LogicalPCOnAssemble { get; private set; }
+ ///
+ /// Gets the state of the long Logical Program Counter for the 's
+ /// object when OnAssemble was invoked.
+ ///
+ protected int LongLogicalPCOnAssemble { get; private set; }
+
///
/// Gets the state of the real Program Counter for the 's
/// object when OnAssemble was invoked.
diff --git a/Core6502DotNet/src/Core/AssemblyController.cs b/Core6502DotNet/src/Core/AssemblyController.cs
index 0a19798..0a38c2a 100644
--- a/Core6502DotNet/src/Core/AssemblyController.cs
+++ b/Core6502DotNet/src/Core/AssemblyController.cs
@@ -150,11 +150,10 @@ public double Assemble()
else
{
var passedArgs = _services.Options.GetPassedArgs();
- var exec = Process.GetCurrentProcess().MainModule.ModuleName;
var inputFiles = string.Join("\n// ", preprocessor.GetInputFiles());
- var fullDisasm = $"// {Assembler.AssemblerNameSimple}\n" +
- $"// {exec} {string.Join(' ', passedArgs)}\n" +
- $"// {DateTime.Now:f}\n\n// Input files:\n\n" +
+ var fullDisasm = $"// {Assembler.ProductSummary}\n" +
+ $"// Options: {string.Join(' ', passedArgs)}\n" +
+ $"// {DateTime.Now:f}\n// Input files:\n\n" +
$"// {inputFiles}\n\n" + disassembly;
byteCount = WriteOutput(fullDisasm);
if (!_services.Options.NoWarnings && _services.Log.HasWarnings)
diff --git a/Core6502DotNet/src/Core/AssemblyServices.cs b/Core6502DotNet/src/Core/AssemblyServices.cs
index d8861e7..c3b0f04 100644
--- a/Core6502DotNet/src/Core/AssemblyServices.cs
+++ b/Core6502DotNet/src/Core/AssemblyServices.cs
@@ -33,7 +33,7 @@ public AssemblyServices(Options options)
OutputFormat = Options.Format ?? string.Empty;
CPU = Options.CPU;
Encoding = new AsmEncoding(Options.CaseSensitive);
- Evaluator = new Evaluator(Options.CaseSensitive) { SymbolEvaluator = EvaluateSymbol };
+ Evaluator = new Evaluator(Options.CaseSensitive) { UnknownValueEvaluator = EvaluateUnknownOperand };
SymbolManager = new SymbolManager(options.CaseSensitive, Evaluator);
Log = new ErrorLog(Options.WarningsAsErrors);
Output = new BinaryOutput(true, Options.CaseSensitive, Options.LongAddressing);
@@ -43,17 +43,20 @@ public AssemblyServices(Options options)
#region Methods
- double EvaluateSymbol(RandomAccessIterator tokens)
+ double EvaluateUnknownOperand(RandomAccessIterator tokens)
{
var token = tokens.Current;
- var subscript = -1;
+ var subscript = -1.0;
var converted = double.NaN;
var isString = token.IsDoubleQuote();
if (char.IsLetter(token.Name[0]) || token.Name[0] == '_')
{
- var next = tokens.GetNext();
- if (next != null && next.IsOpen() && next.Name.Equals("["))
- subscript = (int)Evaluator.Evaluate(tokens, 0, int.MaxValue);
+ var next = tokens.PeekNext();
+ if (next?.IsOpen() == true && next.Name.Equals("["))
+ {
+ tokens.MoveNext();
+ subscript = Evaluator.Evaluate(tokens, 0, int.MaxValue);
+ }
var symbol = SymbolManager.GetSymbol(token, CurrentPass > 0);
if (symbol == null)
{
@@ -71,15 +74,16 @@ public AssemblyServices(Options options)
}
if (subscript >= 0)
{
- if (symbol.StorageType != StorageType.Vector)
- throw new SyntaxException(token.Position, "Type mismatch.");
- if ((symbol.IsNumeric && subscript >= symbol.NumericVector.Count) ||
- (!symbol.IsNumeric && subscript >= symbol.StringVector.Count))
- throw new SyntaxException(token.Position, "Index was out of range.");
- if (symbol.IsNumeric)
- return symbol.NumericVector[subscript];
- token = new Token(symbol.StringVector[subscript], TokenType.Operand);
- isString = true;
+ StringView tokenStringValue = "";
+ double tokenValue = double.NaN;
+ isString = symbol.DataType == DataType.String && symbol.StorageType == StorageType.Vector;
+ Symbol.AccessResult result = isString ? symbol.TryGetElementAt(subscript, out tokenStringValue) :
+ symbol.TryGetElementAt(subscript, out tokenValue);
+ if (result != Symbol.AccessResult.Success)
+ throw new ExpressionException(next, SymbolManager.GetErrorMessageFromGetResult(result));
+ if (!isString)
+ return tokenValue;
+ token = new Token(tokenStringValue, TokenType.Operand);
}
else if (symbol.IsNumeric)
{
diff --git a/Core6502DotNet/src/Core/BinaryOutput.cs b/Core6502DotNet/src/Core/BinaryOutput.cs
index fdb1fd3..03994ba 100644
--- a/Core6502DotNet/src/Core/BinaryOutput.cs
+++ b/Core6502DotNet/src/Core/BinaryOutput.cs
@@ -166,7 +166,7 @@ public static int GetAlignmentSize(int pc, int amount)
/// The byte string converted.
public IEnumerable ConvertToBytes(double value)
{
- var bytes = BitConverter.GetBytes(Convert.ToInt64(value)).ToList();
+ var bytes = BitConverter.GetBytes((long)value).ToList();
int nonZero;
if (value < 0)
nonZero = bytes.FindLastIndex(b => b != 255);
@@ -420,8 +420,8 @@ public void AddBytes(IEnumerable bytes, int size, bool ignoreEndian)
}
_logicalPc = (_logicalPc + size) % BufferSize;
- if (ProgramEnd < ((_blocks << 16) | ProgramCounter))
- ProgramEnd = (_blocks << 16) | ProgramCounter;
+ if (ProgramEnd < LongProgramCounter)
+ ProgramEnd = LongProgramCounter;
if (_sectionCollection.SectionSelected)
_sectionCollection.SetOutputCount(_pc - _sectionCollection.SelectedStartAddress);
}
@@ -502,12 +502,12 @@ public int GetRelativeOffset(int address1, int offsetfromPc)
/// The set of bytes from the specified start address to Program End.
public ReadOnlyCollection GetBytesFrom(int start)
{
- if (!_compilingStarted || ((_blocks << 16) | ProgramCounter) < ProgramStart)
+ if (!_compilingStarted || LongProgramCounter < ProgramStart)
return new List().AsReadOnly();
- if ((ProgramCounter & MaxAddress) != _logicalPc)
+ if (LongProgramCounter != LongLogicalPC)
{
- var diff = _logicalPc - start;
- start = ProgramCounter - diff;
+ var diff = LongLogicalPC - start;
+ start = LongProgramCounter - diff;
}
if (start < ProgramStart || start >= ProgramEnd)
return new List().AsReadOnly();
@@ -755,6 +755,12 @@ private set
///
public int LongProgramCounter => ProgramCounter | (_blocks << 16);
+ ///
+ /// Gets the long logical Program Counter.
+ ///
+ public int LongLogicalPC => _logicalPc | (_blocks << 16);
+
+
///
/// Gets the names of any defined sections not used during
/// assembly.
diff --git a/Core6502DotNet/src/Core/Evaluator.cs b/Core6502DotNet/src/Core/Evaluator.cs
index 9cbad47..aa4df84 100644
--- a/Core6502DotNet/src/Core/Evaluator.cs
+++ b/Core6502DotNet/src/Core/Evaluator.cs
@@ -7,8 +7,8 @@
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
-using System.Text.RegularExpressions;
using ConversionDef = System.Func;
using OperationDef = System.Tuple, double>, int>;
@@ -35,6 +35,19 @@ public IllegalQuantityException(Token token, double quantity)
public double Quantity { get; }
}
+ ///
+ /// An enumeration of possible value types returned in an successful evaluation.
+ ///
+ public enum ValueType
+ {
+ Unknown = 0,
+ Boolean,
+ Binary,
+ Double,
+ Integer
+ }
+
+
///
/// A class that can evaluate strings as mathematical expressions.
///
@@ -58,8 +71,6 @@ public class Evaluator
#region Members
- static readonly Regex s_separators = new Regex(@"\d_\d", RegexOptions.Compiled);
-
static readonly HashSet s_conditionals = new HashSet
{
"||", "&&", "<", "<=", ">", ">=", "==", "!="
@@ -74,37 +85,39 @@ public class Evaluator
static readonly IReadOnlyDictionary s_operators = new Dictionary
{
{ new Token(",", TokenType.Separator), new OperationDef(parms => parms[0], 0) },
- { new Token(">", TokenType.Unary), new OperationDef(parms => ((long)parms[0] & 65535) / 0x100, 1) },
- { new Token("<", TokenType.Unary), new OperationDef(parms => (long)parms[0] & 255, 1) },
- { new Token("&", TokenType.Unary), new OperationDef(parms => (long)parms[0] & 65535, 1) },
- { new Token("^", TokenType.Unary), new OperationDef(parms => ((long)parms[0] & UInt24.MaxValue) / 0x10000, 1) },
- { new Token("||", TokenType.Binary), new OperationDef(parms => ((long)parms[1]!=0?1:0) | ((long)parms[0]!=0?1:0), 2) },
- { new Token("&&", TokenType.Binary), new OperationDef(parms => ((long)parms[1]!=0?1:0) & ((long)parms[0]!=0?1:0), 3) },
- { new Token("|", TokenType.Binary), new OperationDef(parms => (long)parms[1] | (long)parms[0], 4) },
- { new Token("^", TokenType.Binary), new OperationDef(parms => (long)parms[1] ^ (long)parms[0], 5) },
- { new Token("&", TokenType.Binary), new OperationDef(parms => (long)parms[1] & (long)parms[0], 6) },
- { new Token("!=", TokenType.Binary), new OperationDef(parms => !parms[1].AlmostEquals(parms[0])?1:0, 7) },
- { new Token("==", TokenType.Binary), new OperationDef(parms => parms[1].AlmostEquals(parms[0])?1:0, 7) },
- { new Token("<", TokenType.Binary), new OperationDef(parms => parms[1] < parms[0] ? 1 : 0, 8) },
- { new Token("<=", TokenType.Binary), new OperationDef(parms => parms[1] <= parms[0] ? 1 : 0, 8) },
- { new Token(">=", TokenType.Binary), new OperationDef(parms => parms[1] >= parms[0] ? 1 : 0, 8) },
- { new Token(">", TokenType.Binary), new OperationDef(parms => parms[1] > parms[0] ? 1 : 0, 8) },
- { new Token("<<", TokenType.Binary), new OperationDef(parms => (int)parms[1] << (int)parms[0], 9) },
- { new Token(">>", TokenType.Binary), new OperationDef(parms => (int)parms[1] >> (int)parms[0], 9) },
- { new Token("-", TokenType.Binary), new OperationDef(parms => parms[1] - parms[0], 10) },
- { new Token("+", TokenType.Binary), new OperationDef(parms => parms[1] + parms[0], 10) },
- { new Token("/", TokenType.Binary), new OperationDef(parms => parms[0]==0?throw new DivideByZeroException():parms[1]/parms[0],11) },
- { new Token("*", TokenType.Binary), new OperationDef(parms => parms[1] * parms[0], 11) },
- { new Token("%", TokenType.Binary), new OperationDef(parms => (long)parms[1] % (long)parms[0], 11) },
- { new Token("^^", TokenType.Binary), new OperationDef(parms => Math.Pow(parms[1], parms[0]), 12) },
- { new Token("~", TokenType.Unary), new OperationDef(parms => ~((long)parms[0]), 13) },
- { new Token("!", TokenType.Unary), new OperationDef(parms => parms[0].AlmostEquals(0) ? 1 : 0, 13) },
- { new Token("-", TokenType.Unary), new OperationDef(parms => -parms[0], 13) },
- { new Token("+", TokenType.Unary), new OperationDef(parms => +parms[0], 13) },
- { new Token("$", TokenType.Radix), new OperationDef(parms => parms[0], 13) },
- { new Token("%", TokenType.Radix), new OperationDef(parms => parms[0], 13) }
+ { new Token("?", TokenType.Ternary), new OperationDef(parms => parms[2] == 1 ? parms[0] : parms[1], 1) },
+ { new Token(":", TokenType.Ternary), new OperationDef(parms => parms[0], 1) },
+ { new Token(">", TokenType.Unary), new OperationDef(parms => ((long)parms[0] & 65535) / 0x100, 2) },
+ { new Token("<", TokenType.Unary), new OperationDef(parms => (long)parms[0] & 255, 2) },
+ { new Token("&", TokenType.Unary), new OperationDef(parms => (long)parms[0] & 65535, 2) },
+ { new Token("^", TokenType.Unary), new OperationDef(parms => ((long)parms[0] & UInt24.MaxValue) / 0x10000, 2) },
+ { new Token("||", TokenType.Binary), new OperationDef(parms => ((long)parms[1]!=0?1:0) | ((long)parms[0]!=0?1:0), 3) },
+ { new Token("&&", TokenType.Binary), new OperationDef(parms => ((long)parms[1]!=0?1:0) & ((long)parms[0]!=0?1:0), 4) },
+ { new Token("|", TokenType.Binary), new OperationDef(parms => (long)parms[1] | (long)parms[0], 5) },
+ { new Token("^", TokenType.Binary), new OperationDef(parms => (long)parms[1] ^ (long)parms[0], 6) },
+ { new Token("&", TokenType.Binary), new OperationDef(parms => (long)parms[1] & (long)parms[0], 7) },
+ { new Token("<=>",TokenType.Binary), new OperationDef(parms => Comparer.Default.Compare(parms[1], parms[0]), 8) },
+ { new Token("!=", TokenType.Binary), new OperationDef(parms => !parms[1].AlmostEquals(parms[0])?1:0, 9) },
+ { new Token("==", TokenType.Binary), new OperationDef(parms => parms[1].AlmostEquals(parms[0])?1:0, 9) },
+ { new Token("<", TokenType.Binary), new OperationDef(parms => parms[1] < parms[0] ? 1 : 0, 10) },
+ { new Token("<=", TokenType.Binary), new OperationDef(parms => parms[1] <= parms[0] ? 1 : 0, 10) },
+ { new Token(">=", TokenType.Binary), new OperationDef(parms => parms[1] >= parms[0] ? 1 : 0, 10) },
+ { new Token(">", TokenType.Binary), new OperationDef(parms => parms[1] > parms[0] ? 1 : 0, 10) },
+ { new Token("<<", TokenType.Binary), new OperationDef(parms => (int)parms[1] << (int)parms[0], 11) },
+ { new Token(">>", TokenType.Binary), new OperationDef(parms => (int)parms[1] >> (int)parms[0], 11) },
+ { new Token("-", TokenType.Binary), new OperationDef(parms => parms[1] - parms[0], 12) },
+ { new Token("+", TokenType.Binary), new OperationDef(parms => parms[1] + parms[0], 12) },
+ { new Token("/", TokenType.Binary), new OperationDef(parms => parms[0]==0?throw new DivideByZeroException():parms[1]/parms[0],13) },
+ { new Token("*", TokenType.Binary), new OperationDef(parms => parms[1] * parms[0], 13) },
+ { new Token("%", TokenType.Binary), new OperationDef(parms => (long)parms[1] % (long)parms[0], 13) },
+ { new Token("^^", TokenType.Binary), new OperationDef(parms => Math.Pow(parms[1], parms[0]), 14) },
+ { new Token("~", TokenType.Unary), new OperationDef(parms => ~((long)parms[0]), 15) },
+ { new Token("!", TokenType.Unary), new OperationDef(parms => parms[0].AlmostEquals(0) ? 1 : 0, 15) },
+ { new Token("-", TokenType.Unary), new OperationDef(parms => -parms[0], 15) },
+ { new Token("+", TokenType.Unary), new OperationDef(parms => +parms[0], 15) }
};
-
+ static readonly CultureInfo s_info;
+ const NumberStyles AsmNumberStyle = NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands | NumberStyles.AllowExponent;
static readonly Random s_rng = new Random();
readonly IReadOnlyDictionary _functions;
readonly List _functionEvaluators;
@@ -114,6 +127,13 @@ public class Evaluator
#region Constructors
+ static Evaluator()
+ {
+ s_info = CultureInfo.CreateSpecificCulture("en-US");
+ var nfi = s_info.NumberFormat;
+ nfi.NumberGroupSeparator = "_";
+ }
+
///
/// Creates a new instance of the expression evaluator.
///
@@ -213,73 +233,78 @@ public bool ExpressionIsCondition(RandomAccessIterator tokens)
/// true if the expression is conditional, false otherwise.
public bool ExpressionIsCondition(RandomAccessIterator tokens, bool restoreIterator)
{
+ var firstIndex = tokens.Index;
bool booleanNeeded = true;
- bool comparerFound = false, comparerNeeded = false;
+ if (tokens.Current?.Type == TokenType.Open)
+ {
+ tokens.MoveNext();
+ booleanNeeded = !ExpressionIsCondition(tokens, false);
+ }
Token token = tokens.GetNext();
- var firstIndex = tokens.Index;
- if (!Token.IsTerminal(token) && Token.IsTerminal(tokens.PeekNext()))
+ if ((!booleanNeeded && (Token.IsTerminal(token) || token.Type == TokenType.Ternary)) ||
+ (!Token.IsTerminal(token) && token.ValueType == ValueType.Boolean && (Token.IsTerminal(tokens.PeekNext()) || tokens.PeekNext().Type == TokenType.Ternary)))
{
- booleanNeeded = !_constants.TryGetValue(token.Name, out var val);
+ if (restoreIterator)
+ tokens.SetIndex(firstIndex);
+ return true;
}
- else
+ bool comparerFound = false, comparerNeeded = false;
+ while (!Token.IsTerminal(token) && token.Type != TokenType.Ternary)
{
- while (!Token.IsTerminal(token))
+ if (token.Type == TokenType.Operand && booleanNeeded && !comparerNeeded)
{
- if (token.Type == TokenType.Operand && booleanNeeded && !comparerNeeded)
+ if (token.ValueType == ValueType.Boolean)
{
- if (_constants.TryGetValue(token.Name, out var val))
- {
- booleanNeeded = false;
- }
- else if (token.Name[0] == '_' || char.IsLetter(token.Name[0]))
- {
- var operands = new List { token };
- if (tokens.PeekNext() != null && tokens.PeekNext().Name.Equals("["))
- {
- var ix = tokens.Index;
- tokens.MoveNext();
- operands.AddRange(Token.GetGroup(tokens));
- tokens.SetIndex(ix + operands.Count - 1);
- }
- var eval = Evaluate(operands.GetIterator());
- if (eval == 0 || eval == 1)
- booleanNeeded = false;
- else
- comparerNeeded = true;
- }
- else
- {
- comparerNeeded = true;
- }
+ booleanNeeded = false;
}
- else if ((token.Type.HasFlag(TokenType.Unary) && token.Name.Equals("!")) ||
- token.Name.Equals("("))
+ else if (token.Name[0] == '_' || char.IsLetter(token.Name[0]))
{
- var isSubCondition = ExpressionIsCondition(tokens, false);
- if (booleanNeeded && !comparerNeeded && isSubCondition)
+ var operands = new List { token };
+ if (tokens.PeekNext() != null && tokens.PeekNext().Name.Equals("["))
+ {
+ var ix = tokens.Index;
+ tokens.MoveNext();
+ operands.AddRange(Token.GetGroup(tokens));
+ tokens.SetIndex(ix + operands.Count - 1);
+ }
+ var eval = Evaluate(operands.GetIterator());
+ if (eval == 0 || eval == 1)
booleanNeeded = false;
else
comparerNeeded = true;
}
- else if (token.Type == TokenType.Radix || token.Type == TokenType.Unary || token.Type == TokenType.Function)
+ else
{
comparerNeeded = true;
- if (token.Type == TokenType.Radix || token.Type == TokenType.Function)
- {
- tokens.MoveNext();
- if (token.Type == TokenType.Function)
- _ = Token.GetGroup(tokens);
- }
}
- else if (token.Type == TokenType.Binary)
+ }
+ else if ((token.Type.HasFlag(TokenType.Unary) && token.Name.Equals("!")) ||
+ token.Name.Equals("("))
+ {
+ var isSubCondition = ExpressionIsCondition(tokens, false);
+ if (booleanNeeded && !comparerNeeded && isSubCondition)
+ booleanNeeded = false;
+ else
+ comparerNeeded = true;
+ }
+ else if (token.Type == TokenType.Radix || token.Type == TokenType.Unary || token.Type == TokenType.Function)
+ {
+ comparerNeeded = true;
+ if (token.Type == TokenType.Radix || token.Type == TokenType.Function)
{
- if (s_conditionals.Contains(token.Name))
- comparerFound = true;
- else
- comparerNeeded = true;
+ tokens.MoveNext();
+ if (token.Type == TokenType.Function)
+ _ = Token.GetGroup(tokens);
}
- token = tokens.GetNext();
}
+ else if (token.Type == TokenType.Binary)
+ {
+ if (s_conditionals.Contains(token.Name))
+ comparerFound = true;
+ else
+ comparerNeeded = true;
+ }
+ token = tokens.GetNext();
}
if (restoreIterator)
tokens.SetIndex(firstIndex);
@@ -292,30 +317,25 @@ Stack EvaluateInternal(RandomAccessIterator iterator, bool fromGr
var operators = new Stack();
var lastType = TokenType.None;
StringView lastToken = "";
- StringView nonBase10 = "";
+ var index = iterator.Index; // in case we need to backtrack
Token token;
var end = TokenType.Terminal;
while ((token = iterator.GetNext()) != null && !(token.Type == TokenType.Closed || (!fromGroup && end.HasFlag(token.Type))))
{
- if (token.Type == TokenType.Operand)
+ if (token.Type == TokenType.Operand || token.Type == TokenType.Radix)
{
- if (lastType == TokenType.Radix)
+ if (token.Type == TokenType.Operand && token.ValueType == ValueType.Unknown)
{
- if (!nonBase10.Equals(""))
- throw new ExpressionException(token, "Unexpected token.");
- nonBase10 = token.Name;
+ results.Push(UnknownValueEvaluator(iterator));
+ continue;
}
- else if (iterator.PeekNext() != null && iterator.PeekNext().Name.Equals("["))
+ if (token.Type == TokenType.Radix)
{
- var value = SymbolEvaluator(iterator);
- if (double.IsNegativeInfinity(value))
- throw new ExpressionException(token, "Index is out of range.");
- results.Push(value);
- }
- else
- {
- results.Push(Evaluate(token, double.MinValue, double.MaxValue));
+ if (Token.IsTerminal(iterator.PeekNext()) || iterator.PeekNext().ValueType == ValueType.Unknown)
+ throw new ExpressionException(token, "Expected value.");
+ token = iterator.GetNext();
}
+ results.Push((double)token.Value);
}
else
{
@@ -346,7 +366,22 @@ Stack EvaluateInternal(RandomAccessIterator iterator, bool fromGr
throw new SyntaxException(token, "Unexpected expression.");
if (!TokenType.Evaluation.HasFlag(token.Type))
return new Stack();
- if (operators.Count > 0)
+ if (token.Type == TokenType.Ternary && token.Name.Equals("?"))
+ {
+ if (iterator.PeekNext() == null)
+ throw new SyntaxException(token, "Invalid ternary expression.");
+ var iterCopy = new RandomAccessIterator(iterator, index);
+ if (!ExpressionIsCondition(iterCopy))
+ throw new SyntaxException(token, "Invalid ternary expression.");
+ while (operators.Count > 0)
+ DoOperation(operators.Pop(), results);
+ var subExpressions = EvaluateInternal(iterator, false);
+ foreach (var subEx in subExpressions)
+ results.Push(subEx);
+ iterator.Rewind(iterator.Index - 1);
+ DoOperation(token, results);
+ }
+ else if (operators.Count > 0)
{
var top = operators.Peek();
if (top.Name.Equals("!") && !token.Name.Equals("||") && !token.Name.Equals("&&"))
@@ -355,65 +390,54 @@ Stack EvaluateInternal(RandomAccessIterator iterator, bool fromGr
while ((top.Type == TokenType.Function || s_operators[top].Item2 >= opOrder) && operators.Count > 0)
{
operators.Pop();
- DoOperation(top, ref nonBase10, results);
+ DoOperation(top, results);
if (operators.Count > 0)
top = operators.Peek();
}
}
- if (token.Type != TokenType.Separator)
+ if (token.Type == TokenType.Separator)
+ index = iterator.Index;
+ else if (token.Type != TokenType.Ternary)
operators.Push(token);
}
}
- }
+ }
while (operators.Count > 0)
- DoOperation(operators.Pop(), ref nonBase10, results);
+ DoOperation(operators.Pop(), results);
return results;
}
- void DoOperation(Token op, ref StringView nonBase10, Stack output)
+ void DoOperation(Token op, Stack output)
{
- if (nonBase10.Length > 0)
+ OperationDef operation;
+ var parms = new List();
+ var parmCount = 1;
+ if (op.Type == TokenType.Function)
{
- try
- {
- output.Push(s_radixOperators[op.Name](nonBase10));
- nonBase10 = "";
- }
- catch
- {
- throw new SyntaxException(op, $"\"{op.Name}{nonBase10}\" is not a valid expression.");
- }
+ operation = _functions[op.Name];
+ parmCount = operation.Item2;
}
else
{
- OperationDef operation;
- var parms = new List();
- var parmCount = 1;
- if (op.Type == TokenType.Function)
- {
- operation = _functions[op.Name];
- parmCount = operation.Item2;
- }
- else
+ operation = s_operators[op];
+ if (op.Type == TokenType.Binary)
+ parmCount++;
+ else if (op.Type == TokenType.Ternary)
+ parmCount += 2;
+ }
+ while (--parmCount >= 0)
+ {
+ if (output.Count == 0)
{
- operation = s_operators[op];
- if (op.Type == TokenType.Binary)
- parmCount++;
+ var opType = op.Type == TokenType.Function ? "function" : "operator";
+ throw new SyntaxException(op, $"Missing arguments for {opType} \"{op}\".");
}
- while (parmCount-- >= parms.Count)
- {
- if (output.Count == 0)
- {
- var opType = op.Type == TokenType.Function ? "function" : "operator";
- throw new SyntaxException(op, $"Missing operand argument for {opType} \"{op}\".");
- }
- parms.Add(output.Pop());
- }
- if ((op.Name.Equals("||") || op.Name.Equals("&&") || op.Name.Equals("!")) && parms.Any(p => p != 1 && p != 0))
- throw new ExpressionException(op, "Invalid conditional expression.");
- output.Push(operation.Item1(parms));
+ parms.Add(output.Pop());
}
+ if ((op.Name.Equals("||") || op.Name.Equals("&&") || op.Name.Equals("!")) && parms.Any(p => p != 1 && p != 0))
+ throw new ExpressionException(op, "Invalid conditional expression.");
+ output.Push(operation.Item1(parms));
}
double DoEvaluation(RandomAccessIterator tokens, bool advanceIterator, double minValue, double maxValue, bool isMath)
@@ -443,10 +467,7 @@ void DoOperation(Token op, ref StringView nonBase10, Stack output)
if (!isMath)
{
- var ienumtokens = new RandomAccessIterator(tokens, true)
- .Skip(ix + 1)
- .Take(tokens.Index - ix - 1);
- if (!ExpressionIsCondition(ienumtokens.GetIterator()))
+ if (!ExpressionIsCondition(new RandomAccessIterator(tokens, ix)))
throw new SyntaxException(first, "Invalid conditional expression.");
}
return r;
@@ -510,74 +531,92 @@ public double Evaluate(Token token)
///
- /// Evaluates a parsed tokens as a mathematical expression.
+ /// Get the value from the given or pair of values.
///
- /// The parsed token representing the expression.
- /// The minimum value allowed in the evaluation.
- /// The maximum value allowed in the evaluation.
- /// Allow symbol evaluation to occur if
- /// the token is not successfully parsed.
- /// The result of the evaluation.
- ///
- ///
- ///
- ///
- public double Evaluate(Token token, double minValue, double maxValue)
+ /// A radix expression preceding the name.
+ /// The name.
+ /// A comparer.
+ /// A tuple containing the value type (if known) and the boxed value.
+ public static (ValueType valueType, double value) GetValue(StringView radix, StringView name, StringViewComparer comparer)
{
- if (!double.TryParse(RemoveSeparators(token.Name.ToString()), out var converted))
+ if (radix != null)
+ return (ValueType.Binary, s_radixOperators[radix](name));
+ if (!double.TryParse(name.ToString(), AsmNumberStyle, s_info, out var converted))
{
- if (token.Name[0] == '0' && token.Name.Length > 2)
+ if (name[0] == '0' && name.Length > 2)
{
// try to convert non-base 10 literals in 0x/0b/0o notation.
try
{
- if (token.Name[1] == 'b' || token.Name[1] == 'B')
- converted = Convert.ToInt64(GetBinaryString(token.Name.Substring(2)), 2);
- else if (token.Name[1] == 'o' || token.Name[1] == 'O')
- converted = Convert.ToInt64(token.Name.Substring(2).Replace("_", string.Empty), 8);
- else if (token.Name[1] == 'x' || token.Name[1] == 'X')
- converted = Convert.ToInt64(token.ToString().Replace("_", string.Empty), 16);
+ if (name[1] == 'b' || name[1] == 'B')
+ converted = Convert.ToInt64(GetBinaryString(name.Substring(2)), 2);
+ else if (name[1] == 'o' || name[1] == 'O')
+ converted = Convert.ToInt64(name.Substring(2).Replace("_", string.Empty), 8);
+ else if (name[1] == 'x' || name[1] == 'X')
+ converted = Convert.ToInt64(name.Substring(2).Replace("_", string.Empty), 16);
else
- throw new SyntaxException(token, "Not a valid numeric constant.");
+ throw new ArgumentException("Not a valid numeric constant.");
+ return (ValueType.Binary, converted);
}
catch
{
- throw new SyntaxException(token, "Not a valid numeric constant.");
+ throw new ArgumentException("Not a valid numeric constant.");
}
}
- else if (!_constants.TryGetValue(token.Name, out converted))
- {
- var tokens = new List { token };
- var it = tokens.GetIterator();
- it.MoveNext();
- converted = SymbolEvaluator(it);
- }
+ if (name.Equals("false", comparer) || name.Equals("true", comparer))
+ return (ValueType.Boolean, name.Equals("true", comparer) ? 1 : 0);
+ return (ValueType.Unknown, double.NaN);
}
- else if (token.Name[0] == '0' &&
- token.Name.Length > 1 &&
- (token.Name[1] >= '0' && token.Name[1] <= '7') ||
- (token.Name.Length > 3 && token.Name[1] == '_' && token.Name[2] >= '0' && token.Name[2] <= '7'))
+ if (name[0] == '0' &&
+ name.Length > 1 &&
+ (name[1] >= '0' && name[1] <= '7') ||
+ (name.Length > 3 && name[1] == '_' && name[2] >= '0' && name[2] <= '7'))
{
// all leading zeros treated as octal
try
{
- converted = Convert.ToInt64(RemoveSeparators(token.ToString()), 8);
+ return (ValueType.Boolean, Convert.ToInt64(name.ToString().Replace("_", string.Empty), 8));
}
catch
{
- throw new SyntaxException(token, "Not a valid numeric constant.");
+ throw new ArgumentException("Not a valid numeric constant.");
}
}
- if (converted < minValue || converted > maxValue)
- throw new IllegalQuantityException(token, converted);
- return converted;
+ if (converted.IsInteger())
+ return (ValueType.Integer, converted);
+ return (ValueType.Double, converted);
}
- static string RemoveSeparators(string number)
+ ///
+ /// Evaluates a parsed tokens as a mathematical expression.
+ ///
+ /// The parsed token representing the expression.
+ /// The minimum value allowed in the evaluation.
+ /// The maximum value allowed in the evaluation.
+ /// Allow symbol evaluation to occur if
+ /// the token is not successfully parsed.
+ /// The result of the evaluation.
+ ///
+ ///
+ ///
+ ///
+ public double Evaluate(Token token, double minValue, double maxValue)
{
- if (s_separators.IsMatch(number))
- return number.Replace("_", string.Empty);
- return number;
+ double converted;
+ if (token.ValueType == ValueType.Unknown)
+ {
+ var tokens = new List { token };
+ var it = tokens.GetIterator();
+ it.MoveNext();
+ converted = UnknownValueEvaluator(it);
+ }
+ else
+ {
+ converted = (double)token.Value;
+ }
+ if (converted < minValue || converted > maxValue)
+ throw new IllegalQuantityException(token, converted);
+ return converted;
}
///
@@ -672,7 +711,7 @@ public static string GetBinaryString(string binary)
///
/// An evaluator of symbols the evaluator does not recognize
///
- public Func, double> SymbolEvaluator { get; set; }
+ public Func, double> UnknownValueEvaluator { get; set; }
///
/// Add a custom function evaluator to the evaluator.
diff --git a/Core6502DotNet/src/Core/StringView.cs b/Core6502DotNet/src/Core/StringView.cs
index bab1c20..3f17e4e 100644
--- a/Core6502DotNet/src/Core/StringView.cs
+++ b/Core6502DotNet/src/Core/StringView.cs
@@ -49,6 +49,7 @@ public StringView(string str)
}
+
///
/// Constructs a new instance of a string view.
///
@@ -61,7 +62,7 @@ public StringView(string str, int position, int length)
String = str;
Position = position;
Length = length;
- _endIndex = Position + Length;
+ _endIndex = Position + Length;
_enumerator = -1;
}
diff --git a/Core6502DotNet/src/Core/Symbol.cs b/Core6502DotNet/src/Core/Symbol.cs
index c5e1d47..4543577 100644
--- a/Core6502DotNet/src/Core/Symbol.cs
+++ b/Core6502DotNet/src/Core/Symbol.cs
@@ -177,6 +177,100 @@ public Symbol(RandomAccessIterator tokens, Evaluator eval)
#region Methods
+ public enum AccessResult
+ {
+ Success,
+ InvalidType,
+ SubscriptOutOfRange,
+ SubscriptNotIntegral
+ }
+
+ ///
+ /// Get the element at the specified index in the string array symbol.
+ ///
+ /// The index subscript.
+ /// The string to get.
+ /// The value.
+ public AccessResult TryGetElementAt(double subscript, out StringView str)
+ {
+ str = null;
+ var result = Validate(subscript, true);
+ if (result == AccessResult.Success)
+ str = StringVector[(int)subscript];
+ return result;
+ }
+ ///
+ /// Update the element at the specified index of the numeric array symbol.
+ ///
+ /// The index subscript.
+ /// The updated value.
+ /// The value.
+ public AccessResult TryUpdateElementAt(double subscript, double val)
+ {
+ var result = Validate(subscript, false);
+ if (result == AccessResult.Success)
+ NumericVector[(int)subscript] = val;
+ return result;
+ }
+
+ ///
+ /// Update the element at the specified index of the string array symbol.
+ ///
+ /// The index subscript.
+ /// The updated string vaule.
+ /// The value.
+ public AccessResult TryUpdateElementAt(double subscript, StringView str)
+ {
+ var result = Validate(subscript, false);
+ if (result == AccessResult.Success)
+ StringVector[(int)subscript] = str;
+ return result;
+ }
+
+ AccessResult Validate(double subscript, bool forString)
+ {
+ var result = AccessResult.SubscriptNotIntegral;
+ if (subscript.IsInteger())
+ {
+ result = AccessResult.InvalidType;
+ if (StorageType == StorageType.Vector || (forString && DataType == DataType.String && StorageType == StorageType.Scalar))
+ {
+ result = AccessResult.SubscriptOutOfRange;
+ int upperBounds;
+ if (StorageType == StorageType.Vector)
+ upperBounds = DataType == DataType.String ? StringVector.Count : NumericVector.Count;
+ else
+ upperBounds = StringValue.Length;
+ var index = (int)subscript;
+ if (index >= 0 && index < upperBounds)
+ return AccessResult.Success;
+ }
+ }
+ return result;
+ }
+
+ ///
+ /// Get the element at the specified index in the numeric array if the symbol is a number, or the
+ /// at the specified index in the string if the symbol is a string.
+ ///
+ /// The index subscript.
+ /// The value to fetch.
+ /// The value.
+ public AccessResult TryGetElementAt(double subscript, out double val)
+ {
+ val = double.NaN;
+ var result = Validate(subscript, DataType == DataType.String);
+ if (result == AccessResult.Success)
+ {
+ var index = (int)subscript;
+ if (DataType == DataType.String)
+ val = StringValue[index];
+ else
+ val = NumericVector[index];
+ }
+ return result;
+ }
+
///
/// Determine of the symbol is equal in type (both data and storage).
///
diff --git a/Core6502DotNet/src/Core/SymbolManager.cs b/Core6502DotNet/src/Core/SymbolManager.cs
index e67c229..0d7455a 100644
--- a/Core6502DotNet/src/Core/SymbolManager.cs
+++ b/Core6502DotNet/src/Core/SymbolManager.cs
@@ -376,6 +376,41 @@ public bool SymbolExists(StringView name, bool searchUp)
return null;
}
+ public static string GetErrorMessageFromGetResult(Symbol.AccessResult result)
+ {
+ return result switch
+ {
+ Symbol.AccessResult.SubscriptNotIntegral => "Subscript was not an integer.",
+ Symbol.AccessResult.SubscriptOutOfRange => "Index out of range.",
+ _ => "Type mismatch."
+ };
+ }
+
+ public Symbol GetSymbol(RandomAccessIterator expression, bool raiseExceptionIfNotFound)
+ {
+ var searchnotFound = SearchedNotFound;
+ if (!expression.MoveNext())
+ throw new ArgumentException("Cannot evaluate the expression.");
+ var symbolToken = expression.Current;
+ if (symbolToken.Type == TokenType.Operand)
+ {
+ var fqdn = GetFullyQualifiedName(symbolToken.Name);
+ if (_symbolTable.TryGetValue(fqdn, out var sym))
+ {
+ SearchedNotFound = searchnotFound;
+ if (sym == null)
+ throw new SymbolException(symbolToken, SymbolException.ExceptionReason.IllegalReference);
+ if (expression.MoveNext() && expression.Current.Name.Equals("["))
+ {
+ var subscript = _evaluator.Evaluate(expression, 0, int.MaxValue);
+ }
+ }
+ }
+
+ return null;
+
+ }
+
///
/// Define a symbol as representing the current state of the program counter.
///
@@ -418,7 +453,7 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
sym = null;
}
var isIndexed = false;
- var subscript = -1;
+ double subscript = -1;
var expectedStorageType = StorageType.Scalar;
var assign = tokens.GetNext();
if (sym != null)
@@ -426,7 +461,7 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
if (assign?.Name.Equals("[") == true)
{
isIndexed = true;
- subscript = (int)_evaluator.Evaluate(tokens, 0, sym.Length);
+ subscript = _evaluator.Evaluate(tokens, 0, sym.Length);
assign = tokens.GetNext();
}
else
@@ -436,7 +471,7 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
expectedStorageType = sym.StorageType;
}
}
- if (Token.IsTerminal(assign) || !(assign.Name.Equals("=") || assign.Name.Equals(":=") || assign.IsCompoundAssignment()))
+ if (Token.IsTerminal(assign) || !(assign.Name.Equals("=") || assign.Name.Equals(":=") || assign.IsCompoundAssignment))
throw new SyntaxException(assign ?? lhs, "Assignment operator expected.");
var rhsIndex = tokens.Index;
@@ -444,10 +479,11 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
if (Token.IsTerminal(rhs))
throw new SyntaxException(assign, "rhs expression is missing.");
var rhsNext = tokens.PeekNext();
- var rhsSubscript = -1;
+ double rhsSubscript = -1;
var storageType = StorageType.Scalar;
DataType dataType;
Symbol rhsSym;
+ var gettingStrChar = false;
if (rhs.Name.Equals("["))
{
if (isIndexed)
@@ -464,35 +500,30 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
rhsSym = SymbolExists(rhs.Name, true) ? GetSymbol(rhs, false) : null;
if (rhsNext?.Name.Equals("[") == true)
{
- if (rhsSym?.StorageType != StorageType.Vector)
- throw new SyntaxException(rhsNext, "Subscript operation invalid.");
- if (Token.IsTerminal(tokens.GetNext()))
- throw new SyntaxException(rhsNext, "Index expression expected for subscript.");
- rhsSubscript = (int)_evaluator.Evaluate(tokens, 0, rhsSym.Length);
+ gettingStrChar = rhsSym?.StorageType == StorageType.Scalar && rhsSym?.DataType == DataType.String;
+ tokens.MoveNext();
+ rhsSubscript = _evaluator.Evaluate(tokens, 0, rhsSym.Length);
rhsNext = tokens.GetNext();
}
else if (rhsSym != null)
{
- if (Token.IsTerminal(tokens.GetNext()))
- {
- storageType = rhsSym.StorageType;
- if (sym == null)
- expectedStorageType = storageType;
- }
- else if (rhsSym.StorageType == StorageType.Vector) // ex: .let x = some_array + 2
- {
- throw new SyntaxException(rhsNext, "Unexpected expression.");
- }
+ // ex: .let x = some_array + 2
+ if (rhsSym.StorageType == StorageType.Vector && !Token.IsTerminal(tokens.GetNext()))
+ throw new SyntaxException(tokens.Current, "Unexpected expression.");
+
+ storageType = rhsSym.StorageType;
+ if (sym == null)
+ expectedStorageType = storageType;
}
if (rhsSym != null && Token.IsTerminal(rhsNext))
- dataType = rhsSym.DataType;
+ dataType = gettingStrChar ? DataType.Numeric : rhsSym.DataType;
else
- dataType = !assign.IsCompoundAssignment() && rhs.IsDoubleQuote() && Token.IsTerminal(rhsNext) ? DataType.String : DataType.Numeric;
+ dataType = !assign.IsCompoundAssignment && rhs.IsDoubleQuote() && Token.IsTerminal(rhsNext) ? DataType.String : DataType.Numeric;
}
if (expectedStorageType != storageType || (sym != null && sym.DataType != dataType))
throw new SyntaxException(rhs, "Type mismatch.");
- if (assign.IsCompoundAssignment() && (sym == null || !sym.IsMutable || expectedStorageType == StorageType.Vector))
+ if (assign.IsCompoundAssignment && (sym == null || !sym.IsMutable || expectedStorageType == StorageType.Vector))
throw new SyntaxException(assign, "Invalid use of compound assignment operator.");
if (expectedStorageType == StorageType.Vector)
@@ -506,13 +537,13 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
{
StringView stringValue = null;
var numericValue = double.NaN;
- if (rhsSym?.DataType == DataType.String && Token.IsTerminal(rhsNext))
- {
- stringValue = rhsSubscript > -1 ? rhsSym.StringVector[rhsSubscript] : rhsSym.StringValue;
- }
- else if (rhsSym?.DataType == DataType.Numeric && Token.IsTerminal(rhsNext))
+ if (Token.IsTerminal(rhsNext) && (rhsSym?.StorageType == StorageType.Vector || gettingStrChar))
{
- numericValue = rhsSubscript > -1 ? rhsSym.NumericVector[rhsSubscript] : rhsSym.NumericValue;
+ var result = (rhsSym.DataType == DataType.Numeric || gettingStrChar) ?
+ rhsSym.TryGetElementAt(rhsSubscript, out numericValue) :
+ rhsSym.TryGetElementAt(rhsSubscript, out stringValue);
+ if (result != Symbol.AccessResult.Success)
+ throw new SyntaxException(rhs, GetErrorMessageFromGetResult(result));
}
else if (dataType == DataType.String)
{
@@ -523,17 +554,32 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
// reset the token iterator back to the beginning of the rhs expression
tokens.SetIndex(rhsIndex);
numericValue = _evaluator.Evaluate(tokens);
- if (assign.IsCompoundAssignment())
+ if (assign.IsCompoundAssignment)
{
// break compound expression = into:
//
- var compoundExpression = new List();
+ var symValue = sym.NumericValue;
if (isIndexed)
- compoundExpression.Add(new Token(sym.NumericVector[subscript].ToString(), TokenType.Operand));
- else
- compoundExpression.Add(new Token(sym.NumericValue.ToString(), TokenType.Operand));
- compoundExpression.Add(new Token(assign.Name[0..^2], TokenType.Binary));
- compoundExpression.Add(new Token(numericValue.ToString(), TokenType.Operand));
+ {
+ var result = sym.TryGetElementAt(subscript, out symValue);
+ if (result != Symbol.AccessResult.Success)
+ throw new SyntaxException(lhs, GetErrorMessageFromGetResult(result));
+ }
+ var symToken = new Token(symValue.ToString(), TokenType.Operand)
+ {
+ Value = symValue
+ };
+ var valueToken = new Token(numericValue.ToString(), TokenType.Operand)
+ {
+ Value = numericValue,
+ ValueType = symToken.ValueType = ValueType.Double
+ };
+ var compoundExpression = new List
+ {
+ symToken,
+ new Token(assign.Name[0..^2], TokenType.Binary),
+ valueToken
+ };
numericValue = _evaluator.Evaluate(compoundExpression.GetIterator());
}
}
@@ -541,10 +587,11 @@ void DefineFromExpression(RandomAccessIterator tokens, bool isGlobal, boo
{
if (isIndexed)
{
- if (dataType == DataType.String)
- sym.StringVector[subscript] = stringValue;
- else
- sym.NumericVector[subscript] = numericValue;
+ var result = dataType == DataType.Numeric ?
+ sym.TryUpdateElementAt(subscript, numericValue) :
+ sym.TryUpdateElementAt(subscript, stringValue);
+ if (result != Symbol.AccessResult.Success)
+ throw new SyntaxException(rhs, GetErrorMessageFromGetResult(result));
}
else if (dataType == DataType.String)
sym.StringValue = stringValue;
@@ -771,7 +818,7 @@ public void Reset()
/// List all labels, including non-addresses.
/// The string listing.
public string ListLabels(bool listAll)
- { //ADD2PLYSTAT = 4783 // $12af
+ {
var listBuilder = new StringBuilder(
"/*************************************************************/\n" +
"/* Symbol Value */\n"+
diff --git a/Core6502DotNet/src/Core/Token.cs b/Core6502DotNet/src/Core/Token.cs
index bd5e070..7f65989 100644
--- a/Core6502DotNet/src/Core/Token.cs
+++ b/Core6502DotNet/src/Core/Token.cs
@@ -19,24 +19,25 @@ namespace Core6502DotNet
public enum TokenType : uint
{
None = 0,
- Start = 0b000000000001,
- Open = 0b000000000010,
- Operand = 0b000000000100,
- Unary = 0b000000001000,
- Radix = 0b000000010000,
- StartOrOperand = 0b000000011111,
- Closed = 0b000000100000,
- Separator = 0b000001000000,
- Terminal = 0b000001100000,
- Binary = 0b000010000000,
- Function = 0b000100000000,
- EndOrBinary = 0b000111100000,
- Instruction = 0b001000000000,
- Label = 0b010000000000,
- LabelInstr = 0b011000000000,
- Misc = 0b100000000000,
- MoreTokens = Binary | Separator | Open,
- Evaluation = Binary | Separator | Function
+ Start = 0b0000000000001,
+ Open = 0b0000000000010,
+ Operand = 0b0000000000100,
+ Unary = 0b0000000001000,
+ Radix = 0b0000000010000,
+ StartOrOperand = 0b0000000011111,
+ Closed = 0b0000000100000,
+ Separator = 0b0000001000000,
+ Terminal = 0b0000001100000,
+ Ternary = 0b0000010000000,
+ Binary = 0b0000100000000,
+ Function = 0b0001000000000,
+ EndOrBinary = 0b0001111100000,
+ Instruction = 0b0010000000000,
+ Label = 0b0100000000000,
+ LabelInstr = 0b0110000000000,
+ Misc = 0b1000000000000,
+ MoreTokens = Binary | Ternary | Separator | Open,
+ Evaluation = Binary | Ternary | Separator | Function
}
///
@@ -47,16 +48,18 @@ public class Token : IEquatable, IComparable
{
#region Members
- ///
- /// Gets the key-value pairs of opens and closures.
- ///
- public static readonly Dictionary s_openClose = new Dictionary
+ static readonly Dictionary s_openClose = new Dictionary
{
{ "(", ")" },
{ "{", "}" },
{ "[", "]" }
};
+ static readonly HashSet s_compoundAssignments = new HashSet
+ {
+ "+=","-=","*=","/=","%=",">>=","<<=","&=","^=","|=","^^="
+ };
+
#endregion
#region Constructors
@@ -80,6 +83,8 @@ public Token(StringView name, TokenType type, int position)
Type = type;
Name = name;
Position = position;
+ IsCompoundAssignment = s_compoundAssignments.Contains(name);
+ IsAssignment = Name?[^1] == '=' && (Name.Length == 1 || Name[0] == ':' || IsCompoundAssignment);
}
///
@@ -88,11 +93,7 @@ public Token(StringView name, TokenType type, int position)
/// The token's (parsed) name.
/// The token's .
public Token(StringView name, TokenType type)
- {
- Name = name;
- Type = type;
- Position = 1;
- }
+ : this(name, type, 1) { }
#endregion
@@ -128,23 +129,6 @@ public Token(StringView name, TokenType type)
/// true if the token is an opening, false otherwise.
public bool IsOpen() => Type.HasFlag(TokenType.Open);
- ///
- /// Determines whether the token represents an assignment operator.
- ///
- /// true if the token name is an assignment operator,
- /// false otherwise.
- public bool IsAssignment()
- => Name?[^1] == '=' && (Name.Length == 1 || Name[0] == ':' || IsCompoundAssignment());
-
- ///
- /// Determines whether the token represents a compound assignment operator.
- ///
- /// true if the token name is a compound assignment operator,
- /// false otherwise.
- public bool IsCompoundAssignment()
- => Name.Length > 1 && Name[^1] == '=' && ",+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=".Contains($",{Name}");
-
-
///
/// Indicates whether the current token name is equal to the given string.
///
@@ -234,9 +218,10 @@ internal static void GatherIntoExpressions(List tokens)
var brackets = 0;
foreach (var token in tokens)
{
- if ((!IsTerminal(token) && !token.IsAssignment() &&
+ if ((!IsTerminal(token) && !token.IsAssignment &&
(token.Type != TokenType.Open ||
lastToken?.Type != TokenType.Closed))||
+ token.Type == TokenType.Ternary ||
inFunction ||
token.Type == TokenType.Closed)
{
@@ -248,7 +233,7 @@ internal static void GatherIntoExpressions(List tokens)
if (--brackets == 0)
inFunction = false;
}
- if (lastToken != null && !lastToken.IsAssignment())
+ if (lastToken != null && !lastToken.IsAssignment)
lastToken.NextInExpression = token;
if (firstToken == null)
firstToken = token;
@@ -280,14 +265,15 @@ public static string GetExpression(Token token, bool startAtToken = false, bool
return token.Name.ToString();
if (token.FirstInExpression != null && !startAtToken)
token = token.FirstInExpression;
- var len = token.Name.Length;
+ var len = 0;
var current = token.NextInExpression;
var previous = token;
+ var firstInLine = token;
var lineSourceIndex = token.LineSourceIndex;
var startOffset = token.Position - 1;
+ var sourceLines = token.Line.FullSource.Split('\n');
if (startAtToken && lineSourceIndex > 0)
{
- var sourceLines = token.Line.FullSource.Split('\n');
for (var i = 0; i < lineSourceIndex; i++)
startOffset += sourceLines[i].Length + 1;
}
@@ -297,17 +283,14 @@ public static string GetExpression(Token token, bool startAtToken = false, bool
{
if (toNewLine)
break;
- len += current.Position;
+ len += sourceLines[lineSourceIndex].Length - firstInLine.Position + current.Position + 1;
+ firstInLine = current;
lineSourceIndex++;
}
- else
- {
- len += current.Position - (previous.Position + previous.Name.Length);
- }
- len += current.Name.Length;
previous = current;
current = current.NextInExpression;
}
+ len += previous.Position - firstInLine.Position + previous.Name.Length;
return token.Line.FullSource.Substring(startOffset, len);
}
@@ -322,6 +305,10 @@ public static string GetExpression(Token token, bool startAtToken = false, bool
///
public TokenType Type { get; }
+ public ValueType ValueType { get; set; }
+
+ public object Value { get; set; }
+
///
/// Gets the token's position in its source line.
///
@@ -336,7 +323,16 @@ public static string GetExpression(Token token, bool startAtToken = false, bool
/// Gets or sets the token's parsed in which it appears.
///
public SourceLine Line { get; internal set; }
-
+
+ ///
+ /// Gets whether the token represents an assignment operator.
+ ///
+ public bool IsAssignment { get; }
+
+ ///
+ /// Gets whether the token represents a compound assignment operator.
+ ///
+ public bool IsCompoundAssignment { get; }
///
/// Gets or sets the source index of the line in which the token appears.
diff --git a/Core6502DotNet/src/Line Assemblers/AssignmentAssembler.cs b/Core6502DotNet/src/Line Assemblers/AssignmentAssembler.cs
index a5a7398..996fae1 100644
--- a/Core6502DotNet/src/Line Assemblers/AssignmentAssembler.cs
+++ b/Core6502DotNet/src/Line Assemblers/AssignmentAssembler.cs
@@ -5,6 +5,7 @@
//
//-----------------------------------------------------------------------------
+using System;
using System.Collections.Generic;
using System.Linq;
@@ -155,7 +156,6 @@ protected override string OnAssemble(RandomAccessIterator lines)
Services.Output.SynchPC();
break;
}
- SetLabel(line);
}
if (iterator?.Current != null)
throw new SyntaxException(iterator.Current, "Unexpected expression.");
@@ -168,6 +168,26 @@ protected override string OnAssemble(RandomAccessIterator lines)
{
return $".{Services.Output.LogicalPC,-41:x4}{unparsedSource}";
}
+ var valueTokenIndex = instruction.Equals(".let") ? 2 : 0;
+ if ((line.Operands.Count - valueTokenIndex) == 1)
+ {
+ var valueToken = line.Operands[valueTokenIndex];
+ if (valueToken.ValueType != ValueType.Unknown)
+ {
+ var value = valueToken.Value;
+ return line.Operands[valueTokenIndex].ValueType switch
+ {
+ ValueType.Binary => $"=${Convert.ToInt64(value),-41:x}{unparsedSource}",
+ ValueType.Boolean => $"={((double)value == 0 ? "false" : "true"),-42}{unparsedSource}",
+ _ => $"={(double)value,-41}{unparsedSource}"
+ };
+ }
+ if (valueToken.IsQuote())
+ {
+ var value = valueToken.ToString().Elliptical(38);
+ return $"={value,-42}{unparsedSource}";
+ }
+ }
var tokenSymbol = instruction.Equals(".let") ? line.Operands[0] : line.Label;
var symbol = Services.SymbolManager.GetSymbol(tokenSymbol, false);
if (symbol != null && symbol.StorageType == StorageType.Scalar)
@@ -181,7 +201,8 @@ protected override string OnAssemble(RandomAccessIterator lines)
condition = Services.Evaluator.ExpressionIsCondition(line.Operands.GetIterator());
if (condition)
return $"={(symbol.NumericValue == 0 ? "false" : "true"),-42}{unparsedSource}";
- if (symbol.NumericValue.IsInteger())
+ if (symbol.DataType == DataType.Address ||
+ line.Operands.Any(t => t.Type == TokenType.Operand && t.IsSpecialOperator()))
return $"=${(int)symbol.NumericValue,-41:x}{unparsedSource}";
return $"={symbol.NumericValue,-41}{unparsedSource}";
}
@@ -192,17 +213,6 @@ protected override string OnAssemble(RandomAccessIterator lines)
return string.Empty;
}
- void SetLabel(SourceLine line)
- {
- if (line.Label != null && !line.Label.Name.Equals("*"))
- {
- if (line.Label.IsSpecialOperator())
- Services.SymbolManager.DefineLineReference(line.Label, Services.Output.LogicalPC);
- else
- DefineLabel(line.Label, Services.Output.LogicalPC, true);
- }
- }
-
public override bool AssemblesLine(SourceLine line)
=> line.Instruction != null &&
(Reserved.IsOneOf("Assignments", line.Instruction.Name) ||
@@ -232,22 +242,24 @@ public double EvaluateFunction(RandomAccessIterator tokens)
if (!param.Name.Equals(")"))
{
param = tokens.GetNext();
- int subscript = -1;
+ double subscript = -1;
if (param.Name.Equals("["))
- subscript = (int)Services.Evaluator.Evaluate(tokens, 0, int.MaxValue);
+ subscript = Services.Evaluator.Evaluate(tokens, 0, int.MaxValue);
if (subscript < 0 || !tokens.PeekNext().Equals(")"))
- throw new SyntaxException(param.Position, "Unexpected argument.");
+ throw new SyntaxException(param, "Unexpected argument.");
+ if (!subscript.IsInteger())
+ throw new ExpressionException(param, "Subscript must be an integer.");
if (symbolLookup.StorageType != StorageType.Vector)
- throw new SyntaxException(param.Position, "Type mismatch.");
+ throw new SyntaxException(param, "Type mismatch.");
if (symbolLookup.DataType == DataType.String)
{
if (subscript >= symbolLookup.StringVector.Count)
throw new SyntaxException(param.Position, "Index out of range.");
- return symbolLookup.StringVector[subscript].Length;
+ return symbolLookup.StringVector[(int)subscript].Length;
}
if (subscript >= symbolLookup.NumericVector.Count)
throw new SyntaxException(param.Position, "Index out of range.");
- return symbolLookup.NumericVector[subscript].Size();
+ return symbolLookup.NumericVector[(int)subscript].Size();
}
return symbolLookup.Length;
}
diff --git a/Core6502DotNet/src/Preprocessing/Preprocessor.cs b/Core6502DotNet/src/Preprocessing/Preprocessor.cs
index 984db36..0c3f67a 100644
--- a/Core6502DotNet/src/Preprocessing/Preprocessor.cs
+++ b/Core6502DotNet/src/Preprocessing/Preprocessor.cs
@@ -290,6 +290,7 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
var expected = TokenType.LabelInstr;
var previousType = TokenType.None;
var opens = new Stack();
+ var ternaryExpressions = 0;
Macro definingMacro = null;
string nextLine, lineSource;
blockComment = stopProcessing = previousWasPlus = false; readyForNewLine = true;
@@ -354,7 +355,7 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
if (c == EOS)
break;
}
- if (c == ':' && it.PeekNext() != '=')
+ if (c == ':' && it.PeekNext() != '=' && ternaryExpressions == 0)
{
if ((expected != TokenType.Instruction && expected != TokenType.EndOrBinary &&
(tokens.Count == 0 || tokens[^1].Type != TokenType.Instruction)) || !LineTerminates())
@@ -546,6 +547,13 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
it.MoveNext();
peek = it.PeekNext();
size++;
+ if (c == '<' && peek == '>')
+ {
+ // spaceship operator
+ it.MoveNext();
+ peek = it.PeekNext();
+ size++;
+ }
}
c = it.Current;
}
@@ -566,7 +574,7 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
type = TokenType.Label;
expected = TokenType.Instruction;
if (c != '*' && position > 0 && _options.WarnOnLabelLeft)
- _options.Log?.LogEntry(fileName, lineNumber, position + 1, "Label is not at the beginning of the line.", nextLine.Substring(0, position), nextLine, false);
+ _options.Log?.LogEntry(fileName, lineNumber, position + 1, "Label is not at the beginning of the line.", nextLine.Substring(0, position), nextLine, false);
}
}
else if (c == '\\' && definingMacro != null)
@@ -616,6 +624,10 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
{
expected = TokenType.EndOrBinary;
}
+ if (previousType == TokenType.Ternary && ternaryExpressions > 0 && tokens[^1].Name.Equals(":"))
+ {
+ ternaryExpressions--;
+ }
}
else if (c == '*' || c == '?')
{
@@ -692,11 +704,22 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
isWidth = false;
}
}
+ else if (c == '?')
+ {
+ ternaryExpressions++;
+ type = TokenType.Ternary;
+ expected = TokenType.StartOrOperand;
+ }
+ else if (c == ':' && ternaryExpressions > 0)
+ {
+ type = TokenType.Ternary;
+ expected = TokenType.StartOrOperand;
+ }
else if (TokenType.MoreTokens.HasFlag(type))
{
previousWasPlus = type == TokenType.Binary && c == '+';
if (type == TokenType.Open && c != '[')
- LogError(fileName, lineNumber, position + 1, "Unexpected token.", it.Index + 1, lineSource);
+ LogError(fileName, lineNumber, position + 1, "Unexpected token.", it.Index + 1, lineSource);
else
expected = TokenType.StartOrOperand;
}
@@ -712,11 +735,25 @@ List ProcessFromStream(string fileName, int lineNumber, StreamReader
break;
}
- previous = it.Current;
- previousType = type;
var token = new Token(new StringView(nextLine, position, size), type, position + 1);
token.LineSourceIndex = lineSources.Count - 1;
+ if (token.Type == TokenType.Operand && !token.IsSpecialOperator())
+ {
+ try
+ {
+ var radix = previousType == TokenType.Radix ? tokens[^1].Name : null;
+ var (valueType, value) = Evaluator.GetValue(radix, token.Name, _options.CaseSensitive ? StringViewComparer.Ordinal : StringViewComparer.IgnoreCase);
+ token.ValueType = valueType;
+ token.Value = value;
+ }
+ catch (Exception ex)
+ {
+ LogError(fileName, lineNumber, token.Position, ex.Message, token.Name.ToString(), lineSource);
+ }
+ }
tokens.Add(token);
+ previous = it.Current;
+ previousType = type;
}
}
if (blockComment && tokens.Count == 0)
diff --git a/Core6502DotNet/src/Utility/Json/JsonValidator.cs b/Core6502DotNet/src/Utility/Json/JsonValidator.cs
index dd08e81..c4f3cb3 100644
--- a/Core6502DotNet/src/Utility/Json/JsonValidator.cs
+++ b/Core6502DotNet/src/Utility/Json/JsonValidator.cs
@@ -102,7 +102,7 @@ AnnotationCollection ValidateInstance(Schema schema, JToken token)
default:
if (token.Type == JTokenType.String)
annotations.AddAnnotations(ValidateString(schema, token));
- else
+ else if (token.Type == JTokenType.Integer || token.Type == JTokenType.Float)
annotations.AddAnnotations(ValidateNumber(schema, token));
annotations.AddAnnotations(ValidateInSubschemas(schema, token, AnnotationAddType.None));
break;
@@ -114,7 +114,7 @@ AnnotationCollection ValidateInstance(Schema schema, JToken token)
static AnnotationCollection ValidateNumber(Schema schema, JToken token)
{
var annotations = new AnnotationCollection();
- var value = (long)token;
+ var value = (double)token;
if (!(!schema.ExclusiveMinimum.HasValue || value > schema.ExclusiveMinimum))
annotations.AddError($"{value} is not greater than {schema.ExclusiveMinimum}.",
schema, "exclusiveMinimum", token);
@@ -201,7 +201,7 @@ AnnotationCollection ValidateObject(Schema schema, JToken token)
annotations.AddAnnotations(dependencyCollection, AnnotationAddType.ErrorsAndProperties);
}
if (schema.PropertyNames != null)
- annotations.AddAnnotations(ValidateInstance(schema.PropertyNames, JToken.Parse($"\"{prop}\"")));
+ annotations.AddAnnotations(ValidateInstance(schema.PropertyNames, JToken.FromObject(prop)));
var jProp = jObject[prop];
if (schema.Properties?.ContainsKey(prop) == true)
{
@@ -426,9 +426,9 @@ AnnotationCollection ValidateInSubschemas(Schema schema, JToken token, Annotatio
if (schema.If != null)
{
var ifCollection = ValidateInstance(schema.If, token);
- annotations.AddAnnotations(ifCollection, ifCollection.Valid ? addType : AnnotationAddType.Errors);
if (ifCollection.Valid)
{
+ annotations.AddAnnotations(ifCollection, addType);
if (schema.Then != null)
annotations.AddAnnotations(ValidateInstance(schema.Then, token), addType | AnnotationAddType.Errors);
}
@@ -436,6 +436,10 @@ AnnotationCollection ValidateInSubschemas(Schema schema, JToken token, Annotatio
{
annotations.AddAnnotations(ValidateInstance(schema.Else, token), addType | AnnotationAddType.Errors);
}
+ else
+ {
+ annotations.AddAnnotations(ifCollection, addType | AnnotationAddType.Errors);
+ }
}
if (!string.IsNullOrEmpty(schema.Ref))
{
diff --git a/Core6502DotNet/src/Utility/Json/Schema.cs b/Core6502DotNet/src/Utility/Json/Schema.cs
index a64687d..ee9932d 100644
--- a/Core6502DotNet/src/Utility/Json/Schema.cs
+++ b/Core6502DotNet/src/Utility/Json/Schema.cs
@@ -108,7 +108,7 @@ static Schema()
Maximum = GetProperty(obj, "maximum");
ExclusiveMaximum = GetProperty(obj, "exclusiveMaximum");
ExclusiveMinimum = GetProperty(obj, "exclusiveMinimum");
- MultipleOf = GetProperty(obj, "multipleOf");
+ MultipleOf = GetProperty(obj, "multipleOf");
MinLength = GetProperty(obj, "minLength");
MaxLength = GetProperty(obj, "maxLength");
MinItems = GetProperty(obj, "minItems");
@@ -520,7 +520,7 @@ public string GetPath(bool absolute)
///
/// Validates the instance number is a multiple of the given value.
///
- public long? MultipleOf { get; }
+ public double? MultipleOf { get; }
///
/// Validates the instance number is greater than or equal to the given value.
diff --git a/Core6502DotNet/src/Utility/Json/SchemaBuilder.cs b/Core6502DotNet/src/Utility/Json/SchemaBuilder.cs
index 96d9cf2..2e78ce4 100644
--- a/Core6502DotNet/src/Utility/Json/SchemaBuilder.cs
+++ b/Core6502DotNet/src/Utility/Json/SchemaBuilder.cs
@@ -274,6 +274,7 @@ KeywordMapper AllDraftsPost4()
.Map("const", JTokenType.Raw);
KeywordMapper AllDraftsPost3()
=> new KeywordMapper().Map("multipleOf", JTokenType.Integer)
+ .Map("multipleOf", JTokenType.Float)
.Map("not", JTokenType.Object, MapToSchema)
.Map("type", JTokenType.Array);
diff --git a/Core6502DotNet/src/Utility/RandomAccessIterator.cs b/Core6502DotNet/src/Utility/RandomAccessIterator.cs
index d685ca5..a4970d5 100644
--- a/Core6502DotNet/src/Utility/RandomAccessIterator.cs
+++ b/Core6502DotNet/src/Utility/RandomAccessIterator.cs
@@ -46,11 +46,11 @@ public RandomAccessIterator(IEnumerable collection)
public RandomAccessIterator(IEnumerable collection, int firstIndex)
{
if (collection == null)
- throw new ArgumentNullException();
+ throw new ArgumentNullException(nameof(collection), "Argument cannot be null.");
_list = collection.ToArray();
_length = _list.Length;
if (_length > 0 && (firstIndex < -1 || firstIndex >= _length))
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(firstIndex), "Index is out of range.");
_firstIndex = firstIndex;
Index = firstIndex;
}
@@ -62,13 +62,25 @@ public RandomAccessIterator(IEnumerable collection, int firstIndex)
/// Reset the copied indicator.
///
public RandomAccessIterator(RandomAccessIterator iterator, bool reset)
+ : this(iterator, reset ? iterator._firstIndex : iterator.Index) {}
+
+ ///
+ /// Constructs a new instance of a class.
+ ///
+ /// An iterator from which to copy.
+ /// Point the copy to the desired index.
+ ///
+ ///
+ public RandomAccessIterator(RandomAccessIterator iterator, int index)
{
if (iterator == null)
- throw new ArgumentNullException();
+ throw new ArgumentNullException(nameof(iterator), "Argument cannot be null.");
+ if (index < -1 || index >= iterator._length)
+ throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
_firstIndex = iterator._firstIndex;
_list = iterator._list;
_length = iterator._length;
- Index = reset ? _firstIndex : iterator.Index;
+ Index = index;
}
#endregion
@@ -84,10 +96,10 @@ public RandomAccessIterator(RandomAccessIterator iterator, bool reset)
public void FastForward(int amount)
{
if (amount == 0)
- throw new ArgumentException();
+ throw new ArgumentException("Amount cannot be zero.");
if (amount < Index || amount >= _length)
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(amount), "Amount is out of range.");
Index = amount - 1;
}
@@ -146,7 +158,7 @@ public T PeekNextSkipping(Predicate predicate)
public void Rewind(int index)
{
if (index < _firstIndex || index >= Index)
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
Index = index;
}
@@ -168,7 +180,7 @@ public void SetIndex(int index)
if (index < Index)
Rewind(index);
else if (index >= _length)
- throw new ArgumentOutOfRangeException();
+ throw new ArgumentOutOfRangeException(nameof(index), "Index is out of range.");
Index = index;
}
diff --git a/Core6502DotNet/src/Utility/StringHelper.cs b/Core6502DotNet/src/Utility/StringHelper.cs
index 2a56126..8462da8 100644
--- a/Core6502DotNet/src/Utility/StringHelper.cs
+++ b/Core6502DotNet/src/Utility/StringHelper.cs
@@ -169,6 +169,10 @@ public static string GetFormatted(RandomAccessIterator iterator, Assembly
{
parms.Add(GetString(iterator, services));
}
+ else if (services.Evaluator.ExpressionIsCondition(iterator))
+ {
+ parms.Add(services.Evaluator.EvaluateCondition(iterator, false));
+ }
else
{
var parmVal = services.Evaluator.Evaluate(iterator, false);
diff --git a/Core6502DotNet/src/m680x/M6809Asm.cs b/Core6502DotNet/src/m680x/M6809Asm.cs
index 1e9bb76..21e940c 100644
--- a/Core6502DotNet/src/m680x/M6809Asm.cs
+++ b/Core6502DotNet/src/m680x/M6809Asm.cs
@@ -353,8 +353,7 @@ string AssembleIndexed(SourceLine line)
}
else if (modes.HasFlag(IndexModes.Indir))
{
- Services.Log.LogEntry(secondparam, "Addressing mode not supported for selected CPU.");
- return string.Empty;
+ return Services.Log.LogEntry(secondparam, "Addressing mode not supported for selected CPU.");
}
secondparam = operand.Current;
}
diff --git a/Core6502DotNet/src/m680x/MotorolaBase.cs b/Core6502DotNet/src/m680x/MotorolaBase.cs
index a15ce11..2bfe9fe 100644
--- a/Core6502DotNet/src/m680x/MotorolaBase.cs
+++ b/Core6502DotNet/src/m680x/MotorolaBase.cs
@@ -423,7 +423,7 @@ protected override string AssembleCpuInstruction(SourceLine line)
var sb = new StringBuilder();
if (!Services.Options.NoAssembly)
{
- var byteString = Services.Output.GetBytesFrom(LongPCOnAssemble).ToString(LongPCOnAssemble, '.');
+ var byteString = Services.Output.GetBytesFrom(LongLogicalPCOnAssemble).ToString(LogicalPCOnAssemble, '.');
sb.Append(byteString.PadRight(Padding));
}
else
diff --git a/Core6502DotNet/src/z80/Z80Asm.cs b/Core6502DotNet/src/z80/Z80Asm.cs
index 44506eb..113929a 100644
--- a/Core6502DotNet/src/z80/Z80Asm.cs
+++ b/Core6502DotNet/src/z80/Z80Asm.cs
@@ -316,7 +316,7 @@ protected override string AssembleCpuInstruction(SourceLine line)
var disasmBuilder = new StringBuilder();
if (!Services.Options.NoAssembly)
{
- var byteString = Services.Output.GetBytesFrom(LogicalPCOnAssemble).ToString(LogicalPCOnAssemble, '.', true);
+ var byteString = Services.Output.GetBytesFrom(LongLogicalPCOnAssemble).ToString(LogicalPCOnAssemble, '.', true);
disasmBuilder.Append(byteString.PadRight(25));
}
else
diff --git a/README.md b/README.md
index f2bdd54..31ef046 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
6502.Net, A .Net-Based Cross-Assembler for Several 8-Bit Microprocessors.
-Version 2.8.0.1
+Version 2.8.1.1
## Overview