using GOLD;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace TestGadget
{
public static class TestGadget
{
static TestGadget()
{
MyParser = new MyParserClass();
MyParser.Translations = new Dictionary<string, string>();
MyParser.Files = new Dictionary<string, string>();
MyParser.Productions = new Dictionary<string, List<string>>();
}
public static void WriteTree(TreeView tree)
{
for (int j = 0; j < MyParser.Productions["rootnode"].Count; j++)
{
string code = MyParser.Productions["rootnode"][j];
string text = "NULL";
if (code != null)
{
text = MyParser.Translations[code];
var node = tree.Nodes.Add(text);
AddLayer(node, code);
}
}
}
static void AddLayer(TreeNode node, string code)
{
if (MyParser.Productions.ContainsKey(code) == false) return;
List<string> ps = MyParser.Productions[code];
for (int j = 0; j < ps.Count; j++)
{
string text = "NULL";
if (ps[j] != null)
{
text = MyParser.Translations[ps[j]];
var n = node.Nodes.Add(text);
AddLayer(n, ps[j]);
}
}
}
public static void LoadGrammer(string path)
{
try
{
if (MyParser.Setup(path))
{
//MessageBox.Show("CGT loaded");
}
else
{
MessageBox.Show("CGT failed to load");
}
}
catch (GOLD.ParserException ex)
{
MessageBox.Show(ex.Message);
}
}
public static void ParseTextFile(string filename)
{
if (MyParser.Loaded == false) return;
string filetext = ReadTextFile(filename);
if (filetext == null || string.IsNullOrWhiteSpace(filetext)) return;
ParseSource(filename);
}
public static void ParseTextFiles(string path, string filename)
{
if (MyParser.Loaded == false) return;
List<string> parsedFiles = new List<string>();
string cur = path + filename;
while (cur != "")
{
parsedFiles.Add(cur);
string filetext = ReadTextFile(cur);
if (filetext == null || string.IsNullOrWhiteSpace(filetext)) continue;
ParseSource(cur);
cur = "";
foreach (string s in MyParser.Files.Values)
{
if (parsedFiles.Contains(path + s) == false)
{
cur = path + s;
break;
}
}
}
}
static string ReadTextFile(string filename)
{
try
{
string text = File.ReadAllText(filename);
return text;
}
catch
{
return null;
}
}
static MyParserClass MyParser;
static void ParseSource(string path)
{
try
{
string text = File.ReadAllText(path);
StringReader reader = new StringReader(text);
bool result = MyParser.Parse(reader);
if (result)
{
//MessageBox.Show(path + " parsed successfully!");
}
else
{
MessageBox.Show(path + Environment.NewLine + MyParser.FailMessage);
}
}
catch (GOLD.ParserException ex)
{
MessageBox.Show(ex.Message);
}
}
}
internal class MyParserClass
{
public bool Loaded = false;
private GOLD.Parser parser = new GOLD.Parser();
public GOLD.Reduction? Root = null;//hacked to be nullable, it wasn't
public string FailMessage = "";
public bool Setup(string FilePath)
{
Loaded = parser.LoadTables(FilePath);
return Loaded;
}
public bool Parse(TextReader reader)
{
GOLD.ParseMessage response;
bool done = false;
bool accepted = false;
parser.Open(reader);
parser.TrimReductions = false;
while (!done)
{
response = parser.Parse();
switch (response)
{
case GOLD.ParseMessage.LexicalError:
//Cannot recognize token
FailMessage = "Lexical Error:\n" +
"Position: " + parser.CurrentPosition().Line + ", " + parser.CurrentPosition().Column + "\n" +
"Read: " + parser.CurrentToken().Data;
done = true;
break;
case GOLD.ParseMessage.SyntaxError:
//Expecting a different token
FailMessage = "Syntax Error:\n" +
"Position: " + parser.CurrentPosition().Line + ", " + parser.CurrentPosition().Column + "\n" +
"Read: " + parser.CurrentToken().Data + "\n" +
"Expecting: " + parser.ExpectedSymbols().Text();
done = true;
break;
case GOLD.ParseMessage.Reduction:
//Populate dictionaries
Populate(parser.CurrentReduction);
break;
case GOLD.ParseMessage.Accept:
//Accepted!
Root = (GOLD.Reduction)parser.CurrentReduction; //The root node!
done = true;
accepted = true;
break;
case GOLD.ParseMessage.TokenRead:
//You don't have to do anything here.
break;
case GOLD.ParseMessage.InternalError:
//INTERNAL ERROR! Something is horribly wrong.
done = true;
break;
case GOLD.ParseMessage.NotLoadedError:
//This error occurs if the CGT was not loaded.
FailMessage = "Tables not loaded";
done = true;
break;
case GOLD.ParseMessage.GroupError:
//GROUP ERROR! Unexpected end of file
FailMessage = "Runaway group";
done = true;
break;
}
}
return accepted;
}
public Dictionary<string, List<string>> Productions = new Dictionary<string, List<string>>();
public Dictionary<string, string> Translations = new Dictionary<string, string>();
public Dictionary<string, string> Files = new Dictionary<string, string>();
void Populate(object o)
{
Reduction r = (Reduction)o;
string ruleName = GetRuleName(r);
if (ruleName == "item")
{
Item? item = GetItem(r);
if (item == null) return;
if (item.Tag.FileId != null)
{
if (Files.ContainsKey(item.Tag.Id) == false)
{
Files.Add(item.Tag.Id, item.Tag.FileId);
}
}
if (Translations.ContainsKey(item.Tag.Id) == false)
{
Translations.Add(item.Tag.Id, item.Literal);
}
}
else if (ruleName == "expression")
{
Reduction litem = (Reduction)r.get_Data(0);
Item? lit = GetItem(litem);
if (lit == null) return;
var next = r.get_Data(2);
if(next is Reduction == false) return;
Reduction ritem = (Reduction)next;
string rule = ritem.Parent.Head().Name();
if (rule == "item")
{
Item? rit = GetItem(ritem);
if (rit == null) return;
List<string> rcodes = new List<string>() { rit.Tag.Id };
Productions.Add(lit.Tag.Id, rcodes);
}
else if (rule == "itemlist")
{
List<Reduction>? reductions = UnwindItemlist(ritem);
if (reductions == null) return;
List<Item> items = new List<Item>();
foreach (Reduction red in reductions)
{
if (red == null) continue;
Item? item = GetItem(red);
if (item == null) continue;
items.Add(item);
}
List<string> rcodes = new List<string>();
foreach (Item it in items)
{
rcodes.Add(it.Tag.Id);
}
Productions.Add(lit.Tag.Id, rcodes);
}
}
}
Item? GetItem(Reduction r)
{
string name = GetRuleName(r);
if (name != "item") return null;
Tag? t = getTag(r);
string literal = (string)r.get_Data(0);
return new Item(literal, t);
}
Tag? getTag(Reduction r)
{
string name = GetRuleName(r);
if (name != "item") return null;
Reduction rtag = (Reduction)r.get_Data(1); //get tag from "item"
if (rtag.Count() == 3)
{
string? tag = rtag.get_Data(1).ToString();
return new Tag(tag);
}
else if (rtag.Count() == 5)
{
string? tag = rtag.get_Data(3).ToString();
if (tag == null) return null; //log error
string? fname = rtag.get_Data(1).ToString();
if (fname == null) return null; //log error
return new Tag(tag, fname);
}
else return null; //log error
}
string GetRuleName(Reduction r)
{
string ruleName = r.Parent.Head().Name();
return ruleName;
}
List<Reduction>? UnwindItemlist(Reduction r)
{
Reduction left = (Reduction)r.get_Data(0);
Reduction right = (Reduction)r.get_Data(2);
if (GetRuleName(right) == "item")
{
return new List<Reduction>() { left, right };
}
else if (GetRuleName(right) == "itemlist")
{
List<Reduction>? li = UnwindItemlist(right);
if (li == null) return null;
List<Reduction> output = new List<Reduction>() { left };
foreach (Reduction e in li) output.Add(e);
return output;
}
return null;
}
}
public class Tag
{
string _id;
string? _fileId;
public string Id
{
get { return _id; }
}
public string? FileId
{
get { return _fileId; }
}
public Tag(string id)
{
_id = id;
}
public Tag(string id, string fileId)
{
_id = id;
_fileId = fileId;
}
}
public class Item
{
string _literal;
Tag _tag;
public string Literal
{
get { return _literal; }
}
public Tag Tag
{
get { return _tag; }
}
public Item(string literal, Tag tag)
{
_literal = literal;
_tag = tag;
}
}
}
//https://www.meziantou.net/introduction-to-goldparser.htm
//TestGadget.LoadGrammer(@"C:\PATH HERE\#DESCRIBE.egt");
//TestGadget.ParseTextFiles(@"C:\PATH HERE\", "0_root");
//TestGadget.WriteTree(MainTreeView);
// When there is a literal that is 8 symbols long it is mistaken for an id, resulting in a syntax error
// Cyrilic symbols result in a lexical error