| /*Author:Martin.Holzherr;Date:20080922;Context:"PEG Support for C#";Licence:CPOL |
| * <<History>> |
| * 20080922;V1.0 created |
| * 20080929;UTF16BE;Added UTF16BE read support to <<FileLoader.LoadFile(out string src)>> |
| * <</History>> |
| */ |
| using System.Collections.Generic; |
| using System.Linq; |
| using System.IO; |
| using System.Diagnostics; |
| using System.Text; |
| using System; |
| namespace Peg.Base |
| { |
| #region Input File Support |
| public enum EncodingClass { unicode, utf8, binary, ascii }; |
| public enum UnicodeDetection { notApplicable, BOM, FirstCharIsAscii }; |
| public class FileLoader |
| { |
| public enum FileEncoding { none, ascii, binary, utf8, unicode, utf16be, utf16le, utf32le, utf32be, uniCodeBOM }; |
| public FileLoader(EncodingClass encodingClass, UnicodeDetection detection, string path) |
| { |
| encoding_ = GetEncoding(encodingClass, detection, path); |
| path_ = path; |
| } |
| public bool IsBinaryFile() |
| { |
| return encoding_ == FileEncoding.binary; |
| } |
| public bool LoadFile(out byte[] src) |
| { |
| src = null; |
| if (!IsBinaryFile()) return false; |
| using (BinaryReader brdr = new BinaryReader(File.Open(path_, FileMode.Open,FileAccess.Read))) |
| { |
| src = brdr.ReadBytes((int)brdr.BaseStream.Length); |
| return true; |
| } |
| } |
| public bool LoadFile(out string src) |
| { |
| src = null; |
| Encoding textEncoding = FileEncodingToTextEncoding(); |
| if (textEncoding == null) |
| { |
| if (encoding_ == FileEncoding.binary) return false; |
| using (StreamReader rd = new StreamReader(path_, true)) |
| { |
| src = rd.ReadToEnd(); |
| return true; |
| } |
| } |
| else |
| { |
| if (encoding_ == FileEncoding.utf16be)//UTF16BE |
| { |
| using (BinaryReader brdr = new BinaryReader(File.Open(path_, FileMode.Open, FileAccess.Read))) |
| { |
| byte[] bytes = brdr.ReadBytes((int)brdr.BaseStream.Length); |
| StringBuilder s = new StringBuilder(); |
| for (int i = 0; i < bytes.Length; i += 2) |
| { |
| char c = (char)(bytes[i] << 8 | bytes[i + 1]); |
| s.Append(c); |
| } |
| src = s.ToString(); |
| return true; |
| } |
| } |
| else |
| { |
| using (StreamReader rd = new StreamReader(path_, textEncoding)) |
| { |
| src = rd.ReadToEnd(); |
| return true; |
| } |
| } |
| } |
| |
| } |
| Encoding FileEncodingToTextEncoding() |
| { |
| switch (encoding_) |
| { |
| case FileEncoding.utf8: return new UTF8Encoding(); |
| case FileEncoding.utf32be: |
| case FileEncoding.utf32le: return new UTF32Encoding(); |
| case FileEncoding.unicode: |
| case FileEncoding.utf16be: |
| case FileEncoding.utf16le: return new UnicodeEncoding(); |
| case FileEncoding.ascii: return new ASCIIEncoding(); |
| case FileEncoding.binary: |
| case FileEncoding.uniCodeBOM: return null; |
| default: Debug.Assert(false); |
| return null; |
| |
| } |
| } |
| static FileEncoding DetermineUnicodeWhenFirstCharIsAscii(string path) |
| { |
| using (BinaryReader br = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read))) |
| { |
| byte[] startBytes = br.ReadBytes(4); |
| if (startBytes.Length == 0) return FileEncoding.none; |
| if (startBytes.Length == 1 || startBytes.Length == 3) return FileEncoding.utf8; |
| if (startBytes.Length == 2 && startBytes[0] != 0) return FileEncoding.utf16le; |
| if (startBytes.Length == 2 && startBytes[0] == 0) return FileEncoding.utf16be; |
| if (startBytes[0] == 0 && startBytes[1] == 0) return FileEncoding.utf32be; |
| if (startBytes[0] == 0 && startBytes[1] != 0) return FileEncoding.utf16be; |
| if (startBytes[0] != 0 && startBytes[1] == 0) return FileEncoding.utf16le; |
| return FileEncoding.utf8; |
| } |
| } |
| FileEncoding GetEncoding(EncodingClass encodingClass, UnicodeDetection detection, string path) |
| { |
| switch (encodingClass) |
| { |
| case EncodingClass.ascii: return FileEncoding.ascii; |
| case EncodingClass.unicode: |
| { |
| if (detection == UnicodeDetection.FirstCharIsAscii) |
| { |
| return DetermineUnicodeWhenFirstCharIsAscii(path); |
| } |
| else if (detection == UnicodeDetection.BOM) |
| { |
| return FileEncoding.uniCodeBOM; |
| } |
| else return FileEncoding.unicode; |
| } |
| case EncodingClass.utf8: return FileEncoding.utf8; |
| case EncodingClass.binary: return FileEncoding.binary; |
| } |
| return FileEncoding.none; |
| } |
| string path_; |
| public readonly FileEncoding encoding_; |
| } |
| #endregion Input File Support |
| #region Error handling |
| public class PegException : System.Exception |
| { |
| public PegException() |
| : base("Fatal parsing error ocurred") |
| { |
| } |
| } |
| public struct PegError |
| { |
| internal SortedList<int, int> lineStarts; |
| void AddLineStarts(string s, int first, int last, ref int lineNo, out int colNo) |
| { |
| colNo = 2; |
| for (int i = first + 1; i <= last; ++i, ++colNo) |
| { |
| if (s[i - 1] == '\n') |
| { |
| lineStarts[i] = ++lineNo; |
| colNo = 1; |
| } |
| } |
| --colNo; |
| } |
| public void GetLineAndCol(string s, int pos, out int lineNo, out int colNo) |
| { |
| for (int i = lineStarts.Count(); i > 0; --i) |
| { |
| KeyValuePair<int, int> curLs = lineStarts.ElementAt(i - 1); |
| if (curLs.Key == pos) |
| { |
| lineNo = curLs.Value; |
| colNo = 1; |
| return; |
| } |
| if (curLs.Key < pos) |
| { |
| lineNo = curLs.Value; |
| AddLineStarts(s, curLs.Key, pos, ref lineNo, out colNo); |
| return; |
| } |
| } |
| lineNo = 1; |
| AddLineStarts(s, 0, pos, ref lineNo, out colNo); |
| } |
| } |
| #endregion Error handling |
| #region Syntax/Parse-Tree related classes |
| public enum ESpecialNodes { eFatal = -10001, eAnonymNTNode = -1000, eAnonymASTNode = -1001, eAnonymousNode = -100 } |
| public enum ECreatorPhase { eCreate, eCreationComplete, eCreateAndComplete } |
| public struct PegBegEnd//indices into the source string |
| { |
| public int Length |
| { |
| get { return posEnd_ - posBeg_; } |
| } |
| public string GetAsString(string src) |
| { |
| Debug.Assert(src.Length >= posEnd_); |
| return src.Substring(posBeg_, Length); |
| } |
| public int posBeg_; |
| public int posEnd_; |
| } |
| public class PegNode : ICloneable |
| { |
| #region Constructors |
| public PegNode(PegNode parent, int id, PegBegEnd match, PegNode child, PegNode next) |
| { |
| parent_ = parent; id_ = id; child_ = child; next_ = next; |
| match_ = match; |
| } |
| public PegNode(PegNode parent, int id, PegBegEnd match, PegNode child) |
| : this(parent, id, match, child, null) |
| { |
| } |
| public PegNode(PegNode parent, int id, PegBegEnd match) |
| : this(parent, id, match, null, null) |
| { } |
| public PegNode(PegNode parent, int id) |
| : this(parent, id, new PegBegEnd(), null, null) |
| { |
| } |
| #endregion Constructors |
| #region Public Members |
| public virtual string GetAsString(string s) |
| { |
| return match_.GetAsString(s); |
| } |
| public virtual PegNode Clone() |
| { |
| PegNode clone= new PegNode(parent_, id_, match_); |
| CloneSubTrees(clone); |
| return clone; |
| } |
| #endregion Public Members |
| #region Protected Members |
| protected void CloneSubTrees(PegNode clone) |
| { |
| PegNode child = null, next = null; |
| if (child_ != null) |
| { |
| child = child_.Clone(); |
| child.parent_ = clone; |
| } |
| if (next_ != null) |
| { |
| next = next_.Clone(); |
| next.parent_ = clone; |
| } |
| clone.child_ = child; |
| clone.next_ = next; |
| } |
| #endregion Protected Members |
| #region Data Members |
| public int id_; |
| public PegNode parent_, child_, next_; |
| public PegBegEnd match_; |
| #endregion Data Members |
| |
| #region ICloneable Members |
| |
| object ICloneable.Clone() |
| { |
| return Clone(); |
| } |
| |
| #endregion |
| } |
| internal struct PegTree |
| { |
| internal enum AddPolicy { eAddAsChild, eAddAsSibling }; |
| internal PegNode root_; |
| internal PegNode cur_; |
| internal AddPolicy addPolicy; |
| } |
| public abstract class PrintNode |
| { |
| public abstract int LenMaxLine(); |
| public abstract bool IsLeaf(PegNode p); |
| public virtual bool IsSkip(PegNode p) { return false; } |
| public abstract void PrintNodeBeg(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel); |
| public abstract void PrintNodeEnd(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel); |
| public abstract int LenNodeBeg(PegNode p); |
| public abstract int LenNodeEnd(PegNode p); |
| public abstract void PrintLeaf(PegNode p, ref int nOffsetLineBeg, bool bAlignVertical); |
| public abstract int LenLeaf(PegNode p); |
| public abstract int LenDistNext(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel); |
| public abstract void PrintDistNext(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel); |
| } |
| public class TreePrint : PrintNode |
| { |
| #region Data Members |
| public delegate string GetNodeName(PegNode node); |
| string src_; |
| TextWriter treeOut_; |
| int nMaxLineLen_; |
| bool bVerbose_; |
| GetNodeName GetNodeName_; |
| #endregion Data Members |
| #region Methods |
| public TreePrint(TextWriter treeOut, string src, int nMaxLineLen, GetNodeName GetNodeName, bool bVerbose) |
| { |
| treeOut_ = treeOut; |
| nMaxLineLen_ = nMaxLineLen; |
| bVerbose_ = bVerbose; |
| GetNodeName_ = GetNodeName; |
| src_ = src; |
| } |
| |
| public void PrintTree(PegNode parent, int nOffsetLineBeg, int nLevel) |
| { |
| if (IsLeaf(parent)) |
| { |
| PrintLeaf(parent, ref nOffsetLineBeg, false); |
| treeOut_.Flush(); |
| return; |
| } |
| bool bAlignVertical = |
| DetermineLineLength(parent, nOffsetLineBeg) > LenMaxLine(); |
| PrintNodeBeg(parent, bAlignVertical, ref nOffsetLineBeg, nLevel); |
| int nOffset = nOffsetLineBeg; |
| for (PegNode p = parent.child_; p != null; p = p.next_) |
| { |
| if (IsSkip(p)) continue; |
| |
| if (IsLeaf(p)) |
| { |
| PrintLeaf(p, ref nOffsetLineBeg, bAlignVertical); |
| } |
| else |
| { |
| PrintTree(p, nOffsetLineBeg, nLevel + 1); |
| } |
| if (bAlignVertical) |
| { |
| nOffsetLineBeg = nOffset; |
| } |
| while (p.next_ != null && IsSkip(p.next_)) p = p.next_; |
| |
| if (p.next_ != null) |
| { |
| PrintDistNext(p, bAlignVertical, ref nOffsetLineBeg, nLevel); |
| } |
| } |
| PrintNodeEnd(parent, bAlignVertical, ref nOffsetLineBeg, nLevel); |
| treeOut_.Flush(); |
| } |
| int DetermineLineLength(PegNode parent, int nOffsetLineBeg) |
| { |
| int nLen = LenNodeBeg(parent); |
| PegNode p; |
| for (p = parent.child_; p != null; p = p.next_) |
| { |
| if (IsSkip(p)) continue; |
| if (IsLeaf(p)) |
| { |
| nLen += LenLeaf(p); |
| } |
| else |
| { |
| nLen += DetermineLineLength(p, nOffsetLineBeg); |
| } |
| if (nLen + nOffsetLineBeg > LenMaxLine()) |
| { |
| return nLen + nOffsetLineBeg; |
| } |
| } |
| nLen += LenNodeEnd(p); |
| return nLen; |
| } |
| public override int LenMaxLine() { return nMaxLineLen_; } |
| public override void |
| PrintNodeBeg(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel) |
| { |
| PrintIdAsName(p); |
| treeOut_.Write("<"); |
| if (bAlignVertical) |
| { |
| treeOut_.WriteLine(); |
| treeOut_.Write(new string(' ', nOffsetLineBeg += 2)); |
| } |
| else |
| { |
| ++nOffsetLineBeg; |
| } |
| } |
| public override void |
| PrintNodeEnd(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel) |
| { |
| if (bAlignVertical) |
| { |
| treeOut_.WriteLine(); |
| treeOut_.Write(new string(' ', nOffsetLineBeg -= 2)); |
| } |
| treeOut_.Write('>'); |
| if (!bAlignVertical) |
| { |
| ++nOffsetLineBeg; |
| } |
| } |
| public override int LenNodeBeg(PegNode p) { return LenIdAsName(p) + 1; } |
| public override int LenNodeEnd(PegNode p) { return 1; } |
| public override void PrintLeaf(PegNode p, ref int nOffsetLineBeg, bool bAlignVertical) |
| { |
| if (bVerbose_) |
| { |
| PrintIdAsName(p); |
| treeOut_.Write('<'); |
| } |
| int len = p.match_.posEnd_ - p.match_.posBeg_; |
| treeOut_.Write("'"); |
| if (len > 0) |
| { |
| treeOut_.Write(src_.Substring(p.match_.posBeg_, p.match_.posEnd_ - p.match_.posBeg_)); |
| } |
| treeOut_.Write("'"); |
| if (bVerbose_) treeOut_.Write('>'); |
| } |
| public override int LenLeaf(PegNode p) |
| { |
| int nLen = p.match_.posEnd_ - p.match_.posBeg_ + 2; |
| if (bVerbose_) nLen += LenIdAsName(p) + 2; |
| return nLen; |
| } |
| public override bool IsLeaf(PegNode p) |
| { |
| return p.child_ == null; |
| } |
| |
| public override void |
| PrintDistNext(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel) |
| { |
| if (bAlignVertical) |
| { |
| treeOut_.WriteLine(); |
| treeOut_.Write(new string(' ', nOffsetLineBeg)); |
| } |
| else |
| { |
| treeOut_.Write(' '); |
| ++nOffsetLineBeg; |
| } |
| } |
| |
| public override int |
| LenDistNext(PegNode p, bool bAlignVertical, ref int nOffsetLineBeg, int nLevel) |
| { |
| return 1; |
| } |
| int LenIdAsName(PegNode p) |
| { |
| string name = GetNodeName_(p); |
| return name.Length; |
| } |
| void PrintIdAsName(PegNode p) |
| { |
| string name = GetNodeName_(p); |
| treeOut_.Write(name); |
| } |
| #endregion Methods |
| } |
| #endregion Syntax/Parse-Tree related classes |
| #region Parsers |
| public abstract class PegBaseParser |
| { |
| #region Data Types |
| public delegate bool Matcher(); |
| public delegate PegNode Creator(ECreatorPhase ePhase, PegNode parentOrCreated, int id); |
| #endregion Data Types |
| #region Data members |
| protected int srcLen_; |
| protected int pos_; |
| protected bool bMute_; |
| protected TextWriter errOut_; |
| protected Creator nodeCreator_; |
| protected int maxpos_; |
| PegTree tree; |
| #endregion Data members |
| public virtual string GetRuleNameFromId(int id) |
| {//normally overridden |
| switch (id) |
| { |
| case (int)ESpecialNodes.eFatal: return "FATAL"; |
| case (int)ESpecialNodes.eAnonymNTNode: return "Nonterminal"; |
| case (int)ESpecialNodes.eAnonymASTNode: return "ASTNode"; |
| case (int)ESpecialNodes.eAnonymousNode: return "Node"; |
| default: return id.ToString(); |
| } |
| } |
| public virtual void GetProperties(out EncodingClass encoding, out UnicodeDetection detection) |
| { |
| encoding = EncodingClass.ascii; |
| detection = UnicodeDetection.notApplicable; |
| } |
| public int GetMaximumPosition() |
| { |
| return maxpos_; |
| } |
| protected PegNode DefaultNodeCreator(ECreatorPhase phase, PegNode parentOrCreated, int id) |
| { |
| if (phase == ECreatorPhase.eCreate || phase == ECreatorPhase.eCreateAndComplete) |
| return new PegNode(parentOrCreated, id); |
| else |
| { |
| if (parentOrCreated.match_.posEnd_ > maxpos_) |
| maxpos_ = parentOrCreated.match_.posEnd_; |
| return null; |
| } |
| } |
| #region Constructors |
| public PegBaseParser(TextWriter errOut) |
| { |
| srcLen_ = pos_ = 0; |
| errOut_ = errOut; |
| nodeCreator_ = DefaultNodeCreator; |
| } |
| #endregion Constructors |
| #region Reinitialization, TextWriter access,Tree Access |
| public void Construct(TextWriter Fout) |
| { |
| srcLen_ = pos_ = 0; |
| bMute_ = false; |
| SetErrorDestination(Fout); |
| ResetTree(); |
| } |
| public void Rewind() { pos_ = 0; } |
| public void SetErrorDestination(TextWriter errOut) |
| { |
| errOut_ = errOut == null ? new StreamWriter(System.Console.OpenStandardError()) |
| : errOut; |
| } |
| #endregion Reinitialization, TextWriter access,Tree Access |
| #region Tree root access, Tree Node generation/display |
| public PegNode GetRoot() { return tree.root_; } |
| public void ResetTree() |
| { |
| tree.root_ = null; |
| tree.cur_ = null; |
| tree.addPolicy = PegTree.AddPolicy.eAddAsChild; |
| } |
| void AddTreeNode(int nId, PegTree.AddPolicy newAddPolicy, Creator createNode, ECreatorPhase ePhase) |
| { |
| if (bMute_) return; |
| if (tree.root_ == null) |
| { |
| tree.root_ = tree.cur_ = createNode(ePhase, tree.cur_, nId); |
| } |
| else if (tree.addPolicy == PegTree.AddPolicy.eAddAsChild) |
| { |
| tree.cur_ = tree.cur_.child_ = createNode(ePhase, tree.cur_, nId); |
| } |
| else |
| { |
| tree.cur_ = tree.cur_.next_ = createNode(ePhase, tree.cur_.parent_, nId); |
| } |
| tree.addPolicy = newAddPolicy; |
| } |
| void RestoreTree(PegNode prevCur, PegTree.AddPolicy prevPolicy) |
| { |
| if (bMute_) return; |
| if (prevCur == null) |
| { |
| tree.root_ = null; |
| } |
| else if (prevPolicy == PegTree.AddPolicy.eAddAsChild) |
| { |
| prevCur.child_ = null; |
| } |
| else |
| { |
| prevCur.next_ = null; |
| } |
| tree.cur_ = prevCur; |
| tree.addPolicy = prevPolicy; |
| } |
| public bool TreeChars(Matcher toMatch) |
| { |
| return TreeCharsWithId((int)ESpecialNodes.eAnonymousNode, toMatch); |
| } |
| public bool TreeChars(Creator nodeCreator, Matcher toMatch) |
| { |
| return TreeCharsWithId(nodeCreator, (int)ESpecialNodes.eAnonymousNode, toMatch); |
| } |
| public bool TreeCharsWithId(int nId, Matcher toMatch) |
| { |
| return TreeCharsWithId(nodeCreator_, nId, toMatch); |
| } |
| public bool TreeCharsWithId(Creator nodeCreator, int nId, Matcher toMatch) |
| { |
| int pos = pos_; |
| if (toMatch()) |
| { |
| if (!bMute_) |
| { |
| AddTreeNode(nId, PegTree.AddPolicy.eAddAsSibling, nodeCreator, ECreatorPhase.eCreateAndComplete); |
| tree.cur_.match_.posBeg_ = pos; |
| tree.cur_.match_.posEnd_ = pos_; |
| } |
| return true; |
| } |
| return false; |
| } |
| public bool TreeNT(int nRuleId, Matcher toMatch) |
| { |
| return TreeNT(nodeCreator_, nRuleId, toMatch); |
| } |
| public bool TreeNT(Creator nodeCreator, int nRuleId, Matcher toMatch) |
| { |
| if (bMute_) return toMatch(); |
| PegNode prevCur = tree.cur_, ruleNode; |
| PegTree.AddPolicy prevPolicy = tree.addPolicy; |
| int posBeg = pos_; |
| AddTreeNode(nRuleId, PegTree.AddPolicy.eAddAsChild, nodeCreator, ECreatorPhase.eCreate); |
| ruleNode = tree.cur_; |
| bool bMatches = toMatch(); |
| if (!bMatches) RestoreTree(prevCur, prevPolicy); |
| else |
| { |
| ruleNode.match_.posBeg_ = posBeg; |
| ruleNode.match_.posEnd_ = pos_; |
| tree.cur_ = ruleNode; |
| tree.addPolicy = PegTree.AddPolicy.eAddAsSibling; |
| nodeCreator(ECreatorPhase.eCreationComplete, ruleNode, nRuleId); |
| } |
| return bMatches; |
| } |
| public bool TreeAST(int nRuleId, Matcher toMatch) |
| { |
| return TreeAST(nodeCreator_, nRuleId, toMatch); |
| } |
| public bool TreeAST(Creator nodeCreator, int nRuleId, Matcher toMatch) |
| { |
| if (bMute_) return toMatch(); |
| bool bMatches = TreeNT(nodeCreator, nRuleId, toMatch); |
| if (bMatches) |
| { |
| if (tree.cur_.child_ != null && tree.cur_.child_.next_ == null && tree.cur_.parent_ != null) |
| { |
| if (tree.cur_.parent_.child_ == tree.cur_) |
| { |
| tree.cur_.parent_.child_ = tree.cur_.child_; |
| tree.cur_.child_.parent_ = tree.cur_.parent_; |
| tree.cur_ = tree.cur_.child_; |
| } |
| else |
| { |
| PegNode prev; |
| for (prev = tree.cur_.parent_.child_; prev != null && prev.next_ != tree.cur_; prev = prev.next_) |
| { |
| } |
| if (prev != null) |
| { |
| prev.next_ = tree.cur_.child_; |
| tree.cur_.child_.parent_ = tree.cur_.parent_; |
| tree.cur_ = tree.cur_.child_; |
| } |
| } |
| } |
| } |
| return bMatches; |
| } |
| public bool TreeNT(Matcher toMatch) |
| { |
| return TreeNT((int)ESpecialNodes.eAnonymNTNode, toMatch); |
| } |
| public bool TreeNT(Creator nodeCreator, Matcher toMatch) |
| { |
| return TreeNT(nodeCreator, (int)ESpecialNodes.eAnonymNTNode, toMatch); |
| } |
| public bool TreeAST(Matcher toMatch) |
| { |
| return TreeAST((int)ESpecialNodes.eAnonymASTNode, toMatch); |
| } |
| public bool TreeAST(Creator nodeCreator, Matcher toMatch) |
| { |
| return TreeAST(nodeCreator, (int)ESpecialNodes.eAnonymASTNode, toMatch); |
| } |
| public virtual string TreeNodeToString(PegNode node) |
| { |
| return GetRuleNameFromId(node.id_); |
| } |
| public void SetNodeCreator(Creator nodeCreator) |
| { |
| Debug.Assert(nodeCreator != null); |
| nodeCreator_ = nodeCreator; |
| } |
| #endregion Tree Node generation |
| #region PEG e1 e2 .. ; &e1 ; !e1 ; e? ; e* ; e+ ; e{a,b} ; . |
| public bool And(Matcher pegSequence) |
| { |
| PegNode prevCur = tree.cur_; |
| PegTree.AddPolicy prevPolicy = tree.addPolicy; |
| int pos0 = pos_; |
| bool bMatches = pegSequence(); |
| if (!bMatches) |
| { |
| pos_ = pos0; |
| RestoreTree(prevCur, prevPolicy); |
| } |
| return bMatches; |
| } |
| public bool Peek(Matcher toMatch) |
| { |
| int pos0 = pos_; |
| bool prevMute = bMute_; |
| bMute_ = true; |
| bool bMatches = toMatch(); |
| bMute_ = prevMute; |
| pos_ = pos0; |
| return bMatches; |
| } |
| public bool Not(Matcher toMatch) |
| { |
| int pos0 = pos_; |
| bool prevMute = bMute_; |
| bMute_ = true; |
| bool bMatches = toMatch(); |
| bMute_ = prevMute; |
| pos_ = pos0; |
| return !bMatches; |
| } |
| public bool PlusRepeat(Matcher toRepeat) |
| { |
| int i; |
| for (i = 0; ; ++i) |
| { |
| int pos0 = pos_; |
| if (!toRepeat()) |
| { |
| pos_ = pos0; |
| break; |
| } |
| } |
| return i > 0; |
| } |
| public bool OptRepeat(Matcher toRepeat) |
| { |
| for (; ; ) |
| { |
| int pos0 = pos_; |
| if (!toRepeat()) |
| { |
| pos_ = pos0; |
| return true; |
| } |
| } |
| } |
| public bool Option(Matcher toMatch) |
| { |
| int pos0 = pos_; |
| if (!toMatch()) pos_ = pos0; |
| return true; |
| } |
| public bool ForRepeat(int count, Matcher toRepeat) |
| { |
| PegNode prevCur = tree.cur_; |
| PegTree.AddPolicy prevPolicy = tree.addPolicy; |
| int pos0 = pos_; |
| int i; |
| for (i = 0; i < count; ++i) |
| { |
| if (!toRepeat()) |
| { |
| pos_ = pos0; |
| RestoreTree(prevCur, prevPolicy); |
| return false; |
| } |
| } |
| return true; |
| } |
| public bool ForRepeat(int lower, int upper, Matcher toRepeat) |
| { |
| PegNode prevCur = tree.cur_; |
| PegTree.AddPolicy prevPolicy = tree.addPolicy; |
| int pos0 = pos_; |
| int i; |
| for (i = 0; i < upper; ++i) |
| { |
| if (!toRepeat()) break; |
| } |
| if (i < lower) |
| { |
| pos_ = pos0; |
| RestoreTree(prevCur, prevPolicy); |
| return false; |
| } |
| return true; |
| } |
| public bool Any() |
| { |
| if (pos_ < srcLen_) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| #endregion PEG e1 e2 .. ; &e1 ; !e1 ; e? ; e* ; e+ ; e{a,b} ; . |
| } |
| public class PegByteParser : PegBaseParser |
| { |
| #region Data members |
| protected byte[] src_; |
| PegError errors; |
| #endregion Data members |
| |
| #region PEG optimizations |
| public sealed class BytesetData |
| { |
| public struct Range |
| { |
| public Range(byte low, byte high) { this.low = low; this.high = high; } |
| public byte low; |
| public byte high; |
| } |
| System.Collections.BitArray charSet_; |
| bool bNegated_; |
| public BytesetData(System.Collections.BitArray b) |
| : this(b, false) |
| { |
| } |
| public BytesetData(System.Collections.BitArray b, bool bNegated) |
| { |
| charSet_ = new System.Collections.BitArray(b); |
| bNegated_ = bNegated; |
| } |
| public BytesetData(Range[] r, byte[] c) |
| : this(r, c, false) |
| { |
| } |
| public BytesetData(Range[] r, byte[] c, bool bNegated) |
| { |
| int max = 0; |
| if (r != null) foreach (Range val in r) if (val.high > max) max = val.high; |
| if (c != null) foreach (int val in c) if (val > max) max = val; |
| charSet_ = new System.Collections.BitArray(max + 1, false); |
| if (r != null) |
| { |
| foreach (Range val in r) |
| { |
| for (int i = val.low; i <= val.high; ++i) |
| { |
| charSet_[i] = true; |
| } |
| } |
| } |
| if (c != null) foreach (int val in c) charSet_[val] = true; |
| bNegated_ = bNegated; |
| } |
| public bool Matches(byte c) |
| { |
| bool bMatches = c < charSet_.Length && charSet_[(int)c]; |
| if (bNegated_) return !bMatches; |
| else return bMatches; |
| } |
| } |
| /* public class BytesetData |
| { |
| public struct Range |
| { |
| public Range(byte low, byte high) { this.low = low; this.high = high; } |
| public byte low; |
| public byte high; |
| } |
| protected System.Collections.BitArray charSet_; |
| bool bNegated_; |
| public BytesetData(System.Collections.BitArray b, bool bNegated) |
| { |
| charSet_ = new System.Collections.BitArray(b); |
| bNegated_ = bNegated; |
| } |
| public BytesetData(byte[] c, bool bNegated) |
| { |
| int max = 0; |
| foreach (int val in c) if (val > max) max = val; |
| charSet_ = new System.Collections.BitArray(max + 1, false); |
| foreach (int val in c) charSet_[val] = true; |
| bNegated_ = bNegated; |
| } |
| public BytesetData(Range[] r, byte[] c, bool bNegated) |
| { |
| int max = 0; |
| foreach (Range val in r) if (val.high > max) max = val.high; |
| foreach (int val in c) if (val > max) max = val; |
| charSet_ = new System.Collections.BitArray(max + 1, false); |
| foreach (Range val in r) |
| { |
| for (int i = val.low; i <= val.high; ++i) |
| { |
| charSet_[i] = true; |
| } |
| } |
| foreach (int val in c) charSet_[val] = true; |
| } |
| |
| |
| public bool Matches(byte c) |
| { |
| bool bMatches = c < charSet_.Length && charSet_[(int)c]; |
| if (bNegated_) return !bMatches; |
| else return bMatches; |
| } |
| }*/ |
| #endregion PEG optimizations |
| #region Constructors |
| public PegByteParser() |
| : this(null) |
| { |
| } |
| public PegByteParser(byte[] src):base(null) |
| { |
| SetSource(src); |
| } |
| public PegByteParser(byte[] src, TextWriter errOut):base(errOut) |
| { |
| SetSource(src); |
| } |
| #endregion Constructors |
| #region Reinitialization, Source Code access, TextWriter access,Tree Access |
| public void Construct(byte[] src, TextWriter Fout) |
| { |
| base.Construct(Fout); |
| SetSource(src); |
| } |
| public void SetSource(byte[] src) |
| { |
| if (src == null) src = new byte[0]; |
| src_ = src; srcLen_ = src.Length; |
| errors.lineStarts = new SortedList<int, int>(); |
| errors.lineStarts[0] = 1; |
| } |
| public byte[] GetSource() { return src_; } |
| |
| #endregion Reinitialization, Source Code access, TextWriter access,Tree Access |
| #region Setting host variables |
| public bool Into(Matcher toMatch,out byte[] into) |
| { |
| int pos = pos_; |
| if (toMatch()) |
| { |
| int nLen = pos_ - pos; |
| into= new byte[nLen]; |
| for(int i=0;i<nLen;++i){ |
| into[i] = src_[i+pos]; |
| } |
| return true; |
| } |
| else |
| { |
| into = null; |
| return false; |
| } |
| } |
| public bool Into(Matcher toMatch,out PegBegEnd begEnd) |
| { |
| begEnd.posBeg_ = pos_; |
| bool bMatches = toMatch(); |
| begEnd.posEnd_ = pos_; |
| return bMatches; |
| } |
| public bool Into(Matcher toMatch,out int into) |
| { |
| byte[] s; |
| into = 0; |
| if (!Into(toMatch,out s)) return false; |
| into = 0; |
| for (int i = 0; i < s.Length; ++i) |
| { |
| into <<= 8; |
| into |= s[i]; |
| } |
| return true; |
| } |
| public bool Into(Matcher toMatch,out double into) |
| { |
| byte[] s; |
| into = 0.0; |
| if (!Into(toMatch,out s)) return false; |
| System.Text.Encoding encoding = System.Text.Encoding.UTF8; |
| string sAsString = encoding.GetString(s); |
| if (!System.Double.TryParse(sAsString, out into)) return false; |
| return true; |
| } |
| public bool BitsInto(int lowBitNo, int highBitNo,out int into) |
| { |
| if (pos_ < srcLen_) |
| { |
| into = (src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1); |
| ++pos_; |
| return true; |
| } |
| into = 0; |
| return false; |
| } |
| public bool BitsInto(int lowBitNo, int highBitNo, BytesetData toMatch, out int into) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte value = (byte)((src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1)); |
| ++pos_; |
| into = value; |
| return toMatch.Matches(value); |
| } |
| into = 0; |
| return false; |
| } |
| #endregion Setting host variables |
| #region Error handling |
| void LogOutMsg(string sErrKind, string sMsg) |
| { |
| errOut_.WriteLine("<{0}>{1}:{2}", pos_, sErrKind, sMsg); |
| errOut_.Flush(); |
| } |
| public virtual bool Fatal(string sMsg) |
| { |
| |
| LogOutMsg("FATAL", sMsg); |
| throw new PegException(); |
| } |
| public bool Warning(string sMsg) |
| { |
| LogOutMsg("WARNING", sMsg); |
| return true; |
| } |
| #endregion Error handling |
| #region PEG Bit level equivalents for PEG e1 ; &e1 ; !e1; e1:into ; |
| public bool Bits(int lowBitNo, int highBitNo, byte toMatch) |
| { |
| if (pos_ < srcLen_ && ((src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1)) == toMatch) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool Bits(int lowBitNo, int highBitNo,BytesetData toMatch) |
| { |
| if( pos_ < srcLen_ ) |
| { |
| byte value= (byte)((src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1)); |
| ++pos_; |
| return toMatch.Matches(value); |
| } |
| return false; |
| } |
| public bool PeekBits(int lowBitNo, int highBitNo, byte toMatch) |
| { |
| return pos_ < srcLen_ && ((src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1)) == toMatch; |
| } |
| public bool NotBits(int lowBitNo, int highBitNo, byte toMatch) |
| { |
| return !(pos_ < srcLen_ && ((src_[pos_] >> (lowBitNo - 1)) & ((1 << highBitNo) - 1)) == toMatch); |
| } |
| public bool IntoBits(int lowBitNo,int highBitNo,out int val) |
| { |
| return BitsInto(lowBitNo,highBitNo,out val); |
| } |
| public bool IntoBits(int lowBitNo, int highBitNo, BytesetData toMatch, out int val) |
| { |
| return BitsInto(lowBitNo, highBitNo, out val); |
| } |
| public bool Bit(int bitNo,byte toMatch) |
| { |
| if (pos_ < srcLen_ && ((src_[pos_]>>(bitNo-1))&1)==toMatch){ |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool PeekBit(int bitNo, byte toMatch) |
| { |
| return pos_ < srcLen_ && ((src_[pos_] >> (bitNo - 1)) & 1) == toMatch; |
| } |
| public bool NotBit(int bitNo, byte toMatch) |
| { |
| return !(pos_ < srcLen_ && ((src_[pos_] >> (bitNo - 1)) & 1) == toMatch); |
| } |
| #endregion PEG Bit level equivalents for PEG e1 ; &e1 ; !e1; e1:into ; |
| #region PEG '<Literal>' / '<Literal>'/i / [low1-high1,low2-high2..] / [<CharList>] |
| public bool Char(byte c1) |
| { |
| if (pos_ < srcLen_ && src_[pos_] == c1) |
| { ++pos_; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2) |
| { |
| if (pos_ + 1 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2) |
| { pos_ += 2; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3) |
| { |
| if (pos_ + 2 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3) |
| { pos_ += 3; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3, byte c4) |
| { |
| if (pos_ + 3 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4) |
| { pos_ += 4; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3, byte c4, byte c5) |
| { |
| if (pos_ + 4 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5) |
| { pos_ += 5; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3, byte c4, byte c5, byte c6) |
| { |
| if (pos_ + 5 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6) |
| { pos_ += 6; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3, byte c4, byte c5, byte c6, byte c7) |
| { |
| if (pos_ + 6 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6 |
| && src_[pos_ + 6] == c7) |
| { pos_ += 7; return true; } |
| return false; |
| } |
| public bool Char(byte c1, byte c2, byte c3, byte c4, byte c5, byte c6, byte c7, byte c8) |
| { |
| if (pos_ + 7 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6 |
| && src_[pos_ + 6] == c7 |
| && src_[pos_ + 7] == c8) |
| { pos_ += 8; return true; } |
| return false; |
| } |
| public bool Char(byte[] s) |
| { |
| int sLength = s.Length; |
| if (pos_ + sLength > srcLen_) return false; |
| for (int i = 0; i < sLength; ++i) |
| { |
| if (s[i] != src_[pos_ + i]) return false; |
| } |
| pos_ += sLength; |
| return true; |
| } |
| public static byte ToUpper(byte c) |
| { |
| if (c >= 97 && c <= 122) return (byte)(c - 32); else return c; |
| } |
| public bool IChar(byte c1) |
| { |
| if (pos_ < srcLen_ && ToUpper(src_[pos_]) == c1) |
| { ++pos_; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2) |
| { |
| if (pos_ + 1 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2)) |
| { pos_ += 2; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2, byte c3) |
| { |
| if (pos_ + 2 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2) |
| && ToUpper(src_[pos_ + 2]) == ToUpper(c3)) |
| { pos_ += 3; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2, byte c3, byte c4) |
| { |
| if (pos_ + 3 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2) |
| && ToUpper(src_[pos_ + 2]) == ToUpper(c3) |
| && ToUpper(src_[pos_ + 3]) == ToUpper(c4)) |
| { pos_ += 4; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2, byte c3, byte c4, byte c5) |
| { |
| if (pos_ + 4 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2) |
| && ToUpper(src_[pos_ + 2]) == ToUpper(c3) |
| && ToUpper(src_[pos_ + 3]) == ToUpper(c4) |
| && ToUpper(src_[pos_ + 4]) == ToUpper(c5)) |
| { pos_ += 5; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2, byte c3, byte c4, byte c5, byte c6) |
| { |
| if (pos_ + 5 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2) |
| && ToUpper(src_[pos_ + 2]) == ToUpper(c3) |
| && ToUpper(src_[pos_ + 3]) == ToUpper(c4) |
| && ToUpper(src_[pos_ + 4]) == ToUpper(c5) |
| && ToUpper(src_[pos_ + 5]) == ToUpper(c6)) |
| { pos_ += 6; return true; } |
| return false; |
| } |
| public bool IChar(byte c1, byte c2, byte c3, byte c4, byte c5, byte c6, byte c7) |
| { |
| if (pos_ + 6 < srcLen_ |
| && ToUpper(src_[pos_]) == ToUpper(c1) |
| && ToUpper(src_[pos_ + 1]) == ToUpper(c2) |
| && ToUpper(src_[pos_ + 2]) == ToUpper(c3) |
| && ToUpper(src_[pos_ + 3]) == ToUpper(c4) |
| && ToUpper(src_[pos_ + 4]) == ToUpper(c5) |
| && ToUpper(src_[pos_ + 5]) == ToUpper(c6) |
| && ToUpper(src_[pos_ + 6]) == ToUpper(c7)) |
| { pos_ += 7; return true; } |
| return false; |
| } |
| public bool IChar(byte[] s) |
| { |
| int sLength = s.Length; |
| if (pos_ + sLength > srcLen_) return false; |
| for (int i = 0; i < sLength; ++i) |
| { |
| if (s[i] != ToUpper(src_[pos_ + i])) return false; |
| } |
| pos_ += sLength; |
| return true; |
| } |
| public bool In(byte c0, byte c1) |
| { |
| if (pos_ < srcLen_ |
| && src_[pos_] >= c0 && src_[pos_] <= c1) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool In(byte c0, byte c1, byte c2, byte c3) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(byte c0, byte c1, byte c2, byte c3, byte c4, byte c5) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3 |
| || c >= c4 && c <= c5) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(byte c0, byte c1, byte c2, byte c3, byte c4, byte c5, byte c6, byte c7) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3 |
| || c >= c4 && c <= c5 |
| || c >= c6 && c <= c7) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(byte[] s) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| for (int i = 0; i < s.Length - 1; i += 2) |
| { |
| if (c >= s[i] && c <= s[i + 1]) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| public bool NotIn(byte[] s) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| for (int i = 0; i < s.Length - 1; i += 2) |
| { |
| if ( c >= s[i] && c <= s[i + 1] ) return false; |
| } |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1) |
| { |
| if (pos_ < srcLen_ |
| && (src_[pos_] == c0 || src_[pos_] == c1)) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2, byte c3) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2, byte c3, byte c4) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2, byte c3, byte c4, byte c5) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2, byte c3, byte c4, byte c5, byte c6) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5 || c == c6) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte c0, byte c1, byte c2, byte c3, byte c4, byte c5, byte c6, byte c7) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5 || c == c6 || c == c7) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(byte[] s) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| for (int i = 0; i < s.Length; ++i) |
| { |
| if (c == s[i]) { ++pos_; return true; } |
| } |
| } |
| return false; |
| } |
| public bool NotOneOf(byte[] s) |
| { |
| if (pos_ < srcLen_) |
| { |
| byte c = src_[pos_]; |
| for (int i = 0; i < s.Length; ++i) |
| { |
| if (c == s[i]) { return false; } |
| } |
| return true; |
| } |
| return false; |
| } |
| public bool OneOf(BytesetData bset) |
| { |
| if(pos_ < srcLen_ && bset.Matches(src_[pos_])) |
| { |
| ++pos_; return true; |
| } |
| return false; |
| } |
| #endregion PEG '<Literal>' / '<Literal>'/i / [low1-high1,low2-high2..] / [<CharList>] |
| } |
| public class PegCharParser : PegBaseParser |
| { |
| #region Data members |
| protected string src_; |
| PegError errors; |
| #endregion Data members |
| #region PEG optimizations |
| public sealed class OptimizedCharset |
| { |
| public struct Range |
| { |
| public Range(char low, char high) { this.low = low; this.high = high; } |
| public char low; |
| public char high; |
| } |
| System.Collections.BitArray charSet_; |
| bool bNegated_; |
| public OptimizedCharset(System.Collections.BitArray b) |
| : this(b, false) |
| { |
| } |
| public OptimizedCharset(System.Collections.BitArray b, bool bNegated) |
| { |
| charSet_ = new System.Collections.BitArray(b); |
| bNegated_ = bNegated; |
| } |
| public OptimizedCharset(Range[] r, char[] c) |
| : this(r, c, false) |
| { |
| } |
| public OptimizedCharset(Range[] r, char[] c, bool bNegated) |
| { |
| int max = 0; |
| if (r != null) foreach (Range val in r) if (val.high > max) max = val.high; |
| if (c != null) foreach (int val in c) if (val > max) max = val; |
| charSet_ = new System.Collections.BitArray(max + 1, false); |
| if (r != null) |
| { |
| foreach (Range val in r) |
| { |
| for (int i = val.low; i <= val.high; ++i) |
| { |
| charSet_[i] = true; |
| } |
| } |
| } |
| if (c != null) foreach (int val in c) charSet_[val] = true; |
| bNegated_ = bNegated; |
| } |
| |
| |
| public bool Matches(char c) |
| { |
| bool bMatches = c < charSet_.Length && charSet_[(int)c]; |
| if (bNegated_) return !bMatches; |
| else return bMatches; |
| } |
| } |
| public sealed class OptimizedLiterals |
| { |
| internal class Trie |
| { |
| internal Trie(char cThis,int nIndex, string[] literals) |
| { |
| cThis_ = cThis; |
| char cMax = char.MinValue; |
| cMin_ = char.MaxValue; |
| HashSet<char> followChars = new HashSet<char>(); |
| |
| foreach (string literal in literals) |
| { |
| if (literal==null || nIndex > literal.Length ) continue; |
| if (nIndex == literal.Length) |
| { |
| bLitEnd_ = true; |
| continue; |
| } |
| char c = literal[nIndex]; |
| followChars.Add(c); |
| if ( c < cMin_) cMin_ = c; |
| if ( c > cMax) cMax = c; |
| } |
| if (followChars.Count == 0) |
| { |
| children_ = null; |
| } |
| else |
| { |
| children_ = new Trie[(cMax - cMin_) + 1]; |
| foreach (char c in followChars) |
| { |
| List<string> subLiterals = new List<string>(); |
| foreach (string s in literals) |
| { |
| if ( nIndex >= s.Length ) continue; |
| if (c == s[nIndex]) |
| { |
| subLiterals.Add(s); |
| } |
| } |
| children_[c - cMin_] = new Trie(c, nIndex + 1, subLiterals.ToArray()); |
| } |
| } |
| |
| } |
| internal char cThis_; //character stored in this node |
| internal bool bLitEnd_; //end of literal |
| |
| internal char cMin_; //first valid character in children |
| internal Trie[] children_; //contains the successor node of cThis_; |
| } |
| internal Trie literalsRoot; |
| public OptimizedLiterals(string[] litAlternatives) |
| { |
| literalsRoot = new Trie('\u0000', 0, litAlternatives); |
| } |
| } |
| #endregion PEG optimizations |
| #region Constructors |
| public PegCharParser():this("") |
| { |
| |
| |
| } |
| public PegCharParser(string src):base(null) |
| { |
| SetSource(src); |
| } |
| public PegCharParser(string src, TextWriter errOut):base(errOut) |
| { |
| SetSource(src); |
| nodeCreator_ = DefaultNodeCreator; |
| } |
| #endregion Constructors |
| #region Overrides |
| public override string TreeNodeToString(PegNode node) |
| { |
| string label = base.TreeNodeToString(node); |
| if (node.id_ == (int)ESpecialNodes.eAnonymousNode) |
| { |
| string value = node.GetAsString(src_); |
| if (value.Length < 32) label += " <" + value + ">"; |
| else label += " <" + value.Substring(0, 29) + "...>"; |
| } |
| return label; |
| } |
| #endregion Overrides |
| #region Reinitialization, Source Code access, TextWriter access,Tree Access |
| public void Construct(string src, TextWriter Fout) |
| { |
| base.Construct(Fout); |
| SetSource(src); |
| } |
| public void SetSource(string src) |
| { |
| if (src == null) src = ""; |
| src_ = src; srcLen_ = src.Length; pos_ = 0; |
| errors.lineStarts = new SortedList<int, int>(); |
| errors.lineStarts[0] = 1; |
| } |
| public string GetSource() { return src_; } |
| #endregion Reinitialization, Source Code access, TextWriter access,Tree Access |
| #region Setting host variables |
| public bool Into(Matcher toMatch,out string into) |
| { |
| int pos = pos_; |
| if (toMatch()) |
| { |
| into = src_.Substring(pos, pos_ - pos); |
| return true; |
| } |
| else |
| { |
| into = ""; |
| return false; |
| } |
| } |
| public bool Into(Matcher toMatch,out PegBegEnd begEnd) |
| { |
| begEnd.posBeg_ = pos_; |
| bool bMatches = toMatch(); |
| begEnd.posEnd_ = pos_; |
| return bMatches; |
| } |
| public bool Into(Matcher toMatch,out int into) |
| { |
| string s; |
| into = 0; |
| if (!Into(toMatch,out s)) return false; |
| if (!System.Int32.TryParse(s, out into)) return false; |
| return true; |
| } |
| public bool Into(Matcher toMatch,out double into) |
| { |
| string s; |
| into = 0.0; |
| if (!Into(toMatch,out s)) return false; |
| if (!System.Double.TryParse(s, out into)) return false; |
| return true; |
| } |
| #endregion Setting host variables |
| #region Error handling |
| void LogOutMsg(string sErrKind, string sMsg) |
| { |
| int lineNo, colNo; |
| errors.GetLineAndCol(src_, pos_, out lineNo, out colNo); |
| errOut_.WriteLine("<{0},{1},{2}>{3}:{4}", lineNo, colNo, maxpos_, sErrKind, sMsg); |
| errOut_.Flush(); |
| } |
| public virtual bool Fatal(string sMsg) |
| { |
| |
| LogOutMsg("FATAL", sMsg); |
| throw new PegException(); |
| //return false; |
| } |
| public bool Warning(string sMsg) |
| { |
| LogOutMsg("WARNING", sMsg); |
| return true; |
| } |
| #endregion Error handling |
| #region PEG optimized version of e* ; e+ |
| public bool OptRepeat(OptimizedCharset charset) |
| { |
| for (; pos_ < srcLen_ && charset.Matches(src_[pos_]); ++pos_) ; |
| return true; |
| } |
| public bool PlusRepeat(OptimizedCharset charset) |
| { |
| int pos0 = pos_; |
| for (; pos_ < srcLen_ && charset.Matches(src_[pos_]); ++pos_) ; |
| return pos_ > pos0; |
| } |
| #endregion PEG optimized version of e* ; e+ |
| #region PEG '<Literal>' / '<Literal>'/i / [low1-high1,low2-high2..] / [<CharList>] |
| public bool Char(char c1) |
| { |
| if (pos_ < srcLen_ && src_[pos_] == c1) |
| { ++pos_; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2) |
| { |
| if (pos_ + 1 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2) |
| { pos_ += 2; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3) |
| { |
| if (pos_ + 2 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3) |
| { pos_ += 3; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3, char c4) |
| { |
| if (pos_ + 3 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4) |
| { pos_ += 4; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3, char c4, char c5) |
| { |
| if (pos_ + 4 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5) |
| { pos_ += 5; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3, char c4, char c5, char c6) |
| { |
| if (pos_ + 5 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6) |
| { pos_ += 6; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3, char c4, char c5, char c6, char c7) |
| { |
| if (pos_ + 6 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6 |
| && src_[pos_ + 6] == c7) |
| { pos_ += 7; return true; } |
| return false; |
| } |
| public bool Char(char c1, char c2, char c3, char c4, char c5, char c6, char c7, char c8) |
| { |
| if (pos_ + 7 < srcLen_ |
| && src_[pos_] == c1 |
| && src_[pos_ + 1] == c2 |
| && src_[pos_ + 2] == c3 |
| && src_[pos_ + 3] == c4 |
| && src_[pos_ + 4] == c5 |
| && src_[pos_ + 5] == c6 |
| && src_[pos_ + 6] == c7 |
| && src_[pos_ + 7] == c8) |
| { pos_ += 8; return true; } |
| return false; |
| } |
| public bool Char(string s) |
| { |
| int sLength = s.Length; |
| if (pos_ + sLength > srcLen_) return false; |
| for (int i = 0; i < sLength; ++i) |
| { |
| if (s[i] != src_[pos_ + i]) return false; |
| } |
| pos_ += sLength; |
| return true; |
| } |
| public bool IChar(char c1) |
| { |
| if (pos_ < srcLen_ && System.Char.ToUpper(src_[pos_]) == c1) |
| { ++pos_; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2) |
| { |
| if (pos_ + 1 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2)) |
| { pos_ += 2; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2, char c3) |
| { |
| if (pos_ + 2 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2) |
| && System.Char.ToUpper(src_[pos_ + 2]) == System.Char.ToUpper(c3)) |
| { pos_ += 3; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2, char c3, char c4) |
| { |
| if (pos_ + 3 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2) |
| && System.Char.ToUpper(src_[pos_ + 2]) == System.Char.ToUpper(c3) |
| && System.Char.ToUpper(src_[pos_ + 3]) == System.Char.ToUpper(c4)) |
| { pos_ += 4; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2, char c3, char c4, char c5) |
| { |
| if (pos_ + 4 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2) |
| && System.Char.ToUpper(src_[pos_ + 2]) == System.Char.ToUpper(c3) |
| && System.Char.ToUpper(src_[pos_ + 3]) == System.Char.ToUpper(c4) |
| && System.Char.ToUpper(src_[pos_ + 4]) == System.Char.ToUpper(c5)) |
| { pos_ += 5; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2, char c3, char c4, char c5, char c6) |
| { |
| if (pos_ + 5 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2) |
| && System.Char.ToUpper(src_[pos_ + 2]) == System.Char.ToUpper(c3) |
| && System.Char.ToUpper(src_[pos_ + 3]) == System.Char.ToUpper(c4) |
| && System.Char.ToUpper(src_[pos_ + 4]) == System.Char.ToUpper(c5) |
| && System.Char.ToUpper(src_[pos_ + 5]) == System.Char.ToUpper(c6)) |
| { pos_ += 6; return true; } |
| return false; |
| } |
| public bool IChar(char c1, char c2, char c3, char c4, char c5, char c6, char c7) |
| { |
| if (pos_ + 6 < srcLen_ |
| && System.Char.ToUpper(src_[pos_]) == System.Char.ToUpper(c1) |
| && System.Char.ToUpper(src_[pos_ + 1]) == System.Char.ToUpper(c2) |
| && System.Char.ToUpper(src_[pos_ + 2]) == System.Char.ToUpper(c3) |
| && System.Char.ToUpper(src_[pos_ + 3]) == System.Char.ToUpper(c4) |
| && System.Char.ToUpper(src_[pos_ + 4]) == System.Char.ToUpper(c5) |
| && System.Char.ToUpper(src_[pos_ + 5]) == System.Char.ToUpper(c6) |
| && System.Char.ToUpper(src_[pos_ + 6]) == System.Char.ToUpper(c7)) |
| { pos_ += 7; return true; } |
| return false; |
| } |
| public bool IChar(string s) |
| { |
| int sLength = s.Length; |
| if (pos_ + sLength > srcLen_) return false; |
| for (int i = 0; i < sLength; ++i) |
| { |
| if (s[i] != System.Char.ToUpper(src_[pos_ + i])) return false; |
| } |
| pos_ += sLength; |
| return true; |
| } |
| |
| public bool In(char c0, char c1) |
| { |
| if (pos_ < srcLen_ |
| && src_[pos_] >= c0 && src_[pos_] <= c1) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool In(char c0, char c1, char c2, char c3) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(char c0, char c1, char c2, char c3, char c4, char c5) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3 |
| || c >= c4 && c <= c5) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(char c0, char c1, char c2, char c3, char c4, char c5, char c6, char c7) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c >= c0 && c <= c1 |
| || c >= c2 && c <= c3 |
| || c >= c4 && c <= c5 |
| || c >= c6 && c <= c7) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool In(string s) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| for (int i = 0; i < s.Length - 1; i += 2) |
| { |
| if (!(c >= s[i] && c <= s[i + 1])) return false; |
| } |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool NotIn(string s) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| for (int i = 0; i < s.Length - 1; i += 2) |
| { |
| if ( c >= s[i] && c <= s[i + 1]) return false; |
| } |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1) |
| { |
| if (pos_ < srcLen_ |
| && (src_[pos_] == c0 || src_[pos_] == c1)) |
| { |
| ++pos_; |
| return true; |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2, char c3) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2, char c3, char c4) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2, char c3, char c4, char c5) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2, char c3, char c4, char c5, char c6) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5 || c == c6) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(char c0, char c1, char c2, char c3, char c4, char c5, char c6, char c7) |
| { |
| if (pos_ < srcLen_) |
| { |
| char c = src_[pos_]; |
| if (c == c0 || c == c1 || c == c2 || c == c3 || c == c4 || c == c5 || c == c6 || c == c7) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(string s) |
| { |
| if (pos_ < srcLen_) |
| { |
| if (s.IndexOf(src_[pos_]) != -1) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool NotOneOf(string s) |
| { |
| if (pos_ < srcLen_) |
| { |
| if (s.IndexOf(src_[pos_]) == -1) |
| { |
| ++pos_; |
| return true; |
| } |
| } |
| return false; |
| } |
| public bool OneOf(OptimizedCharset cset) |
| { |
| if (pos_ < srcLen_ && cset.Matches(src_[pos_])) |
| { |
| ++pos_; return true; |
| } |
| return false; |
| } |
| public bool OneOfLiterals(OptimizedLiterals litAlt) |
| { |
| OptimizedLiterals.Trie node = litAlt.literalsRoot; |
| int matchPos = pos_-1; |
| for (int pos = pos_; pos < srcLen_ ; ++pos) |
| { |
| char c = src_[pos]; |
| if ( node.children_==null |
| || c < node.cMin_ || c > node.cMin_ + node.children_.Length - 1 |
| || node.children_[c - node.cMin_] == null) |
| { |
| break; |
| } |
| node = node.children_[c - node.cMin_]; |
| if (node.bLitEnd_) matchPos = pos + 1; |
| } |
| if (matchPos >= pos_) |
| { |
| pos_= matchPos; |
| return true; |
| } |
| else return false; |
| } |
| #endregion PEG '<Literal>' / '<Literal>'/i / [low1-high1,low2-high2..] / [<CharList>] |
| } |
| #endregion Parsers |
| } |