using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; //TODO add parsing for more than single letter namespace ConsoleLSystem { abstract public class LSystemGeneralWordBuilder { abstract public LSystemNode createLSystemNode(string name, int values_number); abstract public void fillArguments(LSystemNode node, string[] arguments_strings); } public class LSystemWordBuilder : LSystemGeneralWordBuilder { public override LSystemNode createLSystemNode(string name, int values_number) { return new LSystemNode(new LSystemNodeLiteral(name, values_number)); } public override void fillArguments(LSystemNode node, string[] arguments_strings) { for (int i = 0; i < arguments_strings.Length; i++) { node.literal.values[i] = float.Parse(arguments_strings[i], NumberStyles.Any, CultureInfo.InvariantCulture); } } } public class LSystemWordGeneratorBuilder : LSystemGeneralWordBuilder { public Dictionary variableIndex { get;} public LSystemWordGeneratorBuilder(Dictionary variable_index) { this.variableIndex = variable_index; } public override LSystemNode createLSystemNode(string name, int values_number) { return new LSystemNodeGenerator(name, values_number); } public override void fillArguments(LSystemNode node, string[] arguments_strings) { MathExpression[] expressions = arguments_strings.Select(argument => new MathExpression(variableIndex, argument)).ToArray(); LSystemNodeGenerator ng = (LSystemNodeGenerator)node; ng.fillArguments(expressions); } } public class LSystemFileParser { //LSystemWordParser wordParser; //LSystemRulesParser ruleParser; //public LSystemFileParser(LSystemWordParser wordParser, LSystemRulesParser ruleParser) { // this.wordParser = wordParser; // this.ruleParser = ruleParser; //} public static int countParenthesisEnd(string line,char opening_char, char closing_char) { var parenthesises_number = 1; var length = -1; while (parenthesises_number > 0) { length++; var c = line[1 + length]; if (c == opening_char) { parenthesises_number++; } if (c == closing_char) { parenthesises_number--; } } return length; } public static bool parenthesisCheck(string line) { var parenthesises_number = 0; var brackets_number = 0; foreach (var s in line) { if (s == '(') { parenthesises_number++; } if (s == ')') { parenthesises_number--; } if (s == '[') { brackets_number++; } if (s == ']') { brackets_number--; } if (brackets_number<0 || parenthesises_number < 0) { return false; } } return (brackets_number == 0 && parenthesises_number == 0); } public static LSystemNode parseWord(string line, LSystemGeneralWordBuilder builder) { var read_characters = 0; LSystemNode node; if (line[0] == '[') { node = builder.createLSystemNode("", 0); } else { var literal_name = line.Substring(0, 1); if (line.Length>1 && line[1] == '(') { var length = countParenthesisEnd(line.Substring(1), '(', ')'); var values_string = line.Substring(2, length).Split(','); node = builder.createLSystemNode(literal_name, values_string.Length); builder.fillArguments(node, values_string); //Leter and: (, ) read_characters += length + 3; } else { read_characters += 1; node = builder.createLSystemNode(line.Substring(0,1),0); } } while (line.Length > read_characters && line[read_characters] == '[') { var brackets_number = 1; var length = countParenthesisEnd(line.Substring(read_characters), '[', ']'); var child_node = parseWord(line.Substring(read_characters + 1, length),builder); read_characters += length + 2; child_node.parent = node; node.children.Add(child_node); } if (read_characters < line.Length) { var child_node = parseWord(line.Substring(read_characters),builder); child_node.parent = node; node.mainChild = (child_node); } return node; } public static LSystemNodeLiteralVariable parseContextLiteral(string line) { var name = line.Substring(0, 1); var varable_index = new Dictionary(); if (line.Length > 1) { foreach (var i in line.Substring(2, line.Length - 3).Split(',').Select((name, Index) => new { name, Index })) { varable_index.Add(i.name, i.Index); }; } return new LSystemNodeLiteralVariable(name, varable_index.Count, varable_index); } public static LSystemNodeLiteralVariable[] parseSuccessorsContext(string line) { List result = new List(); bool bracketStarted = false; int bracketStartedIndex = 0; for (int i = 0; i < line.Length; i++) { if (line[i] == ']') { if (!bracketStarted) { throw new Exception("invalid syntax"); } else { result.Add(parseContextLiteral(line.Substring(bracketStartedIndex, i - bracketStartedIndex))); bracketStarted = false; } } else if (line[i] == '[') { if (bracketStarted) { throw new Exception("invalid syntax"); } else { bracketStarted = true; bracketStartedIndex = i + 1; } } else if (!bracketStarted) { result.Add(parseContextLiteral(line.Substring(i))); break; } } return result.ToArray(); } //private static String[] parseIgnore(string line) { // var items = line.Trim().Split(' '); // var resut = List //} public static LSystemEvaluator parseLSystem(StreamReader sr) { string line; int line_number = 0; var ignored = new String[0]; LSystemNode axiom = null; List rules = null; while ((line = sr.ReadLine()) != null) { line_number++; if (line.Trim() == "#axiom") { line = sr.ReadLine(); if (!parenthesisCheck(line)) { throw new Exception(String.Format("In line {0} invalid syntax", line_number)); } axiom = parseWord(line,new LSystemWordBuilder()); } if (line.Trim().Split(' ')[0].Trim() == "#ignore") { ignored = line.Trim().Split(' ').Where(x=> x!= "#ignore" && x.Length>0).Select(x => x.Trim()).ToArray(); } if (line.Trim() == "#rules") { rules = parseLSystemRules(sr); } } return new LSystemEvaluator(axiom, rules, ignored); } private static List parseLSystemRules(StreamReader sr) { List rules = new List(); Regex separator = new Regex(@"-(\d*\.?\d*){1}>"); Regex weight_regex = new Regex(@"p=(\d+\.?\d*){1}"); string line; while ((line = sr.ReadLine()) != null && line.Trim() != "#rules end") { try { if (line.Length == 0 || line[0] == '#') { continue; } MathExpressionComparison[] conditions = new MathExpressionComparison[0]; var split = separator.Match(line); var line_parts = line.Split(new string[] { split.Value }, StringSplitOptions.None); // check conditions; //parse predecesor var _t = line_parts[0].Split(':'); var predecesor_string = _t[0]; LSystemNodeLiteralVariable predecesor; LSystemContext context; //check if contains < or > // check context getPredecesorContext(predecesor_string, out predecesor, out context); if (_t.Length > 1) { conditions = _t[1].Trim().Split(';').Select(text => MathExpressionComparasionParser.parse(predecesor.variableIndex, text.Trim())).ToArray(); } // tochastic rule parsing var sucsessor_string = line_parts[1]; var probabilities_list = new List(); var consequents_list = new List(); if (sucsessor_string.Trim() == "#stochastic") { while ((line = sr.ReadLine()) != null && line.Trim() != "#stochastic end") { if (line[0] == '#') { continue; } var weight_string = weight_regex.Match(line); var weight = float.Parse(weight_string.Value.Substring(2), NumberStyles.Any, CultureInfo.InvariantCulture); probabilities_list.Add(weight); var prob_len = weight_string.Value.Length; consequents_list.Add((LSystemNodeGenerator)parseWord(line.Substring(prob_len).Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex))); } } else { consequents_list.Add((LSystemNodeGenerator)parseWord(sucsessor_string.Trim(), new LSystemWordGeneratorBuilder(predecesor.variableIndex))); } //context if (context != null) { if (consequents_list.Count > 1) { rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray(), context)); } else { rules.Add(new LSystemRuleParametricStochasticContext(predecesor, conditions, consequents_list[0], context)); } } else { if (consequents_list.Count > 1) { rules.Add(new LSystemRuleParametricStochastic(predecesor, conditions, consequents_list.ToArray(), probabilities_list.ToArray())); } else { rules.Add(new LSystemRuleParametric(predecesor, conditions, consequents_list[0])); } } //var conditions = parts[0]; //var result } catch (Exception e) { sr.Close(); throw new Exception(String.Format("error in {0} with a message \n {1}", line,e.Message)); } } return rules; } private static void getPredecesorContext(string predecesor_string, out LSystemNodeLiteralVariable predecesor, out LSystemContext context) { string partent_context_str = null; string child_context_str = null; string mid_context_str = null; int mid_start = 0; for (int i = 0; i < predecesor_string.Length; i++) { if (predecesor_string[i] == '<' && partent_context_str == null) { partent_context_str = predecesor_string.Substring(0, i).Trim(); mid_start = i+1; //Console.WriteLine(i); } if (predecesor_string[i] == '>' && child_context_str == null) { child_context_str = predecesor_string.Substring(i + 1).Trim(); mid_context_str = predecesor_string.Substring(mid_start, i - mid_start).Trim(); //Console.WriteLine(i); } } if (mid_context_str == null) { mid_context_str = predecesor_string.Substring(mid_start).Trim(); } LSystemNodeLiteralVariable parent = null; LSystemNodeLiteralVariable[] children = null; predecesor = LSystemFileParser.parseContextLiteral(mid_context_str); if (partent_context_str != null) { parent = LSystemFileParser.parseContextLiteral(partent_context_str); foreach (KeyValuePair kvp in new Dictionary(predecesor.variableIndex)) { //textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value); predecesor.variableIndex[kvp.Key] = kvp.Value + parent.variableIndex.Count; } foreach (KeyValuePair kvp in parent.variableIndex) { //textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value); predecesor.variableIndex.Add(kvp.Key, kvp.Value); } } if (child_context_str != null) { int size = predecesor.variableIndex.Count; children = LSystemFileParser.parseSuccessorsContext(child_context_str); int offset = 0; foreach (var child in children) { foreach (KeyValuePair kvp in child.variableIndex) { //textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value); predecesor.variableIndex.Add(kvp.Key, kvp.Value + size + offset); } offset += child.variableIndex.Count; } } if (child_context_str != null) { if (partent_context_str != null) { context = new LSystemContext(parent, children); } else { context = new LSystemContext(); context.setOnlySucceeding(children); } } else if (partent_context_str != null) { context = new LSystemContext(); context.setOnlyPreceding(parent); } else { context = null; } } } }