private BlockNode ParseBlock(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { Location start = tokens.Current.Location; tokens.MoveNext(); BlockNode temp = new BlockNode(); Maybe <ILineNode> x; while (!tokens.EOS && tokens.Current.Type != TokenType.CLOSE_BRACE) { if (!(x = ParseLine(tokens, scopes)).IsNothing) { temp.Children.Add(x.FromJust); } } if (!tokens.EOS) { tokens.MoveNext(); } else { Error(start, "Unmatched brace."); } return(temp); }
private void IgnoreRestOfLine(MergeableGenerator <Token> tokens) { while (tokens.Current.Type != TokenType.NEWLINE && tokens.MoveNext()) { ; } }
private IList <IAtomNode> ParseList(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { Token head = tokens.Current; tokens.MoveNext(); IList <IAtomNode> atoms = new List <IAtomNode>(); while (tokens.Current.Type != TokenType.NEWLINE && tokens.Current.Type != TokenType.CLOSE_BRACKET) { Maybe <IAtomNode> res = ParseAtom(tokens, scopes); res.IfJust( (IAtomNode n) => atoms.Add(n), () => Error(tokens.Current.Location, "Expected atomic value, got " + tokens.Current.Type + ".")); if (tokens.Current.Type == TokenType.COMMA) { tokens.MoveNext(); } } if (tokens.Current.Type == TokenType.CLOSE_BRACKET) { tokens.MoveNext(); } else { Error(head.Location, "Unmatched open bracket."); } return(atoms); }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { BlockNode result = new BlockNode(); // Iterating indices (and not values via foreach) // to avoid crashes occuring with AddToPool within AddToPool for (int i = 0; i < p.Pool.Lines.Count; ++i) { Pool.PooledLine line = p.Pool.Lines[i]; MergeableGenerator <Token> tempGenerator = new MergeableGenerator <Token>(line.Tokens); tempGenerator.MoveNext(); while (!tempGenerator.EOS) { p.ParseLine(tempGenerator, line.Scope).IfJust( (lineNode) => result.Children.Add(lineNode)); } } p.Pool.Lines.Clear(); return(new Just <ILineNode>(result)); }
private void IgnoreRestOfStatement(MergeableGenerator <Token> tokens) { while (tokens.Current.Type != TokenType.NEWLINE && tokens.Current.Type != TokenType.SEMICOLON && tokens.MoveNext()) { ; } if (tokens.Current.Type == TokenType.SEMICOLON) { tokens.MoveNext(); } }
private IList <IParamNode> ParsePreprocParamList(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { IList <IParamNode> temp = ParseParamList(tokens, scopes, false); for (int i = 0; i < temp.Count; i++) { if (temp[i].Type == ParamType.STRING && ((StringNode)temp[i]).IsValidIdentifier()) { temp[i] = ((StringNode)temp[i]).ToIdentifier(scopes); } } return(temp); }
private Maybe <ILineNode> ParsePreprocessor(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { head = tokens.Current; tokens.MoveNext(); //Note: Not a ParseParamList because no commas. IList <IParamNode> paramList = ParsePreprocParamList(tokens, scopes); Maybe <ILineNode> retVal = directiveHandler.HandleDirective(this, head, paramList, tokens); if (!retVal.IsNothing) { CheckDataWrite(retVal.FromJust.Size); CurrentOffset += retVal.FromJust.Size; } return(retVal); }
public IList <ILineNode> ParseAll(IEnumerable <Token> tokenStream) { //TODO: Make BlockNode or EAProgramNode? //Note must be strict to get all information on the closure before evaluating terms. IList <ILineNode> myLines = new List <ILineNode>(); MergeableGenerator <Token> tokens = new MergeableGenerator <Token>(tokenStream); tokens.MoveNext(); while (!tokens.EOS) { if (tokens.Current.Type != TokenType.NEWLINE || tokens.MoveNext()) { Maybe <ILineNode> retVal = ParseLine(tokens, GlobalScope); retVal.IfJust((ILineNode n) => myLines.Add(n)); } } return(myLines); }
private IList <IParamNode> ParseParamList(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes, bool expandFirstDef = true) { IList <IParamNode> paramList = new List <IParamNode>(); bool first = true; while (tokens.Current.Type != TokenType.NEWLINE && tokens.Current.Type != TokenType.SEMICOLON && !tokens.EOS) { Token head = tokens.Current; ParseParam(tokens, scopes, expandFirstDef || !first).IfJust( (IParamNode n) => paramList.Add(n), () => Error(head.Location, "Expected parameter.")); first = false; } if (tokens.Current.Type == TokenType.SEMICOLON) { tokens.MoveNext(); } return(paramList); }
private Maybe <IParamNode> ParseParam(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes, bool expandDefs = true) { Token head = tokens.Current; switch (tokens.Current.Type) { case TokenType.OPEN_BRACKET: return(new Just <IParamNode>(new ListNode(head.Location, ParseList(tokens, scopes)).Simplify())); case TokenType.STRING: tokens.MoveNext(); return(new Just <IParamNode>(new StringNode(head))); case TokenType.MAYBE_MACRO: //TODO: Move this and the one in ExpandId to a separate ParseMacroNode that may return an Invocation. if (expandDefs && ExpandIdentifier(tokens, scopes)) { return(ParseParam(tokens, scopes)); } else { tokens.MoveNext(); IList <IList <Token> > param = ParseMacroParamList(tokens); //TODO: Smart errors if trying to redefine a macro with the same num of params. return(new Just <IParamNode>(new MacroInvocationNode(this, head, param, scopes))); } case TokenType.IDENTIFIER: if (expandDefs && Definitions.ContainsKey(head.Content) && ExpandIdentifier(tokens, scopes)) { return(ParseParam(tokens, scopes, expandDefs)); } else { return(ParseAtom(tokens, scopes, expandDefs).Fmap((IAtomNode x) => (IParamNode)x.Simplify())); } default: return(ParseAtom(tokens, scopes, expandDefs).Fmap((IAtomNode x) => (IParamNode)x.Simplify())); } }
/*** * Precondition: tokens.Current.Type == TokenType.IDENTIFIER || MAYBE_MACRO * Postcondition: tokens.Current is fully reduced (i.e. not a macro, and not a definition) * Returns: true iff tokens was actually expanded. */ public bool ExpandIdentifier(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { bool ret = false; //Macros and Definitions. if (tokens.Current.Type == TokenType.MAYBE_MACRO && Macros.ContainsName(tokens.Current.Content)) { Token head = tokens.Current; tokens.MoveNext(); IList <IList <Token> > parameters = ParseMacroParamList(tokens); if (Macros.HasMacro(head.Content, parameters.Count)) { tokens.PrependEnumerator(Macros.GetMacro(head.Content, parameters.Count).ApplyMacro(head, parameters, scopes).GetEnumerator()); } else { Error(head.Location, System.String.Format("No overload of {0} with {1} parameters.", head.Content, parameters.Count)); } return(true); } else if (tokens.Current.Type == TokenType.MAYBE_MACRO) { Token head = tokens.Current; tokens.MoveNext(); tokens.PutBack(new Token(TokenType.IDENTIFIER, head.Location, head.Content)); return(true); } else if (Definitions.ContainsKey(tokens.Current.Content)) { Token head = tokens.Current; tokens.MoveNext(); tokens.PrependEnumerator(Definitions[head.Content].ApplyDefinition(head).GetEnumerator()); return(true); } return(ret); }
public IList <IList <Token> > ParseMacroParamList(MergeableGenerator <Token> tokens) { IList <IList <Token> > parameters = new List <IList <Token> >(); int parenNestings = 0; do { tokens.MoveNext(); List <Token> currentParam = new List <Token>(); while ( !(parenNestings == 0 && (tokens.Current.Type == TokenType.CLOSE_PAREN || tokens.Current.Type == TokenType.COMMA)) && tokens.Current.Type != TokenType.NEWLINE) { if (tokens.Current.Type == TokenType.CLOSE_PAREN) { parenNestings--; } else if (tokens.Current.Type == TokenType.OPEN_PAREN) { parenNestings++; } currentParam.Add(tokens.Current); tokens.MoveNext(); } parameters.Add(currentParam); } while (tokens.Current.Type != TokenType.CLOSE_PAREN && tokens.Current.Type != TokenType.NEWLINE); if (tokens.Current.Type != TokenType.CLOSE_PAREN || parenNestings != 0) { Error(tokens.Current.Location, "Unmatched open parenthesis."); } else { tokens.MoveNext(); } return(parameters); }
public Maybe <ILineNode> ParseLine(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { if (IsIncluding) { if (tokens.Current.Type == TokenType.NEWLINE || tokens.Current.Type == TokenType.SEMICOLON) { tokens.MoveNext(); return(new Nothing <ILineNode>()); } head = tokens.Current; switch (head.Type) { case TokenType.IDENTIFIER: case TokenType.MAYBE_MACRO: if (ExpandIdentifier(tokens, scopes)) { return(ParseLine(tokens, scopes)); } else { tokens.MoveNext(); if (tokens.Current.Type == TokenType.COLON) { tokens.MoveNext(); if (scopes.Head.HasLocalLabel(head.Content)) { Warning(head.Location, "Label already in scope, ignoring: " + head.Content); //replacing: " + head.Content); } else if (!IsValidLabelName(head.Content)) { Error(head.Location, "Invalid label name " + head.Content + '.'); } else { scopes.Head.AddLabel(head.Content, CurrentOffset); } return(new Nothing <ILineNode>()); } else { tokens.PutBack(head); return(ParseStatement(tokens, scopes)); } } case TokenType.OPEN_BRACE: return(new Just <ILineNode>(ParseBlock(tokens, new ImmutableStack <Closure>(new Closure(), scopes)))); case TokenType.PREPROCESSOR_DIRECTIVE: return(ParsePreprocessor(tokens, scopes)); case TokenType.OPEN_BRACKET: Error(head.Location, "Unexpected list literal."); IgnoreRestOfLine(tokens); break; case TokenType.NUMBER: case TokenType.OPEN_PAREN: Error(head.Location, "Unexpected mathematical expression."); IgnoreRestOfLine(tokens); break; default: tokens.MoveNext(); Error(head.Location, System.String.Format("Unexpected token: {0}: {1}", head.Type, head.Content)); IgnoreRestOfLine(tokens); break; } return(new Nothing <ILineNode>()); } else { bool hasNext = true; while (tokens.Current.Type != TokenType.PREPROCESSOR_DIRECTIVE && (hasNext = tokens.MoveNext())) { ; } if (hasNext) { return(ParsePreprocessor(tokens, scopes)); } else { Error(null, System.String.Format("Missing {0} endif(s).", Inclusion.Count)); return(new Nothing <ILineNode>()); } } }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { if (p.Inclusion.IsEmpty) { p.Error(self.Location, "No matching if[n]def."); } else { p.Inclusion = p.Inclusion.Tail; } return(new Nothing <ILineNode>()); }
private Maybe <IAtomNode> ParseAtom(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes, bool expandDefs = true) { //Use Shift Reduce Parsing Token head = tokens.Current; Stack <Either <IAtomNode, Token> > grammarSymbols = new Stack <Either <IAtomNode, Token> >(); bool ended = false; while (!ended) { bool shift = false, lookingForAtom = grammarSymbols.Count == 0 || grammarSymbols.Peek().IsRight; Token lookAhead = tokens.Current; if (!ended && !lookingForAtom) //Is already a complete node. Needs an operator of matching precedence and a node of matching prec to reduce. { //Verify next symbol to be an operator. switch (lookAhead.Type) { case TokenType.MUL_OP: case TokenType.DIV_OP: case TokenType.MOD_OP: case TokenType.ADD_OP: case TokenType.SUB_OP: case TokenType.LSHIFT_OP: case TokenType.RSHIFT_OP: case TokenType.SIGNED_RSHIFT_OP: case TokenType.AND_OP: case TokenType.XOR_OP: case TokenType.OR_OP: if (precedences.ContainsKey(lookAhead.Type)) { Reduce(grammarSymbols, precedences[lookAhead.Type]); } shift = true; break; default: ended = true; break; } } else if (!ended) //Is just an operator. Error if two operators in a row. { //Error if two operators in a row. switch (lookAhead.Type) { case TokenType.IDENTIFIER: case TokenType.MAYBE_MACRO: case TokenType.NUMBER: shift = true; break; case TokenType.OPEN_PAREN: { tokens.MoveNext(); Maybe <IAtomNode> interior = ParseAtom(tokens, scopes); if (tokens.Current.Type != TokenType.CLOSE_PAREN) { Error(tokens.Current.Location, "Unmatched open parenthesis (currently at " + tokens.Current.Type + ")."); return(new Nothing <IAtomNode>()); } else if (interior.IsNothing) { Error(lookAhead.Location, "Expected expression inside paretheses. "); return(new Nothing <IAtomNode>()); } else { grammarSymbols.Push(new Left <IAtomNode, Token>(interior.FromJust)); tokens.MoveNext(); break; } } case TokenType.SUB_OP: { //Assume unary negation. tokens.MoveNext(); Maybe <IAtomNode> interior = ParseAtom(tokens, scopes); if (interior.IsNothing) { Error(lookAhead.Location, "Expected expression after negation. "); return(new Nothing <IAtomNode>()); } grammarSymbols.Push(new Left <IAtomNode, Token>(new NegationNode(lookAhead, interior.FromJust))); break; } case TokenType.COMMA: Error(lookAhead.Location, "Unexpected comma (perhaps unrecognized macro invocation?)."); IgnoreRestOfStatement(tokens); return(new Nothing <IAtomNode>()); case TokenType.MUL_OP: case TokenType.DIV_OP: case TokenType.MOD_OP: case TokenType.ADD_OP: case TokenType.LSHIFT_OP: case TokenType.RSHIFT_OP: case TokenType.SIGNED_RSHIFT_OP: case TokenType.AND_OP: case TokenType.XOR_OP: case TokenType.OR_OP: default: Error(lookAhead.Location, "Expected identifier or literal, got " + lookAhead.Type + ": " + lookAhead.Content + '.'); IgnoreRestOfStatement(tokens); return(new Nothing <IAtomNode>()); } } if (shift) { if (lookAhead.Type == TokenType.IDENTIFIER) { if (expandDefs && ExpandIdentifier(tokens, scopes)) { continue; } if (lookAhead.Content.ToUpper() == "CURRENTOFFSET") { grammarSymbols.Push(new Left <IAtomNode, Token>(new NumberNode(lookAhead, CurrentOffset))); } else { grammarSymbols.Push(new Left <IAtomNode, Token>(new IdentifierNode(lookAhead, scopes))); } } else if (lookAhead.Type == TokenType.MAYBE_MACRO) { ExpandIdentifier(tokens, scopes); continue; } else if (lookAhead.Type == TokenType.NUMBER) { grammarSymbols.Push(new Left <IAtomNode, Token>(new NumberNode(lookAhead))); } else if (lookAhead.Type == TokenType.ERROR) { Error(lookAhead.Location, System.String.Format("Unexpected token: {0}", lookAhead.Content)); tokens.MoveNext(); return(new Nothing <IAtomNode>()); } else { grammarSymbols.Push(new Right <IAtomNode, Token>(lookAhead)); } tokens.MoveNext(); continue; } } while (grammarSymbols.Count > 1) { Reduce(grammarSymbols, 11); } if (grammarSymbols.Peek().IsRight) { Error(grammarSymbols.Peek().GetRight.Location, "Unexpected token: " + grammarSymbols.Peek().GetRight.Type); } return(new Just <IAtomNode>(grammarSymbols.Peek().GetLeft)); }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { Maybe <string> existantFile = FileSearcher.FindFile(Path.GetDirectoryName(self.FileName), parameters[0].ToString() !); if (!existantFile.IsNothing) { try { string pathname = existantFile.FromJust; return(new Just <ILineNode>(new DataNode(p.CurrentOffset, File.ReadAllBytes(pathname)))); } catch (Exception) { p.Error(self.Location, "Error reading file \"" + parameters[0].ToString() + "\"."); } } else { p.Error(parameters[0].MyLocation, "Could not find file \"" + parameters[0].ToString() + "\"."); } return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { bool flag = true; Maybe <string> identifier; foreach (IParamNode parameter in parameters) { if (parameter.Type == ParamType.ATOM && !(identifier = ((IAtomNode)parameter).GetIdentifier()).IsNothing) { flag &= p.Macros.ContainsName(identifier.FromJust) || p.Definitions.ContainsKey(identifier.FromJust); //TODO: Built in definitions? } else { p.Error(parameter.MyLocation, "Definition name must be an identifier."); } } p.Inclusion = new ImmutableStack <bool>(flag, p.Inclusion); return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { foreach (IParamNode parm in parameters) { string s = parm.ToString(); if (p.Definitions.ContainsKey(s)) { p.Definitions.Remove(parm.ToString()); } else { p.Warning(parm.MyLocation, "Undefining non-existant definition: " + s); } } return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> HandleDirective(EAParser p, Token directive, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { string directiveName = directive.Content.Substring(1); if (directives.TryGetValue(directiveName, out IDirective? toExec)) { if (!toExec.RequireInclusion || p.IsIncluding) { if (toExec.MinParams <= parameters.Count && (!toExec.MaxParams.HasValue || parameters.Count <= toExec.MaxParams)) { return(toExec.Execute(p, directive, parameters, tokens)); } else { p.Error(directive.Location, "Invalid number of parameters (" + parameters.Count + ") to directive " + directiveName + "."); } } } else { p.Error(directive.Location, "Directive not recognized: " + directiveName); } return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> Execute(EAParser parse, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { ExecTimer.Timer.AddTimingPoint(ExecTimer.KEY_GENERIC); Maybe <string> validFile = FileSearcher.FindFile(Path.GetDirectoryName(self.FileName), IOUtility.GetToolFileName(parameters[0].ToString())); if (validFile.IsNothing) { parse.Error(parameters[0].MyLocation, "Tool " + parameters[0].ToString() + " not found."); return(new Nothing <ILineNode>()); } //from http://stackoverflow.com/a/206347/1644720 // Start the child process. System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo.RedirectStandardError = true; // Redirect the output stream of the child process. p.StartInfo.WorkingDirectory = Path.GetDirectoryName(self.FileName); p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.FileName = validFile.FromJust; StringBuilder argumentBuilder = new StringBuilder(); for (int i = 1; i < parameters.Count; i++) { parameters[i].AsAtom().IfJust((IAtomNode n) => { parameters[i] = n.Simplify(); }); argumentBuilder.Append(parameters[i].PrettyPrint()); argumentBuilder.Append(' '); } argumentBuilder.Append("--to-stdout"); p.StartInfo.Arguments = argumentBuilder.ToString(); p.Start(); // Do not wait for the child process to exit before // reading to the end of its redirected stream. // p.WaitForExit(); // Read the output stream first and then wait. MemoryStream outputBytes = new MemoryStream(); MemoryStream errorStream = new MemoryStream(); p.StandardOutput.BaseStream.CopyTo(outputBytes); p.StandardError.BaseStream.CopyTo(errorStream); p.WaitForExit(); byte[] output = outputBytes.GetBuffer().Take((int)outputBytes.Length).ToArray(); if (errorStream.Length > 0) { parse.Error(self.Location, Encoding.ASCII.GetString(errorStream.GetBuffer().Take((int)errorStream.Length).ToArray())); } else if (output.Length >= 7 && Encoding.ASCII.GetString(output.Take(7).ToArray()) == "ERROR: ") { parse.Error(self.Location, Encoding.ASCII.GetString(output.Skip(7).ToArray())); } else { outputBytes.Position = 0; //Reset MemoryStream position so StreamReader starts reading from beginning. Tokenizer t = new Tokenizer(); tokens.PrependEnumerator(t.Tokenize(outputBytes, Path.GetFileName(self.FileName) + ", Line " + self.LineNumber + "; " + parameters[0].ToString()).GetEnumerator()); } ExecTimer.Timer.AddTimingPoint(parameters[0].ToString().ToLower()); return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { Maybe <string> existantFile = FileSearcher.FindFile(Path.GetDirectoryName(self.FileName), parameters[0].ToString()); if (!existantFile.IsNothing) { try { string pathname = existantFile.FromJust; FileStream inputFile = new FileStream(pathname, FileMode.Open); Tokenizer newFileTokenizer = new Tokenizer(); tokens.PrependEnumerator(newFileTokenizer.Tokenize(inputFile).GetEnumerator()); } catch (Exception) { p.Error(self.Location, "Error reading file \"" + parameters[0].ToString() + "\"."); } } else { p.Error(parameters[0].MyLocation, "Could not find file \"" + parameters[0].ToString() + "\"."); } return(new Nothing <ILineNode>()); }
public Maybe <ILineNode> Execute(EAParser parse, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { ExecTimer.Timer.AddTimingPoint(ExecTimer.KEY_GENERIC); Maybe <string> validFile = FileSearcher.FindFile(Path.GetDirectoryName(self.FileName), IOUtility.GetToolFileName(parameters[0].ToString() !)); if (validFile.IsNothing) { parse.Error(parameters[0].MyLocation, "Tool " + parameters[0].ToString() + " not found."); return(new Nothing <ILineNode>()); } //TODO: abstract out all this running stuff into a method so I don't have code duplication with inctext //from http://stackoverflow.com/a/206347/1644720 // Start the child process. System.Diagnostics.Process p = new System.Diagnostics.Process(); p.StartInfo.RedirectStandardError = true; // Redirect the output stream of the child process. p.StartInfo.WorkingDirectory = Path.GetDirectoryName(self.FileName) !; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.CreateNoWindow = true; p.StartInfo.FileName = validFile.FromJust; StringBuilder argumentBuilder = new StringBuilder(); for (int i = 1; i < parameters.Count; i++) { if (parameters[i].Type == ParamType.ATOM) { parameters[i] = ((IAtomNode)parameters[i]).Simplify(); } argumentBuilder.Append(parameters[i].PrettyPrint()); argumentBuilder.Append(' '); } argumentBuilder.Append("--to-stdout"); p.StartInfo.Arguments = argumentBuilder.ToString(); p.Start(); // Do not wait for the child process to exit before // reading to the end of its redirected stream. // p.WaitForExit(); // Read the output stream first and then wait. MemoryStream outputBytes = new MemoryStream(); MemoryStream errorStream = new MemoryStream(); p.StandardOutput.BaseStream.CopyTo(outputBytes); p.StandardError.BaseStream.CopyTo(errorStream); p.WaitForExit(); byte[] output = outputBytes.GetBuffer().Take((int)outputBytes.Length).ToArray(); if (errorStream.Length > 0) { parse.Error(self.Location, Encoding.ASCII.GetString(errorStream.GetBuffer().Take((int)errorStream.Length).ToArray())); } else if (output.Length >= 7 && Encoding.ASCII.GetString(output.Take(7).ToArray()) == "ERROR: ") { parse.Error(self.Location, Encoding.ASCII.GetString(output.Skip(7).ToArray())); } ExecTimer.Timer.AddTimingPoint(parameters[0].ToString() !.ToLower()); return(new Just <ILineNode>(new DataNode(parse.CurrentOffset, output))); }
private Maybe <ILineNode> ParseStatement(MergeableGenerator <Token> tokens, ImmutableStack <Closure> scopes) { while (ExpandIdentifier(tokens, scopes)) { } head = tokens.Current; tokens.MoveNext(); //TODO: Replace with real raw information, and error if not valid. IList <IParamNode> parameters; //TODO: Make intelligent to reject malformed parameters. //TODO: Parse parameters after checking code validity. if (tokens.Current.Type != TokenType.NEWLINE && tokens.Current.Type != TokenType.SEMICOLON) { parameters = ParseParamList(tokens, scopes); } else { parameters = new List <IParamNode>(); tokens.MoveNext(); } string upperCodeIdentifier = head.Content.ToUpperInvariant(); if (SpecialCodes.Contains(upperCodeIdentifier)) { switch (upperCodeIdentifier) { case "ORG": if (parameters.Count != 1) { Error(head.Location, "Incorrect number of parameters in ORG: " + parameters.Count); } else { parameters[0].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int temp) => { if (temp > 0x2000000) { Error(parameters[0].MyLocation, "Tried to set offset to 0x" + temp.ToString("X")); } else { CurrentOffset = temp; } }), () => { Error(parameters[0].MyLocation, "Expected atomic param to ORG."); } ); } break; case "PUSH": if (parameters.Count != 0) { Error(head.Location, "Incorrect number of parameters in PUSH: " + parameters.Count); } else { pastOffsets.Push(new Tuple <int, bool>(CurrentOffset, offsetInitialized)); } break; case "POP": if (parameters.Count != 0) { Error(head.Location, "Incorrect number of parameters in POP: " + parameters.Count); } else if (pastOffsets.Count == 0) { Error(head.Location, "POP without matching PUSH."); } else { Tuple <int, bool> tuple = pastOffsets.Pop(); CurrentOffset = tuple.Item1; offsetInitialized = tuple.Item2; } break; case "MESSAGE": Message(head.Location, PrettyPrintParams(parameters)); break; case "WARNING": Warning(head.Location, PrettyPrintParams(parameters)); break; case "ERROR": Error(head.Location, PrettyPrintParams(parameters)); break; case "ASSERT": if (parameters.Count != 1) { Error(head.Location, "Incorrect number of parameters in ASSERT: " + parameters.Count); } else { parameters[0].AsAtom().IfJust( (IAtomNode atom) => { atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int temp) => { if (temp < 0) { Error(parameters[0].MyLocation, "Assertion error: " + temp); } }); }, () => { Error(parameters[0].MyLocation, "Expected atomic param to ASSERT."); } ); } break; case "PROTECT": if (parameters.Count == 1) { parameters[0].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int temp) => { protectedRegions.Add(new Tuple <int, int, Location>(temp, 4, head.Location)); }), () => { Error(parameters[0].MyLocation, "Expected atomic param to PROTECT"); }); } else if (parameters.Count == 2) { int start = 0, end = 0; bool errorOccurred = false; parameters[0].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); errorOccurred = true; }).IfJust( (int temp) => { start = temp; }), () => { Error(parameters[0].MyLocation, "Expected atomic param to PROTECT"); errorOccurred = true; }); parameters[1].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); errorOccurred = true; }).IfJust( (int temp) => { end = temp; }), () => { Error(parameters[0].MyLocation, "Expected atomic param to PROTECT"); errorOccurred = true; }); if (!errorOccurred) { int length = end - start; if (length > 0) { protectedRegions.Add(new Tuple <int, int, Location>(start, length, head.Location)); } else { Warning(head.Location, "Protected region not valid (end offset not after start offset). No region protected."); } } } else { Error(head.Location, "Incorrect number of parameters in PROTECT: " + parameters.Count); } break; case "ALIGN": if (parameters.Count != 1) { Error(head.Location, "Incorrect number of parameters in ALIGN: " + parameters.Count); } else { parameters[0].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int temp) => { CurrentOffset = CurrentOffset % temp != 0 ? CurrentOffset + temp - CurrentOffset % temp : CurrentOffset; }), () => { Error(parameters[0].MyLocation, "Expected atomic param to ALIGN"); } ); } break; case "FILL": if (parameters.Count > 2 || parameters.Count == 0) { Error(head.Location, "Incorrect number of parameters in FILL: " + parameters.Count); } else { // FILL <amount> [value] int amount = 0; int value = 0; if (parameters.Count == 2) { // param 2 (if given) is fill value parameters[1].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int val) => { value = val; }), () => { Error(parameters[0].MyLocation, "Expected atomic param to FILL"); }); } // param 1 is amount of bytes to fill parameters[0].AsAtom().IfJust( (IAtomNode atom) => atom.TryEvaluate((Exception e) => { Error(parameters[0].MyLocation, e.Message); }).IfJust( (int val) => { amount = val; }), () => { Error(parameters[0].MyLocation, "Expected atomic param to FILL"); }); var data = new byte[amount]; for (int i = 0; i < amount; ++i) { data[i] = (byte)value; } var node = new DataNode(CurrentOffset, data); CheckDataWrite(amount); CurrentOffset += amount; return(new Just <ILineNode>(node)); } break; } return(new Nothing <ILineNode>()); } else if (Raws.ContainsKey(upperCodeIdentifier)) { //TODO: Check for matches. Currently should type error. foreach (Raw r in Raws[upperCodeIdentifier]) { if (r.Fits(parameters)) { if ((CurrentOffset % r.Alignment) != 0) { Error(head.Location, string.Format("Bad code alignment (offset: {0:X8})", CurrentOffset)); } StatementNode temp = new RawNode(r, head, CurrentOffset, parameters); CheckDataWrite(temp.Size); CurrentOffset += temp.Size; //TODO: more efficient spacewise to just have contiguous writing and not an offset with every line? return(new Just <ILineNode>(temp)); } } //TODO: Better error message (a la EA's ATOM ATOM [ATOM,ATOM]) Error(head.Location, "Incorrect parameters in raw " + head.Content + '.'); IgnoreRestOfStatement(tokens); return(new Nothing <ILineNode>()); } else //TODO: Move outside of this else. { Error(head.Location, "Unrecognized code: " + head.Content); return(new Nothing <ILineNode>()); } }
public Maybe <ILineNode> Execute(EAParser p, Token self, IList <IParamNode> parameters, MergeableGenerator <Token> tokens) { if (parameters[0].Type == ParamType.MACRO) { MacroInvocationNode signature = (MacroInvocationNode)(parameters[0]); string name = signature.Name; IList <Token> myParams = new List <Token>(); foreach (IList <Token> l1 in signature.Parameters) { if (l1.Count != 1 || l1[0].Type != TokenType.IDENTIFIER) { p.Error(l1[0].Location, "Macro parameters must be identifiers (got " + l1[0].Content + ")."); } else { myParams.Add(l1[0]); } } /* if (!p.IsValidMacroName(name, myParams.Count)) * { * if (p.IsReservedName(name)) * { * p.Error(signature.MyLocation, "Invalid redefinition: " + name); * } * else * p.Warning(signature.MyLocation, "Redefining " + name + '.'); * }*/ if (p.Macros.HasMacro(name, myParams.Count)) { p.Warning(signature.MyLocation, "Redefining " + name + '.'); } Maybe <IList <Token> > toRepl; if (parameters.Count != 2) { toRepl = new Just <IList <Token> >(new List <Token>()); } else { toRepl = ExpandParam(p, parameters[1], myParams.Select((Token t) => t.Content)); } if (!toRepl.IsNothing) { p.Macros.AddMacro(new Macro(myParams, toRepl.FromJust), name, myParams.Count); } } else { //Note [mutually] recursive definitions are handled by Parser expansion. Maybe <string> maybeIdentifier; if (parameters[0].Type == ParamType.ATOM && !(maybeIdentifier = ((IAtomNode)parameters[0]).GetIdentifier()).IsNothing) { string name = maybeIdentifier.FromJust; if (p.Definitions.ContainsKey(name)) { p.Warning(parameters[0].MyLocation, "Redefining " + name + '.'); } if (parameters.Count == 2) { Maybe <IList <Token> > toRepl = ExpandParam(p, parameters[1], Enumerable.Empty <string>()); if (!toRepl.IsNothing) { p.Definitions[name] = new Definition(toRepl.FromJust); } } else { p.Definitions[name] = new Definition(); } } else { p.Error(parameters[0].MyLocation, "Definition names must be identifiers (got " + parameters[0].ToString() + ")."); } } return(new Nothing <ILineNode>()); }