Skip to content

Commit 9a6eaa9

Browse files
made XbnfDocument use a generated XbnfParser to parse its input. Fixed a bug with XbnfConcatExpression and XbnfOrExpression constructors
1 parent 4fe6647 commit 9a6eaa9

8 files changed

Lines changed: 193 additions & 70 deletions

File tree

pck/TextReaderEnumerable.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace Pck
99
{
10+
1011
public sealed class FileReaderEnumerable : TextReaderEnumerable
1112
{
1213
protected override bool CanCreateReader => true;
@@ -52,6 +53,31 @@ protected override TextReader CreateTextReader()
5253
}
5354
public abstract class TextReaderEnumerable : IEnumerable<char>
5455
{
56+
#region _OnceReaderEnumerable
57+
sealed class _OnceTextReaderEnumerable : TextReaderEnumerable
58+
{
59+
TextReader _reader;
60+
internal _OnceTextReaderEnumerable(TextReader reader)
61+
{
62+
_reader = reader;
63+
}
64+
protected override TextReader CreateTextReader()
65+
{
66+
if (null == _reader)
67+
throw new NotSupportedException("This method can only be called once.");
68+
var r = _reader;
69+
_reader = null;
70+
return r;
71+
}
72+
protected override bool CanCreateReader => false;
73+
}
74+
#endregion
75+
public static TextReaderEnumerable FromReader(TextReader reader)
76+
{
77+
if (null == reader)
78+
throw new ArgumentNullException("reader");
79+
return new _OnceTextReaderEnumerable(reader);
80+
}
5581
public IEnumerator<char> GetEnumerator()
5682
{
5783
return new TextReaderEnumerator(this);

pckw/expr.xbnf

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
expr = expr "+" term | term;
1+
expr= expr "+" term | term;
22
term= term "*" factor | factor;
33
factor= "(" expr ")" | int;
4+
5+
46
add="+";
57
mul="*";
68
lparen="(";

scratch/Program.cs

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -44,56 +44,9 @@ static void Main(string[] args)
4444

4545
parser.ShowHidden = false;
4646
var pt = parser.ParseSubtree();
47-
var hasErrors = false;
48-
foreach (var pn in ParseNode.Select(pt.FillDescendantsAndSelf(),"#ERROR"))
49-
{
50-
hasErrors = true;
51-
Console.Error.WriteLine("Syntax Error: " + pn.Value);
52-
}
53-
if(!hasErrors)
54-
{
55-
var doc = new XbnfDocument();
56-
foreach(var pc in pt.Children)
57-
{
58-
doc.Productions.Add(_ParseProduction(pc));
59-
}
60-
}
61-
}
62-
static XbnfAttribute _ParseAttribute(ParseNode p)
63-
{
64-
var name = p.Children[0].Value;
65-
var v = ParseNode.SelectFirst(p.Children, XbnfParser.attrvalue);
66-
var val = (object)true;
67-
if (null!=v)
68-
{
69-
string s = v.Children[0].Value;
70-
val = ParseContext.Create(s).ParseJsonValue();
71-
}
72-
return new XbnfAttribute(name, val);
73-
}
74-
static XbnfExpression _ParseExpression(ParseNode p)
75-
{
76-
return null;
77-
}
78-
static XbnfProduction _ParseProduction(ParseNode p)
79-
{
80-
var result = new XbnfProduction();
81-
result.SetLocation(p.Line, p.Column, p.Position);
82-
result.Name = p.Children[0].Value;
83-
var apn = ParseNode.SelectFirst(p.Children, XbnfParser.attributes);
84-
if(null!=apn)
85-
{
86-
foreach(var ap in ParseNode.Select(apn.Children, XbnfParser.attribute))
87-
result.Attributes.Add(_ParseAttribute(ap));
88-
}
89-
var pexp = ParseNode.SelectFirst(p.Children, XbnfParser.orExpression);
90-
if (null!=pexp)
91-
{
92-
result.Expression=_ParseExpression(pexp);
93-
}
94-
Console.Error.WriteLine(result);
95-
return result;
47+
9648
}
49+
9750
static void _TestXbnfTokenizers(string[] args)
9851
{
9952
var cfg = CfgDocument.ReadFrom(@"..\..\..\xbnf.pck");

xbnf/XbnfConcatExpression.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ public XbnfConcatExpression(XbnfExpression left, params XbnfExpression[] right)
1414
var r = right[i];
1515
if (null == Right)
1616
Right = r;
17-
else
18-
{
19-
var c = new XbnfConcatExpression();
20-
c.Left = Left;
21-
c.Right = Right;
22-
Right = null;
23-
Left = c;
24-
}
17+
18+
var c = new XbnfConcatExpression();
19+
c.Left = Left;
20+
c.Right = Right;
21+
Right = null;
22+
Left = c;
23+
2524
}
2625
}
2726
public XbnfConcatExpression()

xbnf/XbnfDocument.cs

Lines changed: 148 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public override string ToString()
106106
sb.AppendLine(Productions[i].ToString());
107107
return sb.ToString();
108108
}
109+
/*
109110
internal static XbnfDocument Parse(ParseContext pc)
110111
{
111112
var result = new XbnfDocument();
@@ -122,15 +123,158 @@ public static XbnfDocument Parse(IEnumerable<char> @string)
122123
=> Parse(ParseContext.Create(@string));
123124
public static XbnfDocument ReadFrom(TextReader reader)
124125
=> Parse(ParseContext.CreateFrom(reader));
126+
*/
127+
public static XbnfDocument Parse(IEnumerable<char> input)
128+
{
129+
XbnfDocument result;
130+
XbnfException.ThrowIfErrors(_TryParse(input, null, out result));
131+
return result;
132+
}
133+
public static XbnfDocument ReadFrom(TextReader input)
134+
{
135+
XbnfDocument result;
136+
XbnfException.ThrowIfErrors(TryReadFrom(input, out result));
137+
return result;
138+
}
125139
public static XbnfDocument ReadFrom(string filename)
126140
{
127-
using (var sr = File.OpenText(filename))
141+
XbnfDocument result;
142+
XbnfException.ThrowIfErrors(TryReadFrom(filename, out result));
143+
return result;
144+
}
145+
public static XbnfDocument ReadFromUrl(string url)
146+
{
147+
XbnfDocument result;
148+
XbnfException.ThrowIfErrors(TryReadFrom(url, out result));
149+
return result;
150+
}
151+
static XbnfAttribute _ParseAttribute(ParseNode p)
152+
{
153+
var name = p.Children[0].Value;
154+
var v = ParseNode.SelectFirst(p.Children, XbnfParser.attrvalue);
155+
var val = (object)true;
156+
if (null != v)
157+
{
158+
string s = v.Children[0].Value;
159+
val = ParseContext.Create(s).ParseJsonValue();
160+
}
161+
var result = new XbnfAttribute(name, val);
162+
result.SetLocation(p.Line, p.Column, p.Position);
163+
return result;
164+
}
165+
static XbnfExpression _ParseExpression(ParseNode p)
166+
{
167+
XbnfExpression result = null;
168+
switch (p.SymbolId)
128169
{
129-
var result = ReadFrom(sr);
130-
result.SetFilename(filename);
131-
return result;
170+
case XbnfParser.orExpression:
171+
if (1 == p.Children.Count)
172+
return _ParseExpression(p.Children[0]);
173+
result = new XbnfOrExpression(_ParseExpression(p.Children[0]), _ParseExpression(p.Children[2]));
174+
result.SetLocation(p.Line, p.Column, p.Position);
175+
return result;
176+
case XbnfParser.concatExpression:
177+
if (1 == p.Children.Count)
178+
return _ParseExpression(p.Children[0]);
179+
var right = new List<XbnfExpression>(p.Children.Count - 1);
180+
XbnfExpression left = null;
181+
foreach (var pch in p.Children)
182+
{
183+
if (XbnfParser.lparen == pch.SymbolId || XbnfParser.rparen == pch.SymbolId)
184+
continue;
185+
if (null == left)
186+
left = _ParseExpression(pch);
187+
else
188+
right.Add(_ParseExpression(pch));
189+
}
190+
result = new XbnfConcatExpression(left, right.ToArray());
191+
result.SetLocation(p.Line, p.Column, p.Position);
192+
return result;
193+
case XbnfParser.optionalExpression:
194+
result = new XbnfOptionalExpression(_ParseExpression(p.Children[1]));
195+
result.SetLocation(p.Line, p.Column, p.Position);
196+
return result;
197+
case XbnfParser.repeatExpression:
198+
result = new XbnfRepeatExpression(_ParseExpression(p.Children[1]), XbnfParser.repeatZero == p.Children[2].SymbolId);
199+
result.SetLocation(p.Line, p.Column, p.Position);
200+
return result;
201+
case XbnfParser.subexpression:
202+
result = _ParseExpression(p.Children[1]);
203+
result.SetLocation(p.Line, p.Column, p.Position);
204+
return result;
205+
case XbnfParser.literal:
206+
var pc = ParseContext.Create(p.Value);
207+
result = new XbnfLiteralExpression(pc.ParseJsonString());
208+
result.SetLocation(p.Line, p.Column, p.Position);
209+
return result;
210+
case XbnfParser.regex:
211+
pc = ParseContext.Create(p.Value);
212+
pc.EnsureStarted();
213+
pc.Advance();
214+
pc.TryReadUntil('\'', '\\', false);
215+
result = new XbnfRegexExpression(pc.GetCapture());
216+
result.SetLocation(p.Line, p.Column, p.Position);
217+
return result;
218+
case XbnfParser.identifier:
219+
result = new XbnfRefExpression(p.Value);
220+
result.SetLocation(p.Line, p.Column, p.Position);
221+
return result;
222+
default:
223+
throw new Exception("Error in parser implementation");
224+
}
225+
}
226+
static XbnfProduction _ParseProduction(ParseNode p)
227+
{
228+
var result = new XbnfProduction();
229+
result.SetLocation(p.Line, p.Column, p.Position);
230+
result.Name = p.Children[0].Value;
231+
var apn = ParseNode.SelectFirst(p.Children, XbnfParser.attributes);
232+
if (null != apn)
233+
{
234+
foreach (var ap in ParseNode.Select(apn.Children, XbnfParser.attribute))
235+
result.Attributes.Add(_ParseAttribute(ap));
236+
}
237+
var pexp = ParseNode.SelectFirst(p.Children, XbnfParser.orExpression);
238+
if (null != pexp)
239+
{
240+
result.Expression = _ParseExpression(pexp);
241+
}
242+
return result;
243+
}
244+
public static IList<XbnfMessage> TryReadFrom(string filename, out XbnfDocument result)
245+
=> _TryParse(new FileReaderEnumerable(filename), filename, out result);
246+
public static IList<XbnfMessage> TryReadFromUrl(string url, out XbnfDocument result)
247+
=> _TryParse(new UrlReaderEnumerable(url), url, out result);
248+
public static IList<XbnfMessage> TryReadFrom(TextReader reader, out XbnfDocument result)
249+
=> _TryParse(TextReaderEnumerable.FromReader(reader), null, out result);
250+
public static IList<XbnfMessage> TryParse(IEnumerable<char> input, out XbnfDocument result)
251+
=> _TryParse(input, null, out result);
252+
static IList<XbnfMessage> _TryParse(IEnumerable<char> input,string filename,out XbnfDocument result)
253+
{
254+
var msgs = new List<XbnfMessage>();
255+
var parser = new XbnfParser(new XbnfTokenizer(input));
256+
var pt = parser.ParseSubtree();
257+
var hasErrors = false;
258+
foreach (var pn in ParseNode.Select(pt.FillDescendantsAndSelf(), "#ERROR"))
259+
{
260+
hasErrors = true;
261+
msgs.Add(new XbnfMessage(ErrorLevel.Error, -1, "Syntax error: " + pn.Value, pn.Line, pn.Column, pn.Position, filename));
262+
}
263+
result = null;
264+
if (!hasErrors)
265+
{
266+
var doc = new XbnfDocument();
267+
if (!string.IsNullOrEmpty(filename))
268+
doc.SetFilename(filename);
269+
foreach (var pc in pt.Children)
270+
{
271+
doc.Productions.Add(_ParseProduction(pc));
272+
}
273+
result = doc;
132274
}
275+
return msgs;
133276
}
277+
134278
#region Value semantics
135279
public bool Equals(XbnfDocument rhs)
136280
{

xbnf/XbnfOrExpression.cs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,13 @@ public XbnfOrExpression(XbnfExpression left, params XbnfExpression[] right)
1414
var r = right[i];
1515
if (null == Right)
1616
Right = r;
17-
else
18-
{
19-
var c = new XbnfOrExpression();
20-
c.Left = Left;
21-
c.Right = Right;
22-
Right = null;
23-
Left = c;
24-
}
17+
18+
var c = new XbnfOrExpression();
19+
c.Left = Left;
20+
c.Right = Right;
21+
Right = null;
22+
Left = c;
23+
2524
}
2625
}
2726
public XbnfOrExpression()

0 commit comments

Comments
 (0)