예제 #1
0
        private void SaveGroups(ref RxContext cxt, int start, int end,
                                bool clear, out RxSavedGroups groups)
        {
            groups.Start = start;
            groups.LastOpenCapture = cxt.LastOpenCapture;
            groups.LastClosedCapture = cxt.LastClosedCapture;
            groups.Data = new RxCapture[end - start];

            for (int i = start; i < end; ++i)
            {
                if (clear || cxt.Captures.Length <= i)
                    groups.Data[i - start].Start = groups.Data[i - start].End = -1;
                else
                {
                    groups.Data[i - start] = cxt.Captures[i];
                }
            }
        }
예제 #2
0
        private bool MatchAt(Runtime runtime, string str, int pos,
                             out RxResult res)
        {
            int len = str.Length;

            res.Matched = false;
            res.Start = res.End = -1;
            res.Captures = null;
            res.StringCaptures = null;

            RxContext cxt;

            cxt.Pos = pos;
            cxt.Groups = new List<RxGroup>();
            cxt.States = new List<RxState>();
            cxt.StateBacktrack = new List<int>();
            if (Captures > 0)
                cxt.Captures = new RxCapture[Captures];
            else
                cxt.Captures = null;
            if (Saved > 0)
                cxt.Saved = new int[Saved];
            else
                cxt.Saved = null;
            cxt.LastOpenCapture = cxt.LastClosedCapture = -1;

            for (int index = 0; index >= 0;)
            {
                switch (Ops[index].Number)
                {
                case Opcode.OpNumber.OP_RX_START_MATCH:
                    // do nothing for now
                    ++index;
                    break;
                case Opcode.OpNumber.OP_RX_EXACT:
                case Opcode.OpNumber.OP_RX_EXACT_I:
                {
                    var s = Exact[Ops[index].Index];
                    bool case_insensitive = Ops[index].Number == Opcode.OpNumber.OP_RX_EXACT_I;

                    if (   cxt.Pos + s.Length > len
                        || string.Compare(str, cxt.Pos, s, 0, s.Length,
                                          case_insensitive) != 0)
                        index = Backtrack(ref cxt);
                    else
                    {
                        cxt.Pos += s.Length;
                        ++index;
                    }

                    break;
                }
                case Opcode.OpNumber.OP_RX_SAVE_POS:
                {
                    cxt.Saved[Ops[index].Index] = cxt.Pos;

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_RESTORE_POS:
                {
                    cxt.Pos = cxt.Saved[Ops[index].Index];

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_ANY_NONEWLINE:
                {
                    if (cxt.Pos == len || str[cxt.Pos] == '\n')
                        index = Backtrack(ref cxt);
                    else
                    {
                        ++cxt.Pos;
                        ++index;
                    }

                    break;
                }
                case Opcode.OpNumber.OP_RX_ANY:
                {
                    if (cxt.Pos == len)
                        index = Backtrack(ref cxt);
                    else
                    {
                        ++cxt.Pos;
                        ++index;
                    }

                    break;
                }
                case Opcode.OpNumber.OP_RX_CLASS:
                {
                    var c = Classes[Ops[index].Index];

                    if (cxt.Pos < len)
                    {
                        char ch = str[cxt.Pos];

                        ++cxt.Pos;
                        ++index;

                        if (c.Exact.IndexOf(ch) >= 0)
                            break;

                        if ((c.Flags & Opcode.RX_CLASS_WORDS) != 0 && IsWord(ch))
                            break;
                        if ((c.Flags & Opcode.RX_CLASS_NOT_WORDS) != 0 && !IsWord(ch))
                            break;
                        if ((c.Flags & Opcode.RX_CLASS_DIGITS) != 0 && char.IsDigit(ch))
                            break;
                        if ((c.Flags & Opcode.RX_CLASS_NOT_DIGITS) != 0 && !char.IsDigit(ch))
                            break;
                        if ((c.Flags & Opcode.RX_CLASS_SPACES) != 0 && char.IsWhiteSpace(ch))
                            break;
                        if ((c.Flags & Opcode.RX_CLASS_NOT_SPACES) != 0 && !char.IsWhiteSpace(ch))
                            break;
                    }

                    index = Backtrack(ref cxt);
                    break;
                }
                case Opcode.OpNumber.OP_RX_BEGINNING:
                {
                    if (cxt.Pos != 0)
                        index = Backtrack(ref cxt);
                    else
                        ++index;

                    break;
                }
                case Opcode.OpNumber.OP_RX_START_GROUP:
                {
                    var grp = new RxGroup(-1);

                    cxt.Groups.Add(grp);
                    cxt.StateBacktrack.Add(cxt.States.Count);

                    index = Targets[Ops[index].Index];
                    break;
                }
                case Opcode.OpNumber.OP_RX_BACKTRACK:
                case Opcode.OpNumber.OP_RX_TRY:
                {
                    var st = new RxState(cxt.Pos, Targets[Ops[index].Index],
                                         cxt.Groups.Count);

                    cxt.States.Add(st);

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_POP_STATE:
                {
                    cxt.States.RemoveAt(cxt.States.Count - 1);

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_FAIL:
                {
                    index = Backtrack(ref cxt);
                    break;
                }
                case Opcode.OpNumber.OP_RX_QUANTIFIER:
                {
                    var group = cxt.Groups[cxt.Groups.Count - 1];
                    var quant = Quantifiers[Ops[index].Index];
                    int lastMatch = group.LastMatch;

                    ++index;
                    group.Count += 1;
                    group.LastMatch = cxt.Pos;

                    if (group.Count > 0 && quant.Group >= 0)
                        EndCapture(ref cxt, quant.Group);

                    // max repeat count
                    if (group.Count == quant.MaxCount)
                    {
                        cxt.Groups.RemoveAt(cxt.Groups.Count - 1);
                        break;
                    }

                    // zero-length match
                    if (cxt.Pos == lastMatch)
                    {
                        break;
                    }

                    RxSavedGroups gr;
                    if (group.Count == 0 || group.Count >= quant.MinCount)
                        SaveGroups(ref cxt, quant.SubgroupStart, quant.SubgroupEnd,
                                   group.Count == 0,
                                   out gr);
                    else
                        gr = new RxSavedGroups();

                    if (group.Count == 0 && quant.MinCount > 0)
                    {
                        // force failure on backtrack
                        var st = new RxState(cxt.Pos, -1, -1);
                        st.Groups = gr;

                        cxt.States.Add(st);
                    }
                    else if (quant.IsGreedy && group.Count >= quant.MinCount)
                    {
                        var st = new RxState(cxt.Pos, index, cxt.Groups.Count - 1);
                        st.Groups = gr;

                        cxt.States.Add(st);
                    }

                    cxt.Groups[cxt.Groups.Count - 1] = group;

                    // if nongreedy, match at least min
                    if (!quant.IsGreedy && group.Count >= quant.MinCount)
                    {
                        var st = new RxState(cxt.Pos, Targets[quant.To], cxt.Groups.Count);
                        st.Groups = gr;

                        cxt.States.Add(st);
                        break;
                    }

                    if (quant.Group >= 0)
                        StartCapture(ref cxt, quant.Group);

                    index = Targets[quant.To];
                    break;
                }
                case Opcode.OpNumber.OP_RX_CAPTURE_START:
                {
                    StartCapture(ref cxt, Ops[index].Index);

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_CAPTURE_END:
                {
                    EndCapture(ref cxt, Ops[index].Index);

                    ++index;
                    break;
                }
                case Opcode.OpNumber.OP_RX_ACCEPT:
                {
                    for (int i = cxt.LastOpenCapture + 1; i < Ops[index].Index; ++i)
                        cxt.Captures[i].Start = cxt.Captures[i].End = -1;

                    if (cxt.Captures != null)
                    {
                        res.StringCaptures = new string[cxt.Captures.Length];
                        for (int i = 0; i < cxt.Captures.Length; ++i)
                            if (cxt.Captures[i].End != -1)
                                res.StringCaptures[i] =
                                    str.Substring(cxt.Captures[i].Start,
                                                  cxt.Captures[i].End - cxt.Captures[i].Start);
                    }

                    res.Start = pos;
                    res.End = cxt.Pos;
                    res.Captures = cxt.Captures;
                    res.Matched = true;

                    index = -1;

                    break;
                }
                case Opcode.OpNumber.OP_JUMP:
                    index = Targets[Ops[index].Index];
                    break;
                default:
                    throw new System.Exception("PANIC: unhandled opcode " + Ops[index].Number);
                }
            }

            return res.Matched;
        }
예제 #3
0
        private void RestoreGroups(ref RxContext cxt, ref RxSavedGroups groups)
        {
            if (groups.Data == null)
                return;

            for (int i = 0; i < groups.Data.Length; ++i)
                cxt.Captures[i + groups.Start] = groups.Data[i];

            cxt.LastOpenCapture = groups.LastOpenCapture;
            cxt.LastClosedCapture = groups.LastClosedCapture;
        }
예제 #4
0
 public RxState(int pos, int target, int group)
 {
     Pos = pos;
     Target = target;
     Group = group;
     Groups = new RxSavedGroups();
 }