ln.lexer/SharpLexer/match/CharacterGroup.cs

204 lines
3.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using lexer.buffer;
using System.Threading;
using System.Runtime.Remoting.Messaging;
using System.Text;
namespace lexer.match
{
public class CharacterGroup : Matchable
{
struct chinterval
{
public char first;
public char last;
public chinterval(char first, char last)
{
this.first = first;
this.last = last;
}
public bool Match(char ch)
{
return (ch >= first) && (ch <= last);
}
public override string ToString()
{
return string.Format("[chinterval min=0x{0:X4} max=0x{1:X4}]", (int)this.first, (int)this.last);
}
}
List<char> includeCharacters = new List<char>();
List<chinterval> includeIntervals = new List<chinterval>();
List<char> excludeCharacters = new List<char>();
List<chinterval> excludeIntervals = new List<chinterval>();
public CharacterGroup(CharacterBuffer chbuffer)
{
if (chbuffer.Current != '[')
{
throw new FormatException("CharacterGroup Definition must start with '['");
}
chbuffer.MoveNext();
char[] idef = chbuffer.findUnescaped(new char[] { ']', '/' });
char[] edef = null;
if (chbuffer.Last == '/')
{
edef = chbuffer.findUnescaped(']');
}
#if DEBUG
Console.WriteLine("CharacterGroup: include = {0}", new String(idef));
Console.WriteLine("CharacterGroup: exclude = {0}", new String(edef));
#endif
parseComponents(includeCharacters, includeIntervals, idef);
if (edef != null)
{
parseComponents(excludeCharacters, excludeIntervals, edef);
}
}
private void parseComponents(List<char> cList, List<chinterval> iList, char[] def)
{
DefinitionReader dr = new DefinitionReader(def);
while (dr.Current != DefinitionReader.OP_EOB)
{
if (dr.Current == DefinitionReader.OP_INTERVAL)
{
char min = (char)0;
char max = (char)0xffff;
if (cList.Count > 0)
{
min = cList.Last();
cList.RemoveAt(cList.Count - 1);
}
dr.MoveNext();
if (dr.Current != DefinitionReader.OP_EOB)
{
max = (char)dr.Current;
}
iList.Add(new chinterval(min, max));
}
else
{
cList.Add((char)dr.Current);
}
dr.MoveNext();
}
}
public bool Match(char ch)
{
foreach (chinterval i in excludeIntervals)
{
if (i.Match(ch))
{
return false;
}
}
foreach (char ec in excludeCharacters)
{
if (ec == ch)
{
return false;
}
}
foreach (chinterval i in includeIntervals)
{
if (i.Match(ch))
{
return true;
}
}
foreach (char ic in includeCharacters)
{
if (ic == ch)
{
return true;
}
}
return false;
}
public override MatchedPart[] Match(CharacterBuffer chbuffer)
{
if (!chbuffer.EndOfBuffer && Match(chbuffer.Current))
{
return new MatchedPart[] { new MatchedPart(this, new char[] { chbuffer.Current }) };
}
return null;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("[");
foreach (char ch in includeCharacters)
{
if (ch <= 0x20)
{
sb.AppendFormat("\\0x{0:X4}", (int)ch);
}
else
{
sb.Append(ch);
}
}
foreach (chinterval chi in includeIntervals)
{
if (chi.first <= 0x20)
{
sb.AppendFormat("\\0x{0:X4}", (int)chi.first);
}
else
{
sb.Append(chi.first);
}
sb.Append("..");
if (chi.last <= 0x20)
{
sb.AppendFormat("\\0x{0:X4}", (int)chi.last);
}
else
{
sb.Append(chi.last);
}
}
if ((excludeIntervals.Count > 0) || (excludeCharacters.Count > 0))
{
sb.Append("/");
foreach (char ch in includeCharacters)
{
if (ch <= 0x20)
{
sb.AppendFormat("\\{0:X4}", (int)ch);
}
else
{
sb.Append(ch);
}
}
}
sb.Append("]");
return sb.ToString();
}
}
}