MWS_2021/Unity Project/Assets/Scripts/LSystem/LSystemParser.cs

349 lines
15 KiB
C#
Raw Normal View History

2021-04-17 22:09:48 +02:00
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<string, int> variableIndex { get;}
public LSystemWordGeneratorBuilder(Dictionary<string,int> 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<string, int>();
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<LSystemNodeLiteralVariable> result = new List<LSystemNodeLiteralVariable>();
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<LSystemRule> 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<LSystemRule> parseLSystemRules(StreamReader sr) {
List<LSystemRule> rules = new List<LSystemRule>();
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<float>();
var consequents_list = new List<LSystemNodeGenerator>();
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<string, int> kvp in new Dictionary<string, int>(predecesor.variableIndex)) {
//textBox3.Text += ("Key = {0}, Value = {1}", kvp.Key, kvp.Value);
predecesor.variableIndex[kvp.Key] = kvp.Value + parent.variableIndex.Count;
}
foreach (KeyValuePair<string, int> 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<string, int> 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;
}
}
}
}