using System.Collections.Generic; using System.Linq; namespace NTERA.Interpreter.Compiler { public static class Preprocessor { public static IDictionary PreprocessFile(string contents, string filename) { Dictionary procs = new Dictionary(); Lexer lexer = new Lexer(contents); Marker startMarker = lexer.TokenMarker; string currentDefinitionName = null; List currentDefinitionParameters = new List(); List currentDefinitionVariables = new List(); bool isReturnFunction = false; void Commit() { if (currentDefinitionName != null) { string procBody = contents.Substring(startMarker.Pointer, lexer.TokenMarker.Pointer - startMarker.Pointer); var definition = new FunctionDefinition(currentDefinitionName, currentDefinitionParameters.ToArray(), currentDefinitionVariables.ToArray(), isReturnFunction, filename, startMarker); procs.Add(definition, procBody); isReturnFunction = false; currentDefinitionName = null; currentDefinitionParameters.Clear(); } } using (var enumerator = lexer.GetEnumerator()) { do { if (lexer.TokenMarker.Column != 1) continue; if (enumerator.Current == Token.Function) { Commit(); startMarker = lexer.TokenMarker; enumerator.MoveNext(); if (enumerator.Current != Token.Identifer) throw new ParserException("Invalid function declaration - Expected an identifier", lexer.TokenMarker); currentDefinitionName = lexer.Identifer; enumerator.MoveNext(); if (enumerator.Current == Token.NewLine || enumerator.Current == Token.EOF) continue; if (enumerator.Current != Token.LParen && enumerator.Current != Token.Comma) throw new ParserException("Invalid function declaration", lexer.TokenMarker); enumerator.MoveNext(); if (enumerator.Current != Token.Identifer && enumerator.Current != Token.RParen) throw new ParserException("Invalid function declaration", lexer.TokenMarker); while (enumerator.Current == Token.Identifer) { string parameterName = lexer.Identifer; List indices = new List(); Value? defaultValue = null; enumerator.MoveNext(); while (enumerator.Current == Token.Colon && enumerator.MoveNext()) { if (enumerator.Current == Token.Value) { indices.Add(lexer.Value.Type == ValueType.Real ? ((int)lexer.Value).ToString() : lexer.Value.String); } else if (enumerator.Current == Token.Identifer) { indices.Add(lexer.Identifer); } enumerator.MoveNext(); } if (enumerator.Current == Token.Equal) { enumerator.MoveNext(); bool hasUnaryMinus = false; if (enumerator.Current == Token.Minus) { hasUnaryMinus = true; enumerator.MoveNext(); } if (enumerator.Current == Token.Identifer) { defaultValue = lexer.Identifer; } else if (enumerator.Current == Token.Value) { defaultValue = lexer.Value; if (hasUnaryMinus) { if (defaultValue.Value.Type == ValueType.Real) defaultValue = defaultValue * -1; else defaultValue = "-" + defaultValue; } } else throw new ParserException("Invalid function declaration", lexer.TokenMarker); enumerator.MoveNext(); } if (enumerator.Current == Token.Comma || enumerator.Current == Token.RParen) { enumerator.MoveNext(); } else if (enumerator.Current != Token.NewLine && enumerator.Current != Token.EOF) throw new ParserException("Invalid function declaration", lexer.TokenMarker); currentDefinitionParameters.Add(new FunctionParameter(parameterName, indices.ToArray(), defaultValue)); } if (enumerator.Current == Token.RParen) enumerator.MoveNext(); if (enumerator.Current != Token.NewLine && enumerator.Current != Token.EOF) throw new ParserException("Invalid function declaration", lexer.TokenMarker); } else if (enumerator.Current == Token.Sharp) { enumerator.MoveNext(); switch (enumerator.Current) { case Token.Dims: case Token.Dim: { bool isString = enumerator.Current != Token.Dim; enumerator.MoveNext(); VariableType variableType = VariableType.None; while (enumerator.Current == Token.Const || enumerator.Current == Token.Ref || enumerator.Current == Token.Dynamic) { if (enumerator.Current == Token.Const) variableType |= VariableType.Constant; else if (enumerator.Current == Token.Ref) variableType |= VariableType.Reference; else if (enumerator.Current == Token.Dynamic) variableType |= VariableType.Dynamic; enumerator.MoveNext(); } string variable = lexer.Identifer; enumerator.MoveNext(); Value? defaultValue = null; if (enumerator.Current == Token.Comma) { while (enumerator.MoveNext() && enumerator.Current != Token.Equal && enumerator.Current != Token.NewLine && enumerator.Current != Token.EOF) { } //arraySize = (int)lexer.Expression().Real; } if (enumerator.Current == Token.Equal) { enumerator.MoveNext(); if (isString) lexer.Type = LexerType.String; defaultValue = lexer.Expression(); lexer.Type = LexerType.Both; } else if (enumerator.Current != Token.NewLine && enumerator.Current != Token.EOF) { throw new ParserException("Invalid function declaration", lexer.TokenMarker); } currentDefinitionVariables.Add(new FunctionVariable(variable, isString ? ValueType.String : ValueType.Real, variableType, defaultValue)); break; } case Token.ReturnFunction: { isReturnFunction = true; break; } } } } while (enumerator.MoveNext()); } Commit(); return procs; } public static IList> ProcessCSV(IEnumerable lines) { List> csv = new List>(); foreach (var line in lines) { if (string.IsNullOrWhiteSpace(line) || line[0] == ';') continue; string newLine = line; int commentIndex = line.IndexOf(';'); if (commentIndex >= 0) newLine = line.Substring(0, commentIndex); string[] split = newLine.Split(','); csv.Add(split.ToList()); } return csv; } } }