182 lines
3.6 KiB
C#
182 lines
3.6 KiB
C#
using System;
|
|
using System.Xml;
|
|
using System.Collections.Generic;
|
|
using lexer.match;
|
|
using lexer.buffer;
|
|
namespace lexer
|
|
{
|
|
public class Grammar
|
|
{
|
|
Dictionary<String, Sequence> sequences = new Dictionary<string, Sequence>();
|
|
|
|
public Grammar(){
|
|
}
|
|
|
|
public Grammar(String filename)
|
|
{
|
|
Load(filename);
|
|
}
|
|
|
|
public Grammar(XmlDocument xml)
|
|
{
|
|
Load(xml);
|
|
}
|
|
|
|
public void Load(String filename)
|
|
{
|
|
XmlDocument xml = new XmlDocument();
|
|
xml.Load(filename);
|
|
Load(xml);
|
|
}
|
|
|
|
public void Load(XmlDocument xml)
|
|
{
|
|
XmlNodeList tokens = xml.SelectNodes("/Grammar/Tokens/Token");
|
|
foreach (XmlNode _ntoken in tokens)
|
|
{
|
|
XmlElement ntoken = (XmlElement)_ntoken;
|
|
Console.WriteLine("Loading Token: {0}", ntoken.Attributes["name"].Value);
|
|
|
|
CharacterBuffer chb = new CharacterBuffer(ntoken.InnerText);
|
|
Sequence sequence = parseSequence(chb, ntoken.Attributes["name"].Value);
|
|
|
|
sequence.Grouping = ntoken.HasAttribute("grouping");
|
|
sequence.Notice = ntoken.HasAttribute("notice");
|
|
|
|
this.sequences.Add(ntoken.Attributes["name"].Value, sequence);
|
|
}
|
|
}
|
|
|
|
public Sequence getSequence(String name)
|
|
{
|
|
return this.sequences[name];
|
|
}
|
|
|
|
|
|
public Sequence parseSequence(CharacterBuffer chbuffer, String name = null)
|
|
{
|
|
Sequence sequence = new Sequence(name);
|
|
int min, max;
|
|
|
|
while (!chbuffer.EndOfBuffer)
|
|
{
|
|
parseWhiteSpace(chbuffer);
|
|
if (chbuffer.EndOfBuffer)
|
|
break;
|
|
|
|
min = 1;
|
|
max = 1;
|
|
|
|
if (chbuffer.Current == '[')
|
|
{
|
|
|
|
CharacterGroup cg = new CharacterGroup(chbuffer);
|
|
parseMinMax(chbuffer, ref min, ref max);
|
|
|
|
Expression e = new Expression(cg, min, max);
|
|
sequence.addMatchable(e);
|
|
|
|
}
|
|
else if (chbuffer.Current == '"')
|
|
{
|
|
CharacterSequence cs = new CharacterSequence(chbuffer);
|
|
parseMinMax(chbuffer, ref min, ref max);
|
|
|
|
Expression e = new Expression(cs, min, max);
|
|
sequence.addMatchable(e);
|
|
|
|
}
|
|
else if (chbuffer.Current == '(')
|
|
{
|
|
|
|
chbuffer.MoveNext();
|
|
Sequence s = parseSequence(chbuffer);
|
|
parseMinMax(chbuffer, ref min, ref max);
|
|
|
|
Expression e = new Expression(s, min, max);
|
|
sequence.addMatchable(e);
|
|
|
|
}
|
|
else if (chbuffer.Current == '|')
|
|
{
|
|
|
|
Alternative alt = new Alternative();
|
|
alt.addMatchable(sequence);
|
|
chbuffer.MoveNext();
|
|
alt.addMatchable(parseSequence(chbuffer));
|
|
|
|
return alt;
|
|
}
|
|
else if (chbuffer.Current == ')')
|
|
{
|
|
|
|
chbuffer.MoveNext();
|
|
|
|
return sequence;
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
char[] sym = chbuffer.findSymbol();
|
|
Matchable m = Matchable.getNamedMatchable(sym);
|
|
if (m == null){
|
|
m = new Matchable.DeferredMatchable(sym);
|
|
}
|
|
parseMinMax(chbuffer, ref min, ref max);
|
|
|
|
Expression e = new Expression(m, min, max);
|
|
sequence.addMatchable(e);
|
|
}
|
|
|
|
}
|
|
return sequence;
|
|
}
|
|
|
|
public void parseWhiteSpace(CharacterBuffer chbuffer)
|
|
{
|
|
while (chbuffer.Current <= 0x20)
|
|
{
|
|
chbuffer.MoveNext();
|
|
}
|
|
}
|
|
|
|
public void parseMinMax(CharacterBuffer chbuffer, ref int min,ref int max){
|
|
|
|
if (chbuffer.Current == '{'){
|
|
chbuffer.MoveNext();
|
|
char[] def = chbuffer.find('}');
|
|
|
|
if (def.Length > 0)
|
|
{
|
|
int pcomma = -1;
|
|
|
|
while ((++pcomma < def.Length) && (def[pcomma] != ',')) { }
|
|
|
|
if (pcomma == 0)
|
|
{
|
|
min = 0;
|
|
} else {
|
|
min = int.Parse(new String(def, 0, pcomma));
|
|
}
|
|
|
|
if (pcomma == def.Length - 1)
|
|
{
|
|
max = int.MaxValue;
|
|
} else if (pcomma == def.Length){
|
|
max = min;
|
|
} else {
|
|
pcomma++;
|
|
max = int.Parse(new String(def, pcomma, def.Length - pcomma));
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
min = 1;
|
|
max = 1;
|
|
}
|
|
}
|
|
}
|