private ExpressionResult EvaluateParenthesis(string value) { while (value.Contains("(")) { int openingParenthesis = -1, closingParenthesis = -1, parenCount = 0; for (int i = 0; i < value.Length; i++) { if (value[i] == '(') { parenCount++; if (parenCount == 1) { openingParenthesis = i; } } if (value[i] == ')') { parenCount--; if (parenCount == 0) { closingParenthesis = i; break; } } } if (openingParenthesis == -1 || closingParenthesis == -1) { var expressionResult = new ExpressionResult(); expressionResult.Successful = false; return(expressionResult); } ExpressionResult subExpression = ParseExpression(value.Substring(openingParenthesis + 1, closingParenthesis - (openingParenthesis + 1))); if (!subExpression.Successful) { return(subExpression); } value = value.Remove(openingParenthesis) + subExpression.Value.ToString() + value.Substring(closingParenthesis + 1); } return(ParseExpression(value)); }
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; }
/// <summary> /// Given an expression, it will parse it and return the result as a nullable ushort /// </summary> /// <param name="value"></param> /// <returns></returns> public ExpressionResult ParseExpression(string value) { ExpressionResult expressionResult = new ExpressionResult(); expressionResult.Successful = true; expressionResult.References = new List <string>(); value = value.Trim(); if (HandleExpression != null) { HandleExpressionEventArgs heea = new HandleExpressionEventArgs(value); HandleExpression(this, heea); value = heea.Expression; } if (value.SafeContains('(')) { // Check for advanced expression handlers foreach (var item in ExpressionExtensions) { if (value.StartsWith(item.Key.ToLower() + "(")) { string expr = value.Substring(value.SafeIndexOf('(') + 1); expr = expr.Remove(expr.Length - 1); expressionResult.Value = item.Value(expr); return(expressionResult); } } return(EvaluateParenthesis(value)); } if (value.StartsWith("~")) { expressionResult = ParseExpression(value.Substring(1)); if (expressionResult.Successful) { expressionResult.Value = (ushort)~expressionResult.Value; } return(expressionResult); } if (!HasOperators(value)) { // Parse value ushort result; EvaluateValueEventArgs args = new EvaluateValueEventArgs(value); if (EvaluateExpressionValue != null) { EvaluateExpressionValue(this, args); } if (args.Handled) { expressionResult.Value = args.Result; return(expressionResult); } else if (value.StartsWith("0d")) { value = value.Substring(2); } if (value.StartsWith("'")) // Character { if (value.Length < 3) { expressionResult.Successful = false; return(expressionResult); } value = value.Substring(1, value.Length - 2).Unescape(); if (value == null) { expressionResult.Successful = false; return(expressionResult); } if (value.Length != 1) { expressionResult.Successful = false; return(expressionResult); } expressionResult.Value = (ushort)Encoding.ASCII.GetBytes(value)[0]; return(expressionResult); } else if (value.StartsWith("{") && value.EndsWith("}")) // instruction literal { string instruction = value.Substring(1, value.Length - 2); Assembler subAssembler = new Assembler(); List <ListEntry> assembly = subAssembler.Assemble(instruction); if (assembly.Count == 0) { expressionResult.Successful = false; return(expressionResult); } if (assembly[0].Output == null) { expressionResult.Successful = false; return(expressionResult); } if (assembly[0].Output.Length == 0) { expressionResult.Successful = false; return(expressionResult); } expressionResult.Value = assembly[0].Output[0]; return(expressionResult); } else if (value.StartsWith("0x")) // Hex { value = value.Substring(2); if (!ushort.TryParse(value.Replace("_", ""), NumberStyles.HexNumber, null, out result)) { expressionResult.Successful = false; return(expressionResult); } else { expressionResult.Value = result; return(expressionResult); } } else if (value.StartsWith("0b")) // Binary { value = value.Substring(2); ushort?binResult = ParseBinary(value.Replace("_", "")); if (binResult == null) { expressionResult.Successful = false; } else { expressionResult.Value = binResult.Value; } return(expressionResult); } else if (value.StartsWith("0o")) { value = value.Substring(2); try { expressionResult.Value = Convert.ToUInt16(value.Replace("_", ""), 8); return(expressionResult); } catch { expressionResult.Successful = false; return(expressionResult); } } else if (ushort.TryParse(value.Replace("_", ""), out result)) // Decimal { expressionResult.Value = result; return(expressionResult); } else if (value == "$") { if (LineNumbers.Count == 0) { expressionResult.Successful = false; return(expressionResult); } expressionResult.Value = currentAddress; return(expressionResult); } else if (value.StartsWith("$")) // Relative label { if (LineNumbers.Count == 0) { expressionResult.Successful = false; return(expressionResult); } value = value.Substring(1); int nextLabelIndex = -1; // Find the next relative label after the current line for (int i = 0; i < RelativeLabels.Count; i++) { if (RelativeLabels.ElementAt(i).Key > LineNumbers.Peek()) { nextLabelIndex = i; break; } } if (nextLabelIndex == -1) { nextLabelIndex = RelativeLabels.Count - 1; // If no such label is found, use the last one } bool initialPlus = true; // For each plus, increment that label index, and each minus decrements it foreach (char c in value) { if (c == '+') // The intial plus symbol is ignored { if (initialPlus) { nextLabelIndex++; } initialPlus = false; } else if (c == '-') { nextLabelIndex--; } } if (nextLabelIndex < 0) { expressionResult.Successful = false; return(expressionResult); } if (nextLabelIndex > RelativeLabels.Count - 1) { expressionResult.Successful = false; return(expressionResult); } expressionResult.Value = RelativeLabels.ElementAt(nextLabelIndex).Value; return(expressionResult); } else if (value.ToLower() == "true") { expressionResult.Value = 1; return(expressionResult); } else if (value.ToLower() == "false") { expressionResult.Value = 0; return(expressionResult); } else // Defined value or error { if (value.StartsWith(".")) { value = PriorGlobalLabel + "_" + value.Substring(1); } if (Values.ContainsKey(value)) { expressionResult.Value = Values[value]; } else if (LabelValues.ContainsKey(value)) { expressionResult.Relocate = true; expressionResult.Value = LabelValues.GetValue(value); } else { expressionResult.Successful = false; } expressionResult.References.Add(value); if (!ReferencedValues.Contains(value)) { ReferencedValues.Add(value); } return(expressionResult); } } // Parse expression string[] operands = GetOperands(value); if (operands == null) { expressionResult.Successful = false; return(expressionResult); } if (string.IsNullOrEmpty(operands[0]) && operands[1] == "-") { expressionResult = ParseExpression(operands[2]); expressionResult.Value = (ushort)-expressionResult.Value; return(expressionResult); } if (operands == null) { expressionResult.Successful = false; return(expressionResult); } ExpressionResult left = ParseExpression(operands[0]); ExpressionResult right = ParseExpression(operands[2]); expressionResult.References.AddRange(left.References.Concat(right.References)); if ((!left.Successful || !right.Successful) && operands[1] != "===" && operands[1] != "!==") { expressionResult.Successful = false; return(expressionResult); } switch (operands[1]) { case "*": expressionResult.Value = (ushort)(left.Value * right.Value); break; case "/": expressionResult.Value = (ushort)(left.Value / right.Value); break; case "+": expressionResult.Value = (ushort)(left.Value + right.Value); break; case "-": expressionResult.Value = (ushort)(left.Value - right.Value); break; case "<<": expressionResult.Value = (ushort)(left.Value << right.Value); break; case ">>": expressionResult.Value = (ushort)(left.Value >> right.Value); break; case "|": expressionResult.Value = (ushort)(left.Value | right.Value); break; case "^": expressionResult.Value = (ushort)(left.Value ^ right.Value); break; case "&": expressionResult.Value = (ushort)(left.Value & right.Value); break; case "%": expressionResult.Value = (ushort)(left.Value % right.Value); break; case "==": expressionResult.Value = (ushort)(left.Value == right.Value ? 1 : 0); break; case "!=": case "<>": expressionResult.Value = (ushort)(left.Value != right.Value ? 1 : 0); break; case "<": expressionResult.Value = (ushort)(left.Value < right.Value ? 1 : 0); break; case ">": expressionResult.Value = (ushort)(left.Value > right.Value ? 1 : 0); break; case "<=": expressionResult.Value = (ushort)(left.Value <= right.Value ? 1 : 0); break; case ">=": expressionResult.Value = (ushort)(left.Value >= right.Value ? 1 : 0); break; case "===": expressionResult.Value = (ushort)(operands[0].ToLower().Trim() == operands[2].ToLower().Trim() ? 1 : 0); break; case "!==": expressionResult.Value = (ushort)(operands[0].ToLower().Trim() != operands[2].ToLower().Trim() ? 1 : 0); break; case "&&": expressionResult.Value = (ushort)(left.Value > 0 && right.Value > 1 ? 1 : 0); break; case "||": expressionResult.Value = (ushort)(left.Value > 0 || right.Value > 1 ? 1 : 0); break; case "^^": expressionResult.Value = (ushort)(left.Value > 0 ^ right.Value > 1 ? 1 : 0); // between boolean operators, ^ is ^^ in C# break; default: expressionResult.Successful = false; return(expressionResult); } return(expressionResult); }
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); }
private ExpressionResult EvaluateParenthesis(string value) { while (value.Contains("(")) { int openingParenthesis = -1, closingParenthesis = -1, parenCount = 0; for (int i = 0; i < value.Length; i++) { if (value[i] == '(') { parenCount++; if (parenCount == 1) openingParenthesis = i; } if (value[i] == ')') { parenCount--; if (parenCount == 0) { closingParenthesis = i; break; } } } if (openingParenthesis == -1 || closingParenthesis == -1) { var expressionResult = new ExpressionResult(); expressionResult.Successful = false; return expressionResult; } ExpressionResult subExpression = ParseExpression(value.Substring(openingParenthesis + 1, closingParenthesis - (openingParenthesis + 1))); if (!subExpression.Successful) return subExpression; value = value.Remove(openingParenthesis) + subExpression.Value.ToString() + value.Substring(closingParenthesis + 1); } return ParseExpression(value); }
/// <summary> /// Given an expression, it will parse it and return the result as a nullable ushort /// </summary> /// <param name="value"></param> /// <returns></returns> public ExpressionResult ParseExpression(string value) { ExpressionResult expressionResult = new ExpressionResult(); expressionResult.Successful = true; expressionResult.References = new List<string>(); value = value.Trim(); if (HandleExpression != null) { HandleExpressionEventArgs heea = new HandleExpressionEventArgs(value); HandleExpression(this, heea); value = heea.Expression; } if (value.SafeContains('(')) { // Check for advanced expression handlers foreach (var item in ExpressionExtensions) { if (value.StartsWith(item.Key.ToLower() + "(")) { string expr = value.Substring(value.SafeIndexOf('(') + 1); expr = expr.Remove(expr.Length - 1); expressionResult.Value = item.Value(expr); return expressionResult; } } return EvaluateParenthesis(value); } if (value.StartsWith("~")) { expressionResult = ParseExpression(value.Substring(1)); if (expressionResult.Successful) expressionResult.Value = (ushort)~expressionResult.Value; return expressionResult; } if (!HasOperators(value)) { // Parse value ushort result; EvaluateValueEventArgs args = new EvaluateValueEventArgs(value); if (EvaluateExpressionValue != null) { EvaluateExpressionValue(this, args); } if (args.Handled) { expressionResult.Value = args.Result; return expressionResult; } else if (value.StartsWith("0d")) value = value.Substring(2); if (value.StartsWith("'")) // Character { if (value.Length < 3) { expressionResult.Successful = false; return expressionResult; } value = value.Substring(1, value.Length - 2).Unescape(); if (value == null) { expressionResult.Successful = false; return expressionResult; } if (value.Length != 1) { expressionResult.Successful = false; return expressionResult; } expressionResult.Value = (ushort)Encoding.ASCII.GetBytes(value)[0]; return expressionResult; } else if (value.StartsWith("{") && value.EndsWith("}")) // instruction literal { string instruction = value.Substring(1, value.Length - 2); Assembler subAssembler = new Assembler(); List<ListEntry> assembly = subAssembler.Assemble(instruction); if (assembly.Count == 0) { expressionResult.Successful = false; return expressionResult; } if (assembly[0].Output == null) { expressionResult.Successful = false; return expressionResult; } if (assembly[0].Output.Length == 0) { expressionResult.Successful = false; return expressionResult; } expressionResult.Value = assembly[0].Output[0]; return expressionResult; } else if (value.StartsWith("0x")) // Hex { value = value.Substring(2); if (!ushort.TryParse(value.Replace("_", ""), NumberStyles.HexNumber, null, out result)) { expressionResult.Successful = false; return expressionResult; } else { expressionResult.Value = result; return expressionResult; } } else if (value.StartsWith("0b")) // Binary { value = value.Substring(2); ushort? binResult = ParseBinary(value.Replace("_", "")); if (binResult == null) expressionResult.Successful = false; else expressionResult.Value = binResult.Value; return expressionResult; } else if (value.StartsWith("0o")) { value = value.Substring(2); try { expressionResult.Value = Convert.ToUInt16(value.Replace("_", ""), 8); return expressionResult; } catch { expressionResult.Successful = false; return expressionResult; } } else if (ushort.TryParse(value.Replace("_", ""), out result)) // Decimal { expressionResult.Value = result; return expressionResult; } else if (value == "$") { if (LineNumbers.Count == 0) { expressionResult.Successful = false; return expressionResult; } expressionResult.Value = currentAddress; return expressionResult; } else if (value.StartsWith("$")) // Relative label { if (LineNumbers.Count == 0) { expressionResult.Successful = false; return expressionResult; } value = value.Substring(1); int nextLabelIndex = -1; // Find the next relative label after the current line for (int i = 0; i < RelativeLabels.Count; i++) { if (RelativeLabels.ElementAt(i).Key > LineNumbers.Peek()) { nextLabelIndex = i; break; } } if (nextLabelIndex == -1) nextLabelIndex = RelativeLabels.Count - 1; // If no such label is found, use the last one bool initialPlus = true; // For each plus, increment that label index, and each minus decrements it foreach (char c in value) { if (c == '+') // The intial plus symbol is ignored { if (initialPlus) nextLabelIndex++; initialPlus = false; } else if (c == '-') nextLabelIndex--; } if (nextLabelIndex < 0) { expressionResult.Successful = false; return expressionResult; } if (nextLabelIndex > RelativeLabels.Count - 1) { expressionResult.Successful = false; return expressionResult; } expressionResult.Value = RelativeLabels.ElementAt(nextLabelIndex).Value; return expressionResult; } else if (value.ToLower() == "true") { expressionResult.Value = 1; return expressionResult; } else if (value.ToLower() == "false") { expressionResult.Value = 0; return expressionResult; } else // Defined value or error { if (value.StartsWith(".")) value = PriorGlobalLabel + "_" + value.Substring(1); if (Values.ContainsKey(value)) expressionResult.Value = Values[value]; else if (LabelValues.ContainsKey(value)) { expressionResult.Relocate = true; expressionResult.Value = LabelValues.GetValue(value); } else expressionResult.Successful = false; expressionResult.References.Add(value); if (!ReferencedValues.Contains(value)) ReferencedValues.Add(value); return expressionResult; } } // Parse expression string[] operands = GetOperands(value); if (operands == null) { expressionResult.Successful = false; return expressionResult; } if (string.IsNullOrEmpty(operands[0]) && operands[1] == "-") { expressionResult = ParseExpression(operands[2]); expressionResult.Value = (ushort)-expressionResult.Value; return expressionResult; } if (operands == null) { expressionResult.Successful = false; return expressionResult; } ExpressionResult left = ParseExpression(operands[0]); ExpressionResult right = ParseExpression(operands[2]); expressionResult.References.AddRange(left.References.Concat(right.References)); if ((!left.Successful || !right.Successful) && operands[1] != "===" && operands[1] != "!==") { expressionResult.Successful = false; return expressionResult; } switch (operands[1]) { case "*": expressionResult.Value = (ushort)(left.Value * right.Value); break; case "/": expressionResult.Value = (ushort)(left.Value / right.Value); break; case "+": expressionResult.Value = (ushort)(left.Value + right.Value); break; case "-": expressionResult.Value = (ushort)(left.Value - right.Value); break; case "<<": expressionResult.Value = (ushort)(left.Value << right.Value); break; case ">>": expressionResult.Value = (ushort)(left.Value >> right.Value); break; case "|": expressionResult.Value = (ushort)(left.Value | right.Value); break; case "^": expressionResult.Value = (ushort)(left.Value ^ right.Value); break; case "&": expressionResult.Value = (ushort)(left.Value & right.Value); break; case "%": expressionResult.Value = (ushort)(left.Value % right.Value); break; case "==": expressionResult.Value = (ushort)(left.Value == right.Value ? 1 : 0); break; case "!=": case "<>": expressionResult.Value = (ushort)(left.Value != right.Value ? 1 : 0); break; case "<": expressionResult.Value = (ushort)(left.Value < right.Value ? 1 : 0); break; case ">": expressionResult.Value = (ushort)(left.Value > right.Value ? 1 : 0); break; case "<=": expressionResult.Value = (ushort)(left.Value <= right.Value ? 1 : 0); break; case ">=": expressionResult.Value = (ushort)(left.Value >= right.Value ? 1 : 0); break; case "===": expressionResult.Value = (ushort)(operands[0].ToLower().Trim() == operands[2].ToLower().Trim() ? 1 : 0); break; case "!==": expressionResult.Value = (ushort)(operands[0].ToLower().Trim() != operands[2].ToLower().Trim() ? 1 : 0); break; case "&&": expressionResult.Value = (ushort)(left.Value > 0 && right.Value > 1 ? 1 : 0); break; case "||": expressionResult.Value = (ushort)(left.Value > 0 || right.Value > 1 ? 1 : 0); break; case "^^": expressionResult.Value = (ushort)(left.Value > 0 ^ right.Value > 1 ? 1 : 0); // between boolean operators, ^ is ^^ in C# break; default: expressionResult.Successful = false; return expressionResult; } return expressionResult; }