private void ParseDirectives(List<ListEntry> output, string line, bool lineFromMacro) { string directive = line.Substring(1); string[] parameters = directive.Split(' '); if (directive.ToLower() == "endif" || directive.ToLower() == "end") { if (IfStack.Count == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro ) ); else { IfStack.Pop(); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("elseif") || directive.ToLower().StartsWith("elif")) { if (IfStack.Count == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro ) ); else { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { var result = ParseExpression(line.Substring(line.IndexOf(' '))); if (result.Successful) { if (result.Value > 0) IfStack.Push(!IfStack.Pop()); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } } } else if (directive.ToLower() == "else") { if (IfStack.Count == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro ) ); else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); IfStack.Push(!IfStack.Pop()); } } else if (IfStack.Peek()) { if (directive.ToLower() == "region" || directive.ToLower() == "endregion") { } // Allowed but ignored else if (directive.ToLower() == "nolist") { noList = true; output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); } else if (directive.ToLower() == "list") { noList = false; output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); } else if ((directive.ToLower().StartsWith("dat ") || directive.ToLower().StartsWith("dw "))) { if (parameters.Length == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List<ushort> binOutput = new List<ushort>(); Dictionary<ushort, string> postponedExpressions = new Dictionary<ushort, string>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) binOutput.Add(b); } } else { postponedExpressions.Add((ushort)binOutput.Count, data.Trim()); binOutput.Add(0); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); output[output.Count - 1].PostponedExpressions = postponedExpressions; if (!noList) currentAddress += (ushort)binOutput.Count; } } else if (directive.ToLower().StartsWith("scope")) { if (parameters.Length < 2) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); else if (parameters.Length > 2) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); else { PriorGlobalLabel = parameters[1]; output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); } } else if (directive.ToLower() == "uniquescope") { PriorGlobalLabel = "_unique" + UniqueScopeNumber++; output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); } else if (directive.ToLower().StartsWith("echo")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); string consoleOutput = ""; foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); consoleOutput += str; } } else { ExpressionResult value = ParseExpression(data.Trim()); if (!value.Successful) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); else consoleOutput += value.Value; } } Console.Write(consoleOutput + "\n"); output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); output.Add( new ListEntry( consoleOutput, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); } } else if (directive.ToLower().StartsWith("ref")) { ReferencedValues.Add(directive.Substring(directive.IndexOf(" ") + 1)); } else if (directive.ToLower().StartsWith("asciip")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List<ushort> binOutput = new List<ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); binOutput.Add((ushort)str.Length); foreach (byte b in Encoding.ASCII.GetBytes(str)) binOutput.Add(b); } } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) currentAddress += (ushort)binOutput.Count; } } else if (directive.ToLower().StartsWith("asciic") || directive.ToLower().StartsWith("asciiz")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List<ushort> binOutput = new List<ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) binOutput.Add(b); binOutput.Add(0); } } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) currentAddress += (ushort)binOutput.Count; } } else if (directive.ToLower().StartsWith("ascii")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List<ushort> binOutput = new List<ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) binOutput.Add(b); } } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) currentAddress += (ushort)binOutput.Count; } } else if (directive.ToLower() == "longform") // Handled properly in the second pass output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); else if (directive.ToLower() == "shortform") output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); else if (directive.ToLower().StartsWith("org")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else if (parameters.Length > 2) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); } else { ExpressionResult value = ParseExpression(parameters[1]); if (value == null) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else { currentAddress = value.Value; var entry = new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList); entry.RootLineNumber = RootLineNumber; output.Add(entry); } } } else if (directive.ToLower().StartsWith("ifdef")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else if (parameters.Length > 2) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); } else { if (Values.ContainsKey(parameters[1].ToLower())) IfStack.Push(true); else IfStack.Push(false); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("ifndef")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else if (parameters.Length > 2) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); } else { if (Values.ContainsKey(parameters[1].ToLower())) IfStack.Push(false); else IfStack.Push(true); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("if")) { if (parameters.Length == 1) { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } else { var result = ParseExpression(line.Substring(3)); if (result.Successful) { if (result.Value > 0) IfStack.Push(true); else IfStack.Push(false); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } } else if (directive.ToLower().StartsWith("equ") || directive.ToLower().StartsWith("define") || directive.ToLower().StartsWith("equate")) { if (parameters.Length > 1) { if (Values.ContainsKey(parameters[1])) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.DuplicateName, lineFromMacro ) ); else { if (parameters.Length == 2) { Values.Add(parameters[1], 1); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else if (parameters.Length > 2) { string expression = directive.TrimExcessWhitespace(); expression = expression.Substring(expression.IndexOf(' ') + 1); expression = expression.Substring(expression.IndexOf(' ') + 1); ExpressionResult value = ParseExpression(expression); // TODO: find a way to forward reference if (value != null) { Values.Add(parameters[1], value.Value); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); } } } else if (directive.ToLower().StartsWith("pad") || directive.ToLower().StartsWith("fill")) // .pad length, value { parameters = line.SafeSplit(',', ' '); string[] fixedParams = new string[0]; foreach (string parameter in parameters) if (!string.IsNullOrEmpty(parameter)) fixedParams = fixedParams.Concat(new string[] { parameter }).ToArray(); parameters = fixedParams; if (parameters.Length == 3) { var length = ParseExpression(parameters[1]); var value = ParseExpression(parameters[2]); if (!length.Successful) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); else { ushort[] padding = new ushort[length.Value]; Dictionary<ushort, string> postponed = new Dictionary<ushort, string>(); for (int i = 0; i < padding.Length; i++) { padding[i] = value.Value; if (!value.Successful) postponed.Add((ushort)i, parameters[2]); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList)); output[output.Count - 1].PostponedExpressions = postponed; if (!noList) currentAddress += (ushort)padding.Length; } } else if (parameters.Length == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); } else if (directive.ToLower().StartsWith("reserve")) { if (parameters.Length == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); else { var expression = directive.Substring(7).Trim(); var result = ParseExpression(expression); if (result.Successful) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), new ushort[result.Value], currentAddress, !noList)); currentAddress += result.Value; } else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); } } else if (directive.ToLower().StartsWith("align")) // .align addr { if (parameters.Length == 2) { var addr = ParseExpression(parameters[1]); if (!addr.Successful) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro ) ); else { if (currentAddress > addr.Value) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.AlignToPast, lineFromMacro ) ); else { var amount = (ushort)(addr.Value - currentAddress); ushort[] padding = new ushort[amount]; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList)); if (!noList) currentAddress = addr.Value; } } } else if (parameters.Length == 1) output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro ) ); else output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro ) ); } else if (directive == "relocate") { OldAddress = currentAddress; currentAddress = 0; output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); output[output.Count - 1].CodeType = CodeType.RelocationTable; RelocationGroup++; IsRelocating = true; } else if (directive == "endrelocate") { // TODO: Errors output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro ) ); currentAddress = OldAddress; IsRelocating = false; } else { output.Add( new ListEntry( line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InvalidDirective, lineFromMacro ) ); } } output[output.Count - 1].CodeType = CodeType.Directive; }
private void ParseDirectives(List <ListEntry> output, string line, bool lineFromMacro) { string directive = line.Substring(1); string[] parameters = directive.Split(' '); if (directive.ToLower() == "endif" || directive.ToLower() == "end") { if (IfStack.Count == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro)); } else { IfStack.Pop(); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("elseif") || directive.ToLower().StartsWith("elif")) { if (IfStack.Count == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro)); } else { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { var result = ParseExpression(line.Substring(line.IndexOf(' '))); if (result.Successful) { if (result.Value > 0) { IfStack.Push(!IfStack.Pop()); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } } } else if (directive.ToLower() == "else") { if (IfStack.Count == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.UncoupledStatement, lineFromMacro)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); IfStack.Push(!IfStack.Pop()); } } else if (IfStack.Peek()) { if (directive.ToLower() == "region" || directive.ToLower() == "endregion") { } // Allowed but ignored else if (directive.ToLower() == "nolist") { noList = true; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); } else if (directive.ToLower() == "list") { noList = false; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); } else if ((directive.ToLower().StartsWith("dat ") || directive.ToLower().StartsWith("dw "))) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List <ushort> binOutput = new List <ushort>(); Dictionary <ushort, string> postponedExpressions = new Dictionary <ushort, string>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) { binOutput.Add(b); } } } else { postponedExpressions.Add((ushort)binOutput.Count, data.Trim()); binOutput.Add(0); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); output[output.Count - 1].PostponedExpressions = postponedExpressions; if (!noList) { currentAddress += (ushort)binOutput.Count; } } } else if (directive.ToLower().StartsWith("scope")) { if (parameters.Length < 2) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else if (parameters.Length > 2) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } else { PriorGlobalLabel = parameters[1]; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); } } else if (directive.ToLower() == "uniquescope") { PriorGlobalLabel = "_unique" + UniqueScopeNumber++; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); } else if (directive.ToLower().StartsWith("echo")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); string consoleOutput = ""; foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); consoleOutput += str; } } else { ExpressionResult value = ParseExpression(data.Trim()); if (!value.Successful) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { consoleOutput += value.Value; } } } Console.Write(consoleOutput + "\n"); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); output.Add(new ListEntry(consoleOutput, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); } } else if (directive.ToLower().StartsWith("ref")) { ReferencedValues.Add(directive.Substring(directive.IndexOf(" ") + 1)); } else if (directive.ToLower().StartsWith("asciip")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List <ushort> binOutput = new List <ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); binOutput.Add((ushort)str.Length); foreach (byte b in Encoding.ASCII.GetBytes(str)) { binOutput.Add(b); } } } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) { currentAddress += (ushort)binOutput.Count; } } } else if (directive.ToLower().StartsWith("asciic") || directive.ToLower().StartsWith("asciiz")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List <ushort> binOutput = new List <ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) { binOutput.Add(b); } binOutput.Add(0); } } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) { currentAddress += (ushort)binOutput.Count; } } } else if (directive.ToLower().StartsWith("ascii")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { string[] dataStrings = directive.Substring(directive.IndexOf(" ")).SafeSplit(','); List <ushort> binOutput = new List <ushort>(); foreach (string data in dataStrings) { if (data.Trim().StartsWith("\"")) { if (!data.Trim().EndsWith("\"")) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { string str = data.Trim().Substring(1, data.Trim().Length - 2).Unescape(); foreach (byte b in Encoding.ASCII.GetBytes(str)) { binOutput.Add(b); } } } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), binOutput.ToArray(), currentAddress, !noList)); if (!noList) { currentAddress += (ushort)binOutput.Count; } } } else if (directive.ToLower() == "longform") // Handled properly in the second pass { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else if (directive.ToLower() == "shortform") { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else if (directive.ToLower().StartsWith("org")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else if (parameters.Length > 2) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } else { ExpressionResult value = ParseExpression(parameters[1]); if (value == null) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { currentAddress = value.Value; var entry = new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList); entry.RootLineNumber = RootLineNumber; output.Add(entry); } } } else if (directive.ToLower().StartsWith("ifdef")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else if (parameters.Length > 2) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } else { if (Values.ContainsKey(parameters[1].ToLower())) { IfStack.Push(true); } else { IfStack.Push(false); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("ifndef")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else if (parameters.Length > 2) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } else { if (Values.ContainsKey(parameters[1].ToLower())) { IfStack.Push(false); } else { IfStack.Push(true); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } } else if (directive.ToLower().StartsWith("if")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { var result = ParseExpression(line.Substring(3)); if (result.Successful) { if (result.Value > 0) { IfStack.Push(true); } else { IfStack.Push(false); } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } } else if (directive.ToLower().StartsWith("equ") || directive.ToLower().StartsWith("define") || directive.ToLower().StartsWith("equate")) { if (parameters.Length > 1) { if (Values.ContainsKey(parameters[1])) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.DuplicateName, lineFromMacro)); } else { if (parameters.Length == 2) { Values.Add(parameters[1], 1); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else if (parameters.Length > 2) { string expression = directive.TrimExcessWhitespace(); expression = expression.Substring(expression.IndexOf(' ') + 1); expression = expression.Substring(expression.IndexOf(' ') + 1); ExpressionResult value = ParseExpression(expression); // TODO: find a way to forward reference if (value != null) { Values.Add(parameters[1], value.Value); output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } } } } else if (directive.ToLower().StartsWith("pad") || directive.ToLower().StartsWith("fill")) // .pad length, value { parameters = line.SafeSplit(',', ' '); string[] fixedParams = new string[0]; foreach (string parameter in parameters) { if (!string.IsNullOrEmpty(parameter)) { fixedParams = fixedParams.Concat(new string[] { parameter }).ToArray(); } } parameters = fixedParams; if (parameters.Length == 3) { var length = ParseExpression(parameters[1]); var value = ParseExpression(parameters[2]); if (!length.Successful) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { ushort[] padding = new ushort[length.Value]; Dictionary <ushort, string> postponed = new Dictionary <ushort, string>(); for (int i = 0; i < padding.Length; i++) { padding[i] = value.Value; if (!value.Successful) { postponed.Add((ushort)i, parameters[2]); } } output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList)); output[output.Count - 1].PostponedExpressions = postponed; if (!noList) { currentAddress += (ushort)padding.Length; } } } else if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } } else if (directive.ToLower().StartsWith("reserve")) { if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { var expression = directive.Substring(7).Trim(); var result = ParseExpression(expression); if (result.Successful) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), new ushort[result.Value], currentAddress, !noList)); currentAddress += result.Value; } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } } } else if (directive.ToLower().StartsWith("align")) // .align addr { if (parameters.Length == 2) { var addr = ParseExpression(parameters[1]); if (!addr.Successful) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.IllegalExpression, lineFromMacro)); } else { if (currentAddress > addr.Value) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.AlignToPast, lineFromMacro)); } else { var amount = (ushort)(addr.Value - currentAddress); ushort[] padding = new ushort[amount]; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), padding, currentAddress, !noList)); if (!noList) { currentAddress = addr.Value; } } } } else if (parameters.Length == 1) { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InsufficientParamters, lineFromMacro)); } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.TooManyParamters, lineFromMacro)); } } else if (directive == "relocate") { OldAddress = currentAddress; currentAddress = 0; output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); output[output.Count - 1].CodeType = CodeType.RelocationTable; RelocationGroup++; IsRelocating = true; } else if (directive == "endrelocate") { // TODO: Errors output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, lineFromMacro)); currentAddress = OldAddress; IsRelocating = false; } else { output.Add(new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, ErrorCode.InvalidDirective, lineFromMacro)); } } output[output.Count - 1].CodeType = CodeType.Directive; }
public static string CreateListing(List <ListEntry> output) { string listing = ""; int maxLength = 0, maxFileLength = 0; foreach (var entry in output) { int length = entry.FileName.Length + 1; if (length > maxFileLength) { maxFileLength = length; } } foreach (var entry in output) { int length = maxFileLength + entry.LineNumber.ToString().Length + 9; if (length > maxLength) { maxLength = length; } } TabifiedStringBuilder tsb; foreach (var listentry in output) { tsb = new TabifiedStringBuilder(); // FIX: TJMonk(04-20-2013) - Changing this code to use arrays, and adding support for '#' directives bool pass = false; if (listentry.ErrorCode == ErrorCode.Success) { string[] lineStarts = { ".", "#" }; string[] directives = { "dat", "dw", "db", "ascii", "asciiz", "asciip", "asciic", "align", "fill", "pad", "incbin", "reserve", "incpack", "relocate" }; string toCheck = listentry.Code.ToLower(); bool checkLineStart = false; foreach (var s in lineStarts) { if (toCheck.StartsWith(s)) { checkLineStart = true; toCheck = toCheck.Substring(s.Length); break; } } if (checkLineStart) { foreach (var s in directives) { if (toCheck.StartsWith(s)) { pass = true; break; } } } } if (pass) { // ENDFIX: TJMonk(04-20-2013) // Write code line tsb = new TabifiedStringBuilder(); tsb.WriteAt(0, listentry.FileName); tsb.WriteAt(maxFileLength, "(line " + listentry.LineNumber + "): "); if (listentry.Listed) { tsb.WriteAt(maxLength, "[0x" + LongHex(listentry.Address) + "] "); } else { tsb.WriteAt(maxLength, "[NOLIST] "); } tsb.WriteAt(maxLength + 25, listentry.Code); listing += tsb.Value + Environment.NewLine; // Write data if (listentry.Output != null) { for (int i = 0; i < listentry.Output.Length; i += 8) { tsb = new TabifiedStringBuilder(); tsb.WriteAt(0, listentry.FileName); tsb.WriteAt(maxFileLength, "(line " + listentry.LineNumber + "): "); //if (listentry.Listed) // tsb.WriteAt(maxLength, "[0x" + LongHex((ushort)(listentry.Address + i)) + "] "); //else tsb.WriteAt(maxLength, "[NOLIST] "); string data = ""; for (int j = 0; j < 8 && i + j < listentry.Output.Length; j++) { data += LongHex(listentry.Output[i + j]) + " "; } tsb.WriteAt(maxLength + 30, data.Remove(data.Length - 1)); listing += tsb.Value + Environment.NewLine; } } } else { if (listentry.ErrorCode != ErrorCode.Success) { tsb = new TabifiedStringBuilder(); tsb.WriteAt(0, listentry.FileName); tsb.WriteAt(maxFileLength, "(line " + listentry.LineNumber + "): "); if (listentry.Listed && listentry.Output != null) { tsb.WriteAt(maxLength, "[0x" + LongHex(listentry.Address) + "] "); } else { tsb.WriteAt(maxLength, "[NOLIST] "); } tsb.WriteAt(maxLength + 8, "ERROR: " + ListEntry.GetFriendlyErrorMessage(listentry.ErrorCode)); listing += tsb.Value + Environment.NewLine; } if (listentry.WarningCode != WarningCode.None) { tsb = new TabifiedStringBuilder(); tsb.WriteAt(0, listentry.FileName); tsb.WriteAt(maxFileLength, "(line " + listentry.LineNumber + "): "); if (listentry.Listed && listentry.Output != null) { tsb.WriteAt(maxLength, "[0x" + LongHex(listentry.Address) + "] "); } else { tsb.WriteAt(maxLength, "[NOLIST] "); } tsb.WriteAt(maxLength + 8, "WARNING: " + ListEntry.GetFriendlyWarningMessage(listentry.WarningCode)); listing += tsb.Value + Environment.NewLine; } tsb = new TabifiedStringBuilder(); tsb.WriteAt(0, listentry.FileName); tsb.WriteAt(maxFileLength, "(line " + listentry.LineNumber + "): "); if (listentry.Listed && (listentry.CodeType == CodeType.Label || listentry.Output != null)) { tsb.WriteAt(maxLength, "[0x" + LongHex(listentry.Address) + "] "); } else { tsb.WriteAt(maxLength, "[NOLIST] "); } if (listentry.Output != null) { if (listentry.Output.Length > 0) { tsb.WriteAt(maxLength + 8, DumpArray(listentry.Output)); tsb.WriteAt(maxLength + 25, listentry.Code); } } else { tsb.WriteAt(maxLength + 23, listentry.Code); } listing += tsb.Value + Environment.NewLine; } } return(listing); }
/// <summary> /// Assembles the provided code. /// This will use the current directory to fetch include files and such. /// </summary> /// <returns>A listing for the code</returns> public List<ListEntry> Assemble(string code, string FileName) { FileNames = new Stack<string>(); LineNumbers = new Stack<int>(); FileNames.Push(FileName); LineNumbers.Push(0); RootLineNumber = 0; IfStack.Push(true); bool isFromExpanded; // Pass one string[] lines = code.Replace("\r", "").Split('\n'); List<ListEntry> output = new List<ListEntry>(); for (int i = 0; i < lines.Length; i++) { isFromExpanded = false; if (SuspendedLineCounts.Count == 0) { LineNumbers.Push(LineNumbers.Pop() + 1); RootLineNumber++; } else { isFromExpanded = true; int count = SuspendedLineCounts.Pop(); count--; if (count > 0) SuspendedLineCounts.Push(count); } string line = lines[i].TrimComments().TrimExcessWhitespace(); if (string.IsNullOrEmpty(line)) continue; string[] sublines = line.SafeSplit('\\'); if (sublines.Length > 1) { string[] newLines = new string[lines.Length + sublines.Length - 1]; Array.Copy(lines, 0, newLines, 0, i); Array.Copy(sublines, 0, newLines, i, sublines.Length); if (lines.Length > i + 1) Array.Copy(lines, i + 1, newLines, i + sublines.Length, lines.Length - i - 1); lines = newLines; i--; SuspendedLineCounts.Push(sublines.Length); continue; } ListEntry listEntry = new ListEntry(line, FileNames.Peek(), LineNumbers.Peek(), currentAddress, !noList, isFromExpanded); listEntry.RootLineNumber = RootLineNumber; if (HandleCodeLine != null) { HandleCodeEventArgs args = new HandleCodeEventArgs(); args.Code = line; args.Handled = false; args.Output = listEntry; HandleCodeLine(this, args); if (args.Handled) { output.Add(args.Output); continue; } listEntry = args.Output; line = args.Code; } if (line.SafeContains(':') && !noList) { if (!IfStack.Peek()) continue; listEntry.CodeType = CodeType.Directive; // Parse labels string label = line; if (line.StartsWith(":")) { label = label.Substring(1); if (line.Contains(' ')) line = line.Substring(line.IndexOf(' ') + 1).Trim(); else line = ""; } else { label = label.Remove(label.IndexOf(':')); line = line.Substring(line.IndexOf(':') + 1); } line = line.Trim(); if (label.Contains(" ")) label = label.Remove(label.IndexOf(' ')); if (label == "$") { RelativeLabels.Add(GetRootNumber(LineNumbers), currentAddress); output.Add(listEntry); continue; } if (label.Contains(' ') || label.Contains('\t') || !(char.IsLetter(label[0]) || label[0] == '.' || label[0] == '_')) { listEntry.ErrorCode = ErrorCode.InvalidLabel; output.Add(listEntry); continue; } bool invalid = false; if (label.StartsWith("_")) { listEntry.ErrorCode = ErrorCode.InvalidLabel; output.Add(listEntry); continue; } foreach (char c in label) { if (!char.IsLetterOrDigit(c) && c != '_' && c != '.') { listEntry.ErrorCode = ErrorCode.InvalidLabel; output.Add(listEntry); invalid = true; break; } } if (invalid) continue; if (Values.ContainsKey(label) || LabelValues.ContainsKey(label)) { listEntry.ErrorCode = ErrorCode.DuplicateName; output.Add(listEntry); continue; } if (label.StartsWith(".")) label = PriorGlobalLabel + "_" + label.Substring(1); else PriorGlobalLabel = label; LabelValues.Add(new Label() { LineNumber = LineNumbers.Peek(), Name = label, RootLineNumber = listEntry.RootLineNumber, Address = currentAddress, }); if (!IsRelocating) LabelValues[LabelValues.Count - 1].RelocationGroup = -1; else LabelValues[LabelValues.Count - 1].RelocationGroup = RelocationGroup; listEntry.CodeType = CodeType.Label; output.Add(listEntry); } if (string.IsNullOrEmpty(line)) continue; if (line.Contains(".equ") && !line.StartsWith(".equ")) // TASM compatibility { line = ".equ " + line.Replace(".equ", "").TrimExcessWhitespace(); } if (line.StartsWith("dat ")) { line = "." + line; } if (line.StartsWith(".") || line.StartsWith("#")) { // #include has to be handled in this method if (line.StartsWith("#include") || line.StartsWith(".include")) { if (!IfStack.Peek()) continue; string includedFileName = line.Substring(line.IndexOf(" ") + 1); includedFileName = includedFileName.Trim('"', '\''); if (includedFileName.StartsWith("<") && includedFileName.EndsWith(">")) { // Find included file includedFileName = includedFileName.Trim('<', '>'); string[] paths = IncludePath.Split(new []{';'}, StringSplitOptions.RemoveEmptyEntries ); foreach (var path in paths) { if (File.Exists(Path.Combine(path, includedFileName))) { includedFileName = Path.Combine(path, includedFileName); break; } } } if (!File.Exists(includedFileName)) { listEntry.ErrorCode = ErrorCode.FileNotFound; output.Add(listEntry); } else if (IncludedFiles.Contains(includedFileName)) { } else { using (Stream includedFile = File.Open(includedFileName, FileMode.Open)) { StreamReader sr = new StreamReader(includedFile); string contents = sr.ReadToEnd(); sr.Close(); string[] newSource = contents.Replace("\r", "").Split('\n'); string[] newLines = new string[newSource.Length + lines.Length]; Array.Copy(lines, newLines, i); Array.Copy(newSource, 0, newLines, i, newSource.Length); newLines[i + newSource.Length] = "#endfile"; if (lines.Length > i + 1) Array.Copy(lines, i + 1, newLines, i + newSource.Length + 1, lines.Length - i - 1); lines = newLines; } WorkingDirectories.Push(Directory.GetCurrentDirectory()); if (Path.IsPathRooted(includedFileName)) Directory.SetCurrentDirectory(GetDirectory(includedFileName)); else Directory.SetCurrentDirectory(Path.Combine(Directory.GetCurrentDirectory(), GetDirectory(includedFileName))); FileNames.Push(includedFileName); LineNumbers.Push(0); IncludedFiles.Add(includedFileName); i--; continue; } } else if ((line.StartsWith("#incbin") || line.StartsWith(".incbin")) && !noList) { if (!IfStack.Peek()) continue; string includedFileName = line.Substring(line.IndexOf(" ") + 1); includedFileName = includedFileName.Trim('"', '\''); if (includedFileName.StartsWith("<") && includedFileName.EndsWith(">")) { // Find included file includedFileName = includedFileName.Trim('<', '>'); string[] paths = IncludePath.Split(';'); foreach (var path in paths) { if (File.Exists(Path.Combine(path, includedFileName))) { includedFileName = Path.Combine(path, includedFileName); break; } } } if (!File.Exists(includedFileName)) { listEntry.ErrorCode = ErrorCode.FileNotFound; output.Add(listEntry); } else { using (Stream includedFile = File.Open(includedFileName, FileMode.Open)) { byte[] rawData = new byte[includedFile.Length]; includedFile.Read(rawData, 0, (int)includedFile.Length); List<ushort> binOutput = new List<ushort>(); foreach (byte b in rawData) binOutput.Add(b); listEntry.Output = binOutput.ToArray(); output.Add(listEntry); output[output.Count - 1].CodeType = CodeType.Directive; if (!noList) currentAddress += (ushort)binOutput.Count; } } } else if ((line.StartsWith("#incpack") || line.StartsWith(".incpack")) && !noList) { if (!IfStack.Peek()) continue; string includedFileName = line.Substring(line.IndexOf(" ") + 1); includedFileName = includedFileName.Trim('"', '\''); if (includedFileName.StartsWith("<") && includedFileName.EndsWith(">")) { // Find included file includedFileName = includedFileName.Trim('<', '>'); string[] paths = IncludePath.Split(';'); foreach (var path in paths) { if (File.Exists(Path.Combine(path, includedFileName))) { includedFileName = Path.Combine(path, includedFileName); break; } } } if (!File.Exists(includedFileName)) { listEntry.ErrorCode = ErrorCode.FileNotFound; output.Add(listEntry); } else { using (Stream includedFile = File.Open(includedFileName, FileMode.Open)) { byte[] rawData = new byte[includedFile.Length]; includedFile.Read(rawData, 0, (int)includedFile.Length); List<ushort> binOutput = new List<ushort>(); for (int j = 0; j < rawData.Length; j += 2) { binOutput.Add((ushort)( rawData[j + 1] | (rawData[j] << 8) )); } listEntry.Output = binOutput.ToArray(); output.Add(listEntry); output[output.Count - 1].CodeType = CodeType.Directive; if (!noList) currentAddress += (ushort)binOutput.Count; } } } else if (line == "#endfile" || line == ".endfile") { if (!IfStack.Peek()) continue; FileNames.Pop(); LineNumbers.Pop(); RootLineNumber--; Directory.SetCurrentDirectory(WorkingDirectories.Pop()); } else if (line.StartsWith(".macro") && !noList) { if (!IfStack.Peek()) continue; string macroDefinition = line.Substring(7).Trim(); Macro macro = new Macro(); macro.Args = new string[0]; if (macroDefinition.EndsWith("{")) macroDefinition = macroDefinition.Remove(macroDefinition.Length - 1).Trim(); if (macroDefinition.Contains("(")) { string paramDefinition = macroDefinition.Substring(macroDefinition.IndexOf("(") + 1); macro.Name = macroDefinition.Remove(macroDefinition.IndexOf("(")).Trim(); if (!paramDefinition.EndsWith(")")) { listEntry.ErrorCode = ErrorCode.InvalidMacroDefintion; output.Add(listEntry); } else { paramDefinition = paramDefinition.Remove(paramDefinition.Length - 1); if (paramDefinition.Length > 0) { string[] parameters = paramDefinition.Split(','); bool continueEvaluation = true; for (int j = 0; j < parameters.Length; j++) { string parameter = parameters[j].Trim(); if (!char.IsLetter(parameter[0])) { continueEvaluation = false; break; } foreach (char c in parameter) { if (!char.IsLetterOrDigit(c) && c != '_') { continueEvaluation = false; break; } } if (!continueEvaluation) break; macro.Args = macro.Args.Concat(new string[] { parameter }).ToArray(); } if (!continueEvaluation) continue; } } } else macro.Name = macroDefinition; // Isolate macro code macro.Code = ""; bool foundEndmacro = false; string macroLine = line; i++; for (; i < lines.Length; i++) { line = lines[i].TrimComments().TrimExcessWhitespace(); LineNumbers.Push(LineNumbers.Pop() + 1); if (line == ".endmacro" || line == "#endmacro" || line == "}") { foundEndmacro = true; break; } if (line != "{") macro.Code += "\n" + line; } if (!foundEndmacro) { listEntry.ErrorCode = ErrorCode.UncoupledStatement; output.Add(listEntry); continue; } macro.Code = macro.Code.Trim('\n'); Macros.Add(macro); output.Add(new ListEntry(".macro " + macroDefinition, FileNames.Peek(), LineNumbers.Peek(), currentAddress, isFromExpanded)); output[output.Count - 1].CodeType = CodeType.Directive; foreach (var codeLine in macro.Code.Split('\n')) { output.Add( new ListEntry( codeLine, FileNames.Peek(), LineNumbers.Peek(), currentAddress, isFromExpanded ) ); output[output.Count - 1].CodeType = CodeType.Directive; } output.Add( new ListEntry( ".endmacro", FileNames.Peek(), LineNumbers.Peek(), currentAddress, isFromExpanded ) ); output[output.Count - 1].CodeType = CodeType.Directive; } else { // Parse preprocessor directives ParseDirectives( output, line, isFromExpanded ); } } else { if (!IfStack.Peek()) continue; // Search through macros bool mayHaveMacro = false; foreach (Macro macro in Macros) { if (line.StartsWith(macro.Name)) { mayHaveMacro = true; break; } } if (line.SafeContains('(') && line.SafeContains(')') && mayHaveMacro) { Macro userMacro = new Macro(); userMacro.Args = new string[0]; string macroDefinition = line; string paramDefinition = macroDefinition.Substring(macroDefinition.IndexOf("(") + 1); userMacro.Name = macroDefinition.Remove(macroDefinition.IndexOf("(")).Trim(); if (!paramDefinition.EndsWith(")")) { listEntry.ErrorCode = ErrorCode.InvalidMacroDefintion; output.Add(listEntry); } else { paramDefinition = paramDefinition.Remove(paramDefinition.Length - 1); if (paramDefinition.Length > 0) { string[] parameters = paramDefinition.SafeSplit(','); for (int j = 0; j < parameters.Length; j++) { string parameter = parameters[j].Trim(); userMacro.Args = userMacro.Args.Concat(new[] { parameter }).ToArray(); } } } bool macroMatched = false; foreach (Macro macro in Macros) { if (macro.Name == userMacro.Name && macro.Args.Length == userMacro.Args.Length) { // Expand the macro userMacro.Code = macro.Code; for (int j = 0; j < macro.Args.Length; j++) userMacro.Code = userMacro.Code.Replace(macro.Args[j], userMacro.Args[j]); string[] macroCode = userMacro.Code.Replace("\r", "\n").Split('\n'); string[] newLines = new string[lines.Length + macroCode.Length - 1]; Array.Copy(lines, 0, newLines, 0, i); Array.Copy(macroCode, 0, newLines, i, macroCode.Length); if (lines.Length > i + 1) Array.Copy(lines, i + 1, newLines, i + macroCode.Length, lines.Length - i - 1); lines = newLines; output.Add(listEntry); output[output.Count - 1].CodeType = CodeType.Directive; line = lines[i].TrimComments().TrimExcessWhitespace(); macroMatched = true; SuspendedLineCounts.Push(macroCode.Length); // Suspend the line counts for the expanded macro } } if (macroMatched) { i--; continue; } // We'll just let the opcode matcher yell at them if it isn't found } // Check for OPCodes var opcode = MatchString(line, OpcodeTable); bool nonBasic = false; if (opcode == null) { opcode = MatchString(line, NonBasicOpcodeTable); nonBasic = true; } if (opcode == null) { listEntry.ErrorCode = ErrorCode.InvalidOpcode; output.Add(listEntry); continue; } else { listEntry.Opcode = opcode; StringMatch valueA = null, valueB = null; listEntry.Output = new ushort[1]; if (!nonBasic) { listEntry.CodeType = CodeType.BasicInstruction; if (opcode.valueA != null) valueA = MatchString(opcode.valueA, ValueTable); if (opcode.valueB != null) valueB = MatchString(opcode.valueB, ValueTable); if (nonBasic == false && (opcode.valueA == null || opcode.valueB == null)) { listEntry.ErrorCode = ErrorCode.InvalidOpcode; output.Add(listEntry); continue; } if (valueA.value == valueB.value && valueA.value != 0x1E && valueB.value != 0x1E && opcode.value == 0x1) listEntry.WarningCode = WarningCode.RedundantStatement; if (valueB.value == 0x1F && !opcode.match.Contains("IF")) listEntry.WarningCode = WarningCode.AssignToLiteral; listEntry.ValueA = valueA; listEntry.ValueB = valueB; // De-localize labels if (listEntry.ValueA.isLiteral) { listEntry.Output = listEntry.Output.Concat(new ushort[1]).ToArray(); var result = ParseExpression(listEntry.ValueA.literal); foreach (var reference in result.References) { if (reference.StartsWith(".")) listEntry.ValueA.literal = listEntry.ValueA.literal.Replace(reference, PriorGlobalLabel + "_" + reference.Substring(1)); } } if (listEntry.ValueB.isLiteral) { listEntry.Output = listEntry.Output.Concat(new ushort[1]).ToArray(); var result = ParseExpression(listEntry.ValueB.literal); foreach (var reference in result.References) { if (reference.StartsWith(".")) listEntry.ValueB.literal = listEntry.ValueB.literal.Replace(reference, PriorGlobalLabel + "_" + reference.Substring(1)); } } } else { listEntry.CodeType = CodeType.NonBasicInstruction; if (opcode.valueA != null) valueA = MatchString(opcode.valueA, ValueTable); listEntry.ValueA = valueA; // De-localize labels if (listEntry.ValueA.isLiteral) { listEntry.Output = listEntry.Output.Concat(new ushort[1]).ToArray(); var result = ParseExpression(listEntry.ValueA.literal); foreach (var reference in result.References) { if (reference.StartsWith(".") || reference.StartsWith("_")) listEntry.ValueA.literal = listEntry.ValueA.literal.Replace(reference, PriorGlobalLabel + "_" + reference.Substring(1)); } } } output.Add(listEntry); currentAddress++; if (valueA != null) if (valueA.isLiteral) currentAddress++; if (valueB != null) if (valueB.isLiteral) currentAddress++; } } } return EvaluateAssembly(output); }
public static int Main(string[] args) { DateTime startTime = DateTime.Now; int returnCode = 0; DisplaySplash(); if (args.Length == 0) { DisplayHelp(); return(1); } string inputFile = null; string outputFile = null; string listingFile = null; string jsonFile = null; string pipe = null; string workingDirectory = Directory.GetCurrentDirectory(); bool bigEndian = true, quiet = false, verbose = false; Assembler assembler = new Assembler(); assembler.IncludePath = Environment.GetEnvironmentVariable("ORGINCLUDE"); if (string.IsNullOrEmpty(assembler.IncludePath)) { assembler.IncludePath = ""; } for (int i = 0; i < args.Length; i++) { string arg = args[i]; if (arg.StartsWith("-")) { try { switch (arg) { case "-h": case "-?": case "/h": case "/?": case "--help": DisplayHelp(); return(1); case "-o": case "--output": case "--output-file": outputFile = args[++i]; break; case "--input-file": inputFile = args[++i]; break; case "-e": case "--equate": ExpressionResult result = assembler.ParseExpression(args[i + 2]); if (!result.Successful) { Console.WriteLine("Error: " + ListEntry.GetFriendlyErrorMessage(ErrorCode.IllegalExpression)); return(1); } assembler.Values.Add(args[i + 1].ToLower(), result.Value); i += 2; break; case "-l": case "--listing": listingFile = args[++i]; break; case "--little-endian": bigEndian = false; break; case "--long-literals": assembler.ForceLongLiterals = true; break; case "--quiet": case "-q": quiet = true; break; case "--pipe": case "-p": pipe = args[++i]; break; case "--json": jsonFile = args[++i]; break; case "--include": case "-i": assembler.IncludePath = Environment.GetEnvironmentVariable("ORGINCLUDE") + ";" + args[++i]; break; case "--plugins": ListPlugins(assembler); return(0); case "--working-directory": case "-w": workingDirectory = args[++i]; break; case "--verbose": case "-v": verbose = true; break; case "--debug-mode": Console.ReadKey(); break; case "--install": assembler.InstallPlugin(args[++i]); return(0); case "--remove": assembler.RemovePlugin(args[++i]); return(0); case "--search": assembler.SearchPlugins(args[++i]); return(0); case "--info": assembler.GetInfo(args[++i]); return(0); default: HandleParameterEventArgs hpea = new HandleParameterEventArgs(arg); hpea.Arguments = args; hpea.Index = i; if (assembler.TryHandleParameter != null) { assembler.TryHandleParameter(assembler, hpea); } if (!hpea.Handled) { Console.WriteLine("Error: Invalid parameter: " + arg + "\nUse Organic.exe --help for usage information."); return(1); } else { i = hpea.Index; } if (hpea.StopProgram) { return(0); } break; } } catch (ArgumentOutOfRangeException) { Console.WriteLine("Error: Missing argument: " + arg + "\nUse Organic.exe --help for usage information."); return(1); } } else { if (inputFile == null) { inputFile = arg; } else if (outputFile == null) { outputFile = arg; } else { Console.WriteLine("Error: Invalid parameter: " + arg + "\nUse Organic.exe --help for usage information."); return(1); } } } if (inputFile == null && pipe == null) { Console.WriteLine("Error: No input file specified.\nUse Organic.exe --help for usage information."); return(1); } if (outputFile == null) { outputFile = Path.GetFileNameWithoutExtension(inputFile) + ".bin"; } if (!File.Exists(inputFile) && pipe == null && inputFile != "-") { Console.WriteLine("Error: File not found (" + inputFile + ")"); return(1); } string contents; if (pipe == null) { if (inputFile != "-") { StreamReader reader = new StreamReader(inputFile); contents = reader.ReadToEnd(); reader.Close(); } else { contents = Console.In.ReadToEnd(); } } else { contents = pipe; } List <ListEntry> output; string wdOld = Directory.GetCurrentDirectory(); Directory.SetCurrentDirectory(workingDirectory); if (pipe == null) { output = assembler.Assemble(contents, inputFile); } else { output = assembler.Assemble(contents, "[piped input]"); } Directory.SetCurrentDirectory(wdOld); if (assembler.AssemblyComplete != null) { assembler.AssemblyComplete(assembler, new AssemblyCompleteEventArgs(output)); } // Output errors if (!quiet) { foreach (var entry in output) { if (entry.ErrorCode != ErrorCode.Success) { Console.Error.WriteLine("Error " + entry.FileName + " (line " + entry.LineNumber + "): " + ListEntry.GetFriendlyErrorMessage(entry.ErrorCode)); returnCode = 1; } if (entry.WarningCode != WarningCode.None) { Console.WriteLine("Warning " + entry.FileName + " (line " + entry.LineNumber + "): " + ListEntry.GetFriendlyWarningMessage(entry.WarningCode)); } } } ushort currentAddress = 0; Stream binStream = null; if (outputFile != "-") { if (!string.IsNullOrEmpty(Path.GetDirectoryName(outputFile))) { Directory.CreateDirectory(Path.GetDirectoryName(outputFile)); } binStream = File.Open(outputFile, FileMode.Create); } foreach (var entry in output) { if (entry.Output != null) { foreach (ushort value in entry.Output) { currentAddress++; byte[] buffer = BitConverter.GetBytes(value); if (bigEndian) { Array.Reverse(buffer); } if (outputFile != "-") { binStream.Write(buffer, 0, buffer.Length); } else { Console.Out.Write(Encoding.ASCII.GetString(buffer)); } } } } string listing = ""; if (listingFile != null || verbose) { listing = CreateListing(output); } string json = ""; if (jsonFile != null) { json = CreateJson(output); } if (verbose) { Console.Write(listing); } if (listingFile != null) { if (!string.IsNullOrEmpty(Path.GetDirectoryName(listingFile))) { Directory.CreateDirectory(Path.GetDirectoryName(listingFile)); } var writer = new StreamWriter(listingFile); writer.Write(listing); writer.Close(); } if (jsonFile != null) { if (!string.IsNullOrEmpty(Path.GetDirectoryName(jsonFile))) { Directory.CreateDirectory(Path.GetDirectoryName(jsonFile)); } var writer = new StreamWriter(jsonFile); writer.Write(json); writer.Close(); } TimeSpan duration = DateTime.Now - startTime; Console.WriteLine("Organic build complete " + duration.TotalMilliseconds + "ms"); return(returnCode); }