/// <summary> /// Increment the pass counter. /// </summary> /// <returns>The new value of the pass counter.</returns> public int DoNewPass() { CurrentPass++; SymbolManager.DefineGlobal("CURRENT_PASS", CurrentPass + 1); PassChanged?.Invoke(this, new EventArgs()); PassNeeded = false; return(CurrentPass); }
/// <summary> /// Creates a new instance of the assembly service. /// </summary> /// <param name="options">The parsed options.</param> public AssemblyServices(Options options) { PassNeeded = true; CurrentPass = -1; IsReserved = new List <Func <StringView, bool> >(); InstructionLookupRules = new List <Func <StringView, bool> > { sv => sv[0] == '.' }; Options = options; OutputFormat = Options.Format; CPU = Options.CPU; Encoding = new AsmEncoding(Options.CaseSensitive); Evaluator = new Evaluator(Options.CaseSensitive) { SymbolEvaluator = EvaluateSymbol }; SymbolManager = new SymbolManager(options.CaseSensitive, Evaluator); SymbolManager.AddValidSymbolNameCriterion(s => !Evaluator.IsReserved(s)); Log = new ErrorLog(Options.WarningsAsErrors); Output = new BinaryOutput(true, Options.CaseSensitive, Options.LongAddressing); }
/// <summary> /// Initializes the <see cref="Assembler"/> class for use. Repeated calls will reset symbol labels and variables, /// assembling pass and listing printing states, the binary output, and the error log. /// </summary> /// <param name="args">The command line arguments passed by the user.</param> public static void Initialize(string[] args) { PassChanged = null; PrintOff = false; PassNeeded = true; _pass = -1; LineIterator = null; Options = new CommandLineOptions(); IsReserved = new List <Func <string, bool> >(); InstructionLookupRules = new List <Func <string, bool> >(); if (args != null) { Options.ParseArgs(args); } Encoding = new AsmEncoding(Options.CaseSensitive); SymbolManager = new SymbolManager(Options.CaseSensitive); Evaluator.Initialize(); Evaluator.AddFunctionEvaluator(SymbolManager); Log = new ErrorLog(); Output = new BinaryOutput(); }
double EvaluateSymbol(RandomAccessIterator <Token> tokens) { var token = tokens.Current; var subscript = -1; 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 symbol = SymbolManager.GetSymbol(token, CurrentPass > 0); if (symbol == null) { if (token.Line.Label != null && token.Line.Label.Name.Equals(token.Name, StringViewComparer)) { throw new SymbolException(token, SymbolException.ExceptionReason.NotDefined); } PassNeeded = true; return(0x100); } 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; } else if (symbol.IsNumeric) { if (symbol.DataType == DataType.Address && symbol.Bank != Output.CurrentBank) { return((int)symbol.NumericValue | (symbol.Bank * 0x10000)); } return(symbol.NumericValue); } else { token = new Token(symbol.StringValue, TokenType.Operand); isString = true; } } if (isString || token.IsQuote()) { // is it a string literal? var literal = token.IsQuote() ? token.Name.TrimOnce(token.Name[0]).ToString() : token.Name.ToString(); if (string.IsNullOrEmpty(literal)) { throw new SyntaxException(token.Position, "Cannot evaluate empty string."); } literal = Regex.Unescape(literal); if (!isString) { var charsize = 1; if (char.IsSurrogate(literal[0])) { charsize++; } if (literal.Length > charsize) { throw new SyntaxException(token.Position, "Invalid char literal."); } } // get the integral equivalent from the code points in the string converted = Encoding.GetEncodedValue(literal); } else if (token.Name.Equals("*")) { // get the program counter converted = Output.LogicalPC; } else if (token.Name[0].IsSpecialOperator()) { // get the special character value if (token.Name[0] == '+' && CurrentPass == 0) { converted = Output.LogicalPC; PassNeeded = true; } else { converted = SymbolManager.GetLineReference(token.Name, token); if (double.IsNaN(converted)) { var reason = token.Name[0] == '+' ? SymbolException.ExceptionReason.InvalidForwardReference : SymbolException.ExceptionReason.InvalidBackReference; throw new SymbolException(token, reason); } } } if (double.IsNaN(converted)) { throw new ExpressionException(token.Position, $"\"{token.Name}\" is not a expression."); } return(converted); }