I'm having a little trouble reading values in from a database and assigning them to an array. It seem to work in my unit tests, but in practice some values are missing.
Here's my database code:
private void GetParameterValuesFromDatabase()
{
this.parameterValues = (from DataRow r in this.database.RunCommand("select * from KST_PARAM_VALUES v join DM_PARM_NAME p on v.PARM_NAME_KEY = p.PARM_NAME_KEY").Rows
where (int)r["SCENARIO_KEY"] == this.scenario.ScenarioKey
select new DatabaseParameter
{
ParameterValuesKey = r.Field<int>(0),
ProfileType = r.Field<string>(1),
ScenarioKey = r.Field<int>(2),
StressEditorKey = r.Field<int>(3),
StressClassKey = r.Field<int>(4),
PeriodKey = r.Field<int>(5),
ParameterNameKey = r.Field<int>(6),
ParameterValue = r.Field<double>(7),
ActiveStress = (r.Field<string>(8) == "Y") ? true : false,
ParameterKey = (int)r["PARM_NUMBER"]
}).ToDictionary(r => r.ParameterValuesKey, r => r);
}
Not having any issues with this part of my code, just showing for completeness.
private void LoadParameters()
{
this.GetParameterValuesFromDatabase();
// TODO: Assuming 9 periods for now, change to allow for variable periods
for (int i = 1; i <= MaxNumberOfStressPeriods; i++)
{
this.parametersByPeriod.Add(i, this.parameterValues.Where(t => t.Value.PeriodKey == i).ToDictionary(t => t.Key, t => t.Value));
}
Log.Instance.LogMessage(LogLevel.Debug, "Created parameter dictionaries from database");
// For every stress editor in the dictionary of stress editors
foreach (KeyValuePair<int, ClassList> ed in this.stressParams)
{
// For every type of class selector
foreach (ClassSelector c in Enum.GetValues(typeof(ClassSelector)))
{
// For each of the classes within each class list within the editor
for (int i = 0; i < ed.Value.ClassLists[c].Count; i++)
{
string className = ed.Value.ClassLists[c][i].Name;
// For each double array in each class
foreach (KeyValuePair<int, double[]> t in ed.Value.ClassLists[c][i].ClassVariables.EditorParameters)
{
double[] values = this.GetParameterValues(t.Key, ed.Key, className);
BasicStressEditorVariables.AddParameters(values, ed.Value, className, t.Key);
}
}
}
}
}
}
Above shows the overall LoadParameters() method.
Below we have some code that selects 9 values from the dictionary constructed from the database, ready to be added to the array.
private double[] GetParameterValues(int paramKey, int editorKey, string className)
{
double[] values = new double[9];
for (int i = 1; i <= MaxNumberOfStressPeriods; i++)
{
Dictionary<int, DatabaseParameter> temp = this.parametersByPeriod[i];
foreach (KeyValuePair<int, DatabaseParameter> d in temp)
{
if (d.Value.ParameterKey == paramKey && d.Value.PeriodKey == i && d.Value.StressEditorKey == editorKey && d.Value.ProfileType == className)
{
values[i - 1] = d.Value.ParameterValue;
}
}
}
return values;
}
Below shows getting the destination array from the dictionary, as indexes cannot be passed by reference
public static void AddParameters(double[] values, ClassList editor, string className, int paramKey)
{
// TODO: Maybe search all lists to eliminate the need for the class selector as a parameter
// TODO: Will throw an exception when nothing is found. Handle it
ParameterClass p = null;
foreach (ClassSelector c in Enum.GetValues(typeof(ClassSelector)))
{
p = editor.ClassLists[c].FirstOrDefault(f => f.Name == className);
if (p != null)
{
break;
}
}
// TODO: Notify that could not be found
if (p == null)
{
Log.Instance.LogMessage(LogLevel.Error, $"Unable to find class {className}");
return;
}
double[] dest = p.ClassVariables.editorParameters[paramKey];
AddParameterValues(values, ref dest);
}
And here's the AddParameterValues() method:
private static void AddParameterValues(double[] values, ref double[] destination)
{
if (values.Length != destination.Length)
{
return;
}
for (int i = 0; i < values.Length; i++)
{
destination[i] = values[i];
}
}
Debugging shows that some values are being loaded into the destination array, but some aren't. Could anyone tell me why this is? Or if not, point me toward some material?
Thank you for your time
I'm not that C# specialist but looking to following code as a C programmer
private double[] GetParameterValues(int paramKey, int editorKey, string className)
{
double[] values = new double[9];
//...
return values;
}
I would assume that the lifetime of values is only within the function GetParameterValues and the function GetParameterValues delivers the caller with reference to a dead variable.
What if you change the prototype to something like
private void GetParameterValues(ref double[] values, int paramKey, int editorKey, string className)
Related
I want to change a value in an array that holds a struct:
SitSpot[] _spots = new SitSpot[4];
The struct fields are:
struct SitSpot
{
public SitSpot(Transform spot, bool isOccupied, int id)
{
IsOccupied = isOccupied;
Spot = spot;
Id = id;
}
public bool IsOccupied;
public Transform Spot;
public int Id;
}
However, when accessing the array element and trying to modify it, the original array element remains unchanged
SitSpot spot = _spots.Where(x => x.IsOccupied != true).OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position)).FirstOrDefault();
spot.IsOccupied = true;
So it is necessary to find the index of the array element by to modify specified value:
SitSpot spot = _spots
.Where(x => x.IsOccupied != true)
.OrderBy(x => Vector3.Distance(x.Spot.position, driver.transform.position))
.FirstOrDefault();
spot.IsOccupied = true;
int i = Array.FindIndex(_spots, x => x.Id == spot.Id);
_spots[i] = spot;
My question is, can I access the element inside the array and modify it directly rather than changing the value and reassigning it?
The best choice in your situation seems not to use LINQ. I propose following
static class Extensions
{
public static void SetOccupied(this SitSpot[] spots, Driver driver)
{
int index = -1;
int distance = int.MaxValue;
for (int i = 0; i < spots.Length; i++)
{
if (spots[i].IsOccupied != true)
{
var distance2 = Vector3.Distance(spots[i].Spot.position,
driver.transform.position);
if (distance >= distance2)
{
distance = distance2;
index = i;
}
}
}
if (index != -1)
{
spots[index].IsOccupied = true;
}
}
}
I have a program which builds a very large tree from input data and traverses it, both by recursion. I have tested the program on smaller inputs (and thus smaller trees) and it functions as intended. However when the input data is much larger i run into 'Process is terminated due to StackOverflowException'. I assume this is due to the stack running out of space. Is there any way to prevent this or do I have to switch to building the tree via iteration instead? Or perhaps I am missing a case of infinite recursion somewhere?
Here is the code:
class Program
{
static int[] tileColors;
static Color[] colors;
static int totalTiles;
static void Main(string[] args)
{
Stopwatch s = new Stopwatch();
s.Start();
string[] data = File.ReadAllLines("colors.txt");
totalTiles = int.Parse(data[0].Split(' ')[0]);
int totalColors = int.Parse(data[0].Split(' ')[1]);
string[] colorsRaw = data[1].Split(' ');
tileColors = new int[totalTiles];
for (int i = 0; i < totalTiles; i++)
{
tileColors[i] = int.Parse(colorsRaw[i]) - 1;
}
colors = new Color[totalColors];
for (int i = 3; i < data.Length; i++)
{
string[] raw = data[i].Split(' ');
int[] pair = new int[] { int.Parse(raw[0]) - 1, int.Parse(raw[1]) - 1 };
if (colors[pair[0]] == null)
colors[pair[0]] = new Color(pair[1]);
else
colors[pair[0]].pairs.Add(pair[1]);
if (colors[pair[1]] == null)
colors[pair[1]] = new Color(pair[0]);
else
colors[pair[1]].pairs.Add(pair[0]);
}
Tree t = new Tree();
t.root = new Node(0);
PopulateTree(t.root);
long ans = t.CountMatchingLeaves(t.root, totalTiles - 1) % 1000000007;
Console.WriteLine(ans);
s.Stop();
Console.WriteLine(s.ElapsedMilliseconds);
}
static void PopulateTree(Node root)
{
for (int i = root.tile + 1; i < totalTiles; i++)
{
if (colors[tileColors[i]] == null) continue;
if (colors[tileColors[i]].Compatible(tileColors[root.tile]))
{
var node = new Node(i);
root.children.Add(node);
PopulateTree(node);
}
}
}
}
class Color
{
public List<int> pairs = new List<int>();
public Color(int pair)
{
pairs.Add(pair);
}
public bool Compatible(int c)
{
return pairs.Contains(c);
}
}
class Node
{
public List<Node> children = new List<Node>();
public int tile;
public Node(int tile)
{
this.tile = tile;
}
}
class Tree
{
public Node root;
public List<Node> GetMatchingLeaves(Node root, int match)
{
if (root.children.Count == 0)
{
if (root.tile == match)
{
return new List<Node>() { root };
}
return new List<Node>();
}
List<Node> list = new List<Node>();
foreach(var c in root.children)
{
list.AddRange(GetMatchingLeaves(c, match));
}
return list;
}
public long CountMatchingLeaves(Node root, int match)
{
if (root.children.Count == 0)
{
if (root.tile == match)
{
return 1;
}
return 0;
}
long count = 0;
foreach (var c in root.children)
{
count += CountMatchingLeaves(c, match);
}
return count;
}
}
You can always rewrite recursion as iteration, usually by using a stack class rather than rely on your thread's stack. For your code it would look like this:
static void PopulateTree(Node start)
{
var nodes = new Stack<Node>();
nodes.Push(start);
while(nodes.Count != 0)
{
var root = nodes.Pop();
for (int i = root.tile + 1; i < totalTiles; i++)
{
if (colors[tileColors[i]] == null) continue;
if (colors[tileColors[i]].Compatible(tileColors[root.tile]))
{
var node = new Node(i);
root.children.Add(node);
nodes.Push(node);
}
}
}
}
The while loop checking for more items is the equivalent of your terminating condition in recursion.
I've reviewed numerous articles here on SO about how to group by using a LINQ statement on a list object but the following code fails to group anything even though all the variables have the exact same values. Could someone please tell me why this might not be working? Does it have something to do with LINQ deferred execution? I've tried a sample where I included a second select statement which did not help. I'm passing in a list<MyClass> object which has two identical items and one that is not, so when this statement executes I should receive back only two items.
Actual values in the code:
Type = 1, Capacity = 50, Goal = "Teach algebra",
Attachments = "", Hours = 1, TypeDesignation = 3,
TypeControl = 1, Supplies = 0
TypeControl and Supplies are both objects themselves. Supplies is empty.
TypeControl contains Id = 23, Text = "Math", Active = 1
var test = newclass.GroupBy(n => new
{
n.Type,
n.Capacity,
n.Goal,
n.Attachments,
n.Hours,
n.TypeDesignation,
n.TypeControl,
n.Supplies
}).Distinct().Select(n => new MyClass()
{
Type = n.Key.Type,
Capacity = n.Key.Capacity,
Goal = n.Key.Goal ,
Attachments = n.Key.Attachments,
Hours = n.Key.Hours ,
TypeDesignation = n.Key.TypeDesignation,
TypeControl = n.Key.TypeControl,
Supplies = n.Key.Supplies
});
The answer to my question was that the all the objects inside were, in fact, not equal, in that I had a sub-object that during the group by one object was read as being null while the other was reading as being 0 so they never could group together but when I looked at them with intellisense they always both said null. I resolved the issue by looping through my list and using a comparer method to drill down into the sub-objects and find the differences.
VerifyDuplicates duplicates = new VerifyDuplicates();
List<MyClass> newClass = new List<MyClass>();
classes = classes.OrderBy(s => s.Type).ToList();
List<int> idsToDelete = new List<int>();
for (int i = 0; i < classes.Count; i++)
{
if (i + 1 < classes.Count)
{
var x = duplicates.Compare(classes[i], classes[i + 1]);
if (x == 1)
idsToDelete.Add(classes[i+1].Id);
}
}
newClass = classes.Where(n => !idsToDelete.Contains(n.Id)).Select(n => n).ToList();
public class VerifyDuplicates : Comparer<MyClass>
{
public override int Compare(MyClass x, MyClass y)
{
int p = 0;
if(x != null && y != null)
{
if(x.Type.Equals(y.Type)) { p += 1; }
if(x.Attachments.Equals(y.Attachments)) { p += 1; }
if(x.Capacity.Equals(y.Capacity)) { p += 1; }
if(x.Goal.Equals(y.Goal)) { p += 1; }
if(x.Hours.Equals(y.Hours)) { p += 1; }
if(x.TypeDesignation.Equals(y.TypeDesignation)) { p += 1; }
if(x.TypeControl != null && y.TypeControl != null)
if(x.TypeControl[0].Equals(y.TypeControl[0])) { p += 1; }
if(x.Supplies != null && y.Supplies!= null)
if (x.Supplies.Equals(y.Supplies)) { p += 1; }
return p;
}
}
}
I have a problem that I really cannot get my head around. I know how to sort data in general but this one is taxing me!
I have a list of values in an array. The values look like this:
[03;02HTransactions
[03;16HPost Transactions
[04:02HDividends
[04;16HPostDividends
[01:01H-----------------------------------------------------
[05:01H-----------------------------------------------------
[02:16HDate: Today
[02:02HTrades
So its essentially ANSI formatting from a terminal screen which i'm trying to re-construct into a list so that I can print it on our test logs so it at least looks vaguely readable.
So this is how it works within the first 6 characters: [XX:YY where XX is the row number and YY is the column number. The H doesn't matter its just formatting.
Here is what I've got so far:
List<string> rows = new List<string>();
for (int i = 0; i <= filteredLines.Count - 1; i++)
{
int rowIndex = Convert.ToInt32(filteredLines[i].Substring(1, 2));
Dictionary<int, string> columns = new Dictionary<int, string>();
foreach (string row in filteredLines)
{
int innerRowIndex = Convert.ToInt32(row.Substring(1, 2));
if (innerRowIndex == rowIndex)
{
int columnIndex = Convert.ToInt32(filteredLines[i].Substring(4, 2));
string value = filteredLines[i].Remove(0, 7);
columns.Add(columnIndex, value);
}
}
string columnConcatenated = "";
for (int j = 0; j <= columns.Count; j ++ )
{
columnConcatenated = columnConcatenated + columns[j];
}
rows.Add(columnConcatenated);
}
What I essentially want to do is to to build up the lines and sort them into a list based on the row number so it looks like:
--------------------------------------------
Trades Date: Today
Transactions Post Transactions
Dividends Post Dividends
--------------------------------------------
my example isn't 100% accurate as its hard to count the exact columns, but you get the idea. They just need to be on the same line in the correct order.
I cant help but feel i'm probably not going about this the best way. So is there an ideal way for me to achieve this?
Okay, I would implement it like so:
Create a simple POCO/class to represent a log entry with the properties row, column and text
Implement the IComparable interface, so these items can be sorted, on row # first and on column # second
Parse every log line and create a simple POCO Entry object for each
Use a simple List<Entry> and sort it afterwards
Use a StringBuilder to build up the final output
Loop over every Entry in the list, checking it's row # and perhaps entering some newlines for our StringBuilder if there are gaps
If we get an Entry with a row number which is the same as a previous one (which you can use a temp variable for), don't output a newline, but append the Entry.text to this line instead, at the column you want
You already have code to parse each line, extracting its row, column, and displayed text. If the lines of text are not sparse, you could represent this as basically a 2D dynamic array of characters that automatically pads itself out with spaces or empty lines, like so:
public class StringBuilderList : IList<string>
{
readonly List<StringBuilder> list = new List<StringBuilder>();
readonly char pad = ' ';
const char DefaultPad = ' ';
public StringBuilderList(char pad)
{
this.pad = pad;
}
public StringBuilderList() : this(DefaultPad) {}
public void SetString(int iLine, int iChar, string text)
{
list.EnsureCount(iLine + 1);
if (list[iLine] == null)
list[iLine] = new StringBuilder(iChar + text.Length);
var sb = list[iLine];
sb.OverwriteAt(iChar, text, pad);
}
#region IList<string> Members
public int IndexOf(string item)
{
for (int i = 0; i < Count; i++)
if (this[i] == item) // this is not memory-efficient.
return i;
return -1;
}
public void Insert(int index, string item)
{
var sb = new StringBuilder(item);
list.Insert(index, sb);
}
public void RemoveAt(int index)
{
list.RemoveAt(index);
}
public string this[int index]
{
get
{
// Hide the nulls from the caller!
var sb = list[index];
if (sb == null)
return string.Empty;
return sb.ToString();
}
set
{
if (string.IsNullOrEmpty(value))
{
if (list[index] != null)
list[index].Length = 0;
}
else if (list[index] == null)
{
list[index] = new StringBuilder(value);
}
else
{
list[index].Length = 0;
list[index].Append(value);
}
}
}
#endregion
#region ICollection<string> Members
public void Add(string item)
{
list.Add(new StringBuilder(item));
}
public void Clear()
{
list.Clear();
}
public bool Contains(string item)
{
return IndexOf(item) >= 0;
}
public void CopyTo(string[] array, int arrayIndex)
{
foreach (var str in this)
array[arrayIndex++] = str;
}
public int Count
{
get { return list.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(string item)
{
int index = IndexOf(item);
if (index < 0)
return false;
RemoveAt(index);
return true;
}
#endregion
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
foreach (var sb in list)
yield return (sb == null ? string.Empty : sb.ToString());
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
SetString is the method you would use, it copies the string into the 2d array of characters, expanding it as required with empty lines and/or space characters.
And helper methods:
public static class ListHelper
{
public static void Resize<T>(this List<T> list, int count)
{
if (list == null || count < 0)
throw new ArgumentException();
int oldCount = list.Count;
if (count > oldCount)
{
list.Capacity = count;
for (int i = oldCount; i < count; i++)
list.Add(default(T));
}
else if (count < oldCount)
{
for (int i = oldCount-1; i >= count; i--)
list.RemoveAt(i);
}
}
public static void EnsureCount<T>(this List<T> list, int count)
{
if (list == null || count < 0)
throw new ArgumentException();
if (count > list.Count)
list.Resize(count);
}
}
public static class StringBuilderHelper
{
public static void OverwriteAt(this StringBuilder sb, int index, string text, char pad)
{
var textLen = text.Length;
if (textLen + index > sb.Length)
{
for (int i = sb.Length, newLen = textLen + index; i < newLen; i++)
{
sb.Append(pad);
}
}
for (int i = 0; i < textLen; i++)
{
sb[index + i] = text[i];
}
}
}
So a few people have some solutions though they seemed a bit over complicated for what I needed. I managed to resolve the issue myself using a pen and paper then trying it in visual studio. Here is what I did:
First I created a list by looking through the original array and I sorted and removed duplicates:
List<int> rowList = new List<int>();
for (int i = 0; i <= filteredLines.Count - 1; i++)
{
int rowIndex = Convert.ToInt32(filteredLines[i].Substring(1, 2));
rowList.Add(rowIndex);
}
rowList = rowList.Distinct().ToList<int>();
rowList.Sort();
Next I created a container for my final list that would hold the values, then I ran my sorting routine which makes use of a SortedList in order to ensure the columns are sorted before I concatenate them:
foreach (int listRow in rowList)
{
SortedList<int, string> columnList = new SortedList<int, string>();
foreach(string row in filteredLines)
{
int rowIndex = Convert.ToInt32(row.Substring(1, 2));
if(rowIndex==listRow)
{
int columnIndex = Convert.ToInt32(row.Substring(4, 2));
string value = row.Remove(0, 7);
if(columnList.ContainsKey(columnIndex))
{
columnList[columnIndex] = columnList[columnIndex] + value;
}
else
{
columnList.Add(columnIndex, value);
}
}
}
string concatenatedColumns = "";
foreach(string col in columnList.Values)
{
concatenatedColumns = concatenatedColumns + col;
}
parsedAndSortedRows.Add(concatenatedColumns);
}
It does the job fine and puts all the columns in order on the correct row as I wanted. Thanks for the help to everyone though it was through the different answers I helped come up with this solution.
Where can I find a simple (as much as possible, but no simpler!) implementation of an LR(1) parser generator?
I'm not looking for performance, just the ability to generate the LR(1) states (item sets).
C++, C#, Java, and Python would all work for me.
I've written a very simple one in C# and wanted to share it here.
It basically populates the action lookup table, which tells you which state to shift to or which rule to use for reduction.
If the number is nonnegative, then it denotes a new state; if it's negative, then its one's complement (i.e. ~x) denotes the rule index.
All you need now is to make a lexer and to do the actual parsing with the action table.
Note 1: It might be quite slow at generating the states for a real-world grammar, so you might want to think twice before using it in production code!
Note 2: You might want to double-check its correctness, since I've only checked it a bit.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using size_t = System.UInt32;
public class LRParser
{
private string[] symbols; // index => symbol
private IDictionary<string, size_t> interned = new SortedDictionary<string, size_t>(); // symbol => index
private int[/*state*/, /*lookahead*/] actions; // If >= 0, represents new state after shift. If < 0, represents one's complement (i.e. ~x) of reduction rule.
public LRParser(params KeyValuePair<string, string[]>[] grammar)
{
this.interned.Add(string.Empty, new size_t());
foreach (var rule in grammar)
{
if (!this.interned.ContainsKey(rule.Key))
{ this.interned.Add(rule.Key, (size_t)this.interned.Count); }
foreach (var symbol in rule.Value)
{
if (!this.interned.ContainsKey(symbol))
{ this.interned.Add(symbol, (size_t)this.interned.Count); }
}
}
this.symbols = this.interned.ToArray().OrderBy(p => p.Value).Select(p => p.Key).ToArray();
var syntax = Array.ConvertAll(grammar, r => new KeyValuePair<size_t, size_t[]>(this.interned[r.Key], Array.ConvertAll(r.Value, s => this.interned[s])));
var nonterminals = Array.ConvertAll(this.symbols, s => new List<size_t>());
for (size_t i = 0; i < syntax.Length; i++) { nonterminals[syntax[i].Key].Add(i); }
var firsts = Array.ConvertAll(Enumerable.Range(0, this.symbols.Length).ToArray(), s => nonterminals[s].Count > 0 ? new HashSet<size_t>() : new HashSet<size_t>() { (size_t)s });
int old;
do
{
old = firsts.Select(l => l.Count).Sum();
foreach (var rule in syntax)
{
foreach (var i in First(rule.Value, firsts))
{ firsts[rule.Key].Add(i); }
}
} while (old < firsts.Select(l => l.Count).Sum());
var actions = new Dictionary<int, IDictionary<size_t, IList<int>>>();
var states = new Dictionary<HashSet<Item>, int>(HashSet<Item>.CreateSetComparer());
var todo = new Stack<HashSet<Item>>();
var root = new Item(0, 0, new size_t());
todo.Push(new HashSet<Item>());
Closure(root, todo.Peek(), firsts, syntax, nonterminals);
states.Add(new HashSet<Item>(todo.Peek()), states.Count);
while (todo.Count > 0)
{
var set = todo.Pop();
var closure = new HashSet<Item>();
foreach (var item in set)
{ Closure(item, closure, firsts, syntax, nonterminals); }
var grouped = Array.ConvertAll(this.symbols, _ => new HashSet<Item>());
foreach (var item in closure)
{
if (item.Symbol >= syntax[item.Rule].Value.Length)
{
IDictionary<size_t, IList<int>> map;
if (!actions.TryGetValue(states[set], out map))
{ actions[states[set]] = map = new Dictionary<size_t, IList<int>>(); }
IList<int> list;
if (!map.TryGetValue(item.Lookahead, out list))
{ map[item.Lookahead] = list = new List<int>(); }
list.Add(~(int)item.Rule);
continue;
}
var next = item;
next.Symbol++;
grouped[syntax[item.Rule].Value[item.Symbol]].Add(next);
}
for (size_t symbol = 0; symbol < grouped.Length; symbol++)
{
var g = new HashSet<Item>();
foreach (var item in grouped[symbol])
{ Closure(item, g, firsts, syntax, nonterminals); }
if (g.Count > 0)
{
int state;
if (!states.TryGetValue(g, out state))
{
state = states.Count;
states.Add(g, state);
todo.Push(g);
}
IDictionary<size_t, IList<int>> map;
if (!actions.TryGetValue(states[set], out map))
{ actions[states[set]] = map = new Dictionary<size_t, IList<int>>(); }
IList<int> list;
if (!map.TryGetValue(symbol, out list))
{ map[symbol] = list = new List<int>(); }
list.Add(state);
}
}
}
this.actions = new int[states.Count, this.symbols.Length];
for (int i = 0; i < this.actions.GetLength(0); i++)
{
for (int j = 0; j < this.actions.GetLength(1); j++)
{ this.actions[i, j] = int.MinValue; }
}
foreach (var p in actions)
{
foreach (var q in p.Value)
{ this.actions[p.Key, q.Key] = q.Value.Single(); }
}
foreach (var state in states.OrderBy(p => p.Value))
{
Console.WriteLine("State {0}:", state.Value);
foreach (var item in state.Key.OrderBy(i => i.Rule).ThenBy(i => i.Symbol).ThenBy(i => i.Lookahead))
{
Console.WriteLine(
"\t{0}: {1} \xB7 {2} | {3} → {0}",
this.symbols[syntax[item.Rule].Key],
string.Join(" ", syntax[item.Rule].Value.Take((int)item.Symbol).Select(s => this.symbols[s]).ToArray()),
string.Join(" ", syntax[item.Rule].Value.Skip((int)item.Symbol).Select(s => this.symbols[s]).ToArray()),
this.symbols[item.Lookahead] == string.Empty ? "\x04" : this.symbols[item.Lookahead],
string.Join(
", ",
Array.ConvertAll(
actions[state.Value][item.Symbol < syntax[item.Rule].Value.Length ? syntax[item.Rule].Value[item.Symbol] : item.Lookahead].ToArray(),
a => a >= 0 ? string.Format("state {0}", a) : string.Format("{0} (rule {1})", this.symbols[syntax[~a].Key], ~a))));
}
Console.WriteLine();
}
}
private static void Closure(Item item, HashSet<Item> closure /*output*/, HashSet<size_t>[] firsts, KeyValuePair<size_t, size_t[]>[] syntax, IList<size_t>[] nonterminals)
{
if (closure.Add(item) && item.Symbol >= syntax[item.Rule].Value.Length)
{
foreach (var r in nonterminals[syntax[item.Rule].Value[item.Symbol]])
{
foreach (var i in First(syntax[item.Rule].Value.Skip((int)(item.Symbol + 1)), firsts))
{ Closure(new Item(r, 0, i == new size_t() ? item.Lookahead : i), closure, firsts, syntax, nonterminals); }
}
}
}
private struct Item : IEquatable<Item>
{
public size_t Rule;
public size_t Symbol;
public size_t Lookahead;
public Item(size_t rule, size_t symbol, size_t lookahead)
{
this.Rule = rule;
this.Symbol = symbol;
this.Lookahead = lookahead;
}
public override bool Equals(object obj) { return obj is Item && this.Equals((Item)obj); }
public bool Equals(Item other)
{ return this.Rule == other.Rule && this.Symbol == other.Symbol && this.Lookahead == other.Lookahead; }
public override int GetHashCode()
{ return this.Rule.GetHashCode() ^ this.Symbol.GetHashCode() ^ this.Lookahead.GetHashCode(); }
}
private static IEnumerable<size_t> First(IEnumerable<size_t> symbols, IEnumerable<size_t>[] map)
{
foreach (var symbol in symbols)
{
bool epsilon = false;
foreach (var s in map[symbol])
{
if (s == new size_t()) { epsilon = true; }
else { yield return s; }
}
if (!epsilon) { yield break; }
}
yield return new size_t();
}
private static KeyValuePair<K, V> MakePair<K, V>(K k, V v) { return new KeyValuePair<K, V>(k, v); }
private static void Main(string[] args)
{
var sw = Stopwatch.StartNew();
var parser = new LRParser(
MakePair("start", new string[] { "exps" }),
MakePair("exps", new string[] { "exps", "exp" }),
MakePair("exps", new string[] { }),
MakePair("exp", new string[] { "INTEGER" })
);
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
LRSTAR 9.1 is a minimal LR(1) and LR(*) parser generator. You can use it to verify that your parser generator is giving the correct states, by using option '/s'. LRSTAR has been tested against HYACC and found to be giving the correct LR(1) states. 20 grammars are provided with LRSTAR and 6 Microsoft Visual Studio projects.