void AssembleBinaryFile(SourceLine line) { if (!line.OperandHasToken) { throw new ExpressionException(line.Instruction.Position, "Filename not specified."); } BinaryFile file; var filename = line.Operand.Children[0].Children[0].Name; if (_includedBinaries.ContainsKey(filename)) { file = _includedBinaries[filename]; } else { if (!filename.EnclosedInDoubleQuotes()) { throw new ExpressionException(line.Operand.Position, "Filename not given in quotes."); } file = new BinaryFile(filename.TrimOnce('"')); if (!file.Open()) { throw new ExpressionException(line.Operand.Position, $"Unable to open file \"{filename}\"."); } _includedBinaries.Add(filename, file); } var offset = 0; var size = file.Data.Length; if (size > ushort.MaxValue) { throw new ExpressionException(line.Operand.Position, "File size is too large."); } if (line.Operand.Children.Count > 1) { if (line.Operand.Children.Count > 2) { if (line.Operand.Children.Count > 3) { throw new ExpressionException(line.Operand.Children[3].Position, "Too many arguments specified for directive."); } size = (int)Evaluator.Evaluate(line.Operand.Children[2].Children, ushort.MinValue, ushort.MaxValue); } offset = (int)Evaluator.Evaluate(line.Operand.Children[1].Children, ushort.MinValue, ushort.MaxValue); } if (offset > size - 1) { offset = size - 1; } if (size > file.Data.Length - offset) { size = file.Data.Length - offset; } if (size > ushort.MaxValue) { throw new ExpressionException(line.Operand.Position, $"Difference between specified offset and size is greater than the maximum allowed amount."); } line.Assembly = Assembler.Output.AddBytes(file.Data.Skip(offset), size); }
static void AssembleStrings(SourceLine line) { if (!line.OperandHasToken) { throw new ExpressionException(line.Instruction.Position, $"Instruction \"{line.InstructionName}\" expects one or more string arguments."); } line.Assembly = new List <byte>(); var stringBytes = new List <byte>(); var uninit = 0; foreach (Token child in line.Operand.Children) { if (child.Children.Count == 0) { throw new ExpressionException(child.Position, $"Expected value for instruction \"{line.InstructionName}\"."); } if (child.Children[0].ToString().Equals("?")) { if (child.Children.Count > 1) { Assembler.Log.LogEntry(line, child.Children[1].Position, $"Unexpected expression \"{child.Children[1].Name}\"."); } uninit++; Assembler.Output.AddUninitialized(1); } else { if (StringHelper.ExpressionIsAString(child)) { stringBytes.AddRange(Assembler.Encoding.GetBytes(StringHelper.GetString(child))); } else { stringBytes.AddRange(BinaryOutput.ConvertToBytes(Evaluator.Evaluate(child)).ToList()); } } } switch (line.InstructionName) { case ".cstring": stringBytes.Add(0x00); break; case ".pstring": if (stringBytes.Count > 255) { throw new ExpressionException(line.Operand.Position, $"String expression exceeds the maximum length of \".pstring\" directive."); } stringBytes.Insert(0, Convert.ToByte(stringBytes.Count)); break; case ".lstring": case ".nstring": if (stringBytes.Any(b => b > 0x7f)) { throw new ExpressionException(line.Operand.Position, $"One or more elements in expression \"{line.Operand}\" exceeds maximum value."); } if (line.InstructionName.Equals(".lstring")) { stringBytes = stringBytes.Select(b => Convert.ToByte(b << 1)).ToList(); stringBytes[^ 1] |= 1;
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); }