示例#1
0
        /// <summary>
        /// Gets the value of the token.
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        protected virtual string GetTokenValue(Token token)
        {
            ParseEventHandler handler = this.Events[EventParseToken] as ParseEventHandler;

            if (handler != null)
            {
                return(handler(this, new ParseEventArgs(token)));
            }
            return(token.Value);
        }
示例#2
0
        /// <summary>
        /// Parses a string representation of an s-expression
        ///
        /// Expression ::= Atom | SExpr
        /// Atom ::= ValidName | Number | QuotedString
        /// SExpr ::= "(" Atom | SExpr ")"
        ///
        /// Number ::= ^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]*\\.?[0-9]+)?$
        /// ValidName ::= ^[a-zA-Z_]([a-zA-Z0-9_])*$
        /// QuotedString ::= single or doubly quoted text of arbitrary length, with or without whitespace
        ///
        /// </summary>
        /// <param name="psz">Input string to be parsed</param>
        /// <param name="parseEventHandler">Function to be notified of Parse events</param>
        /// <param name="context">Any object to be passed along to the notification sink</param>
        /// <returns>The context object if successful, null if not</returns>
        ///
        /// <example>
        ///
        /// Given the following support objects
        ///
        ///internal class EvaluatorContext
        ///{
        ///    public Expression Root { get; private set; }
        ///    public Expression Current { get; set; }
        ///
        ///    public EvaluatorContext(Expression Root)
        ///    {
        ///        this.Root = Root;
        ///        this.Current = Root;
        ///    }
        ///}
        ///
        ///protected static void ParseEventHandler(ParseEventArgs e)
        ///{
        ///    EvaluatorContext pctx = e.ParserContext as EvaluatorContext;
        ///    if (pctx == null) return;
        ///
        ///    switch (e.Token)
        ///    {
        ///        case E_TOKEN.Comment:
        ///            return;
        ///
        ///        case E_TOKEN.SExprStart:
        ///            {
        ///                /// a new list child
        ///                pctx.Current = new Expression(pctx.Current, "CHILD >", e.State, e.Token);
        ///            }
        ///            return;
        ///
        ///        case E_TOKEN.SExprFinish:
        ///            {
        ///                /// pop back one level
        ///                pctx.Current = pctx.Current.Parent;
        ///            }
        ///            return;
        ///    }
        ///
        ///    switch (e.State)
        ///    {
        ///        case E_PARSESTATE.Atom:
        ///            {
        ///                /// a new atom child
        ///                Expression Atom = new Expression(pctx.Current, e.TokenValue, e.State, e.Token);
        ///            }
        ///            return;
        ///
        ///        case E_PARSESTATE.Failure:
        ///            {
        ///                throw new ParseException(String.Format("*** FAILURE {0}] : [ {1} ], {2}, {3}", e.ErrorDescription, e.TokenValue, e.State, e.Token));
        ///            }
        ///    }
        ///}
        ///
        ///we can write ...
        ///
        ///EvaluatorContext Context = "(+ 'Hello' ' ' 'World ')".Parse(ParseEventHandler, new EvaluatorContext(new Expression()));
        ///Expression exHelloWorld = Context.Root.Evaluate(null);
        ///
        ///System.Console.WriteLine
        ///
        /// </example>
        ///
        public static object Parse(this string psz, ParseEventHandler parseEventHandler, object context)
        {
            var sStart   = 0;
            var sFinish  = 0;
            var exprNest = 0;

            var state = ParseState.Start;

            while (sFinish <= psz.Length)
            {
                switch (state)
                {
                case ParseState.Start:
                {
                    exprNest = 0;

                    if (parseEventHandler != null)
                    {
                        parseEventHandler(new ParseEventArgs(psz, context, state, Token.MAX, 0, 0));
                    }

                    state = ParseState.AtomOrSExpr;
                }
                break;

                case ParseState.Finish:
                {
                    if (exprNest != 0)
                    {
                        state = ParseState.Failure;
                        break;
                    }

                    if (parseEventHandler != null)
                    {
                        parseEventHandler(new ParseEventArgs(psz, context, state, Token.MAX, 0, 0));
                    }

                    // we're done...
                    return(context);
                }
                }

                var tok = Tokenizer.NextToken(psz, sFinish, out sStart, out sFinish);

                // handle comments and get them out of the way
                switch (tok)
                {
                case Token.CommentStart:     // /*
                {
                    Tokenizer.SnarfComment(psz, sStart, out sStart, out sFinish);

                    if (parseEventHandler != null)
                    {
                        parseEventHandler(new ParseEventArgs(psz, context, ParseState.Comment, Token.CommentStart, sStart, sFinish));
                    }
                }
                    continue;
                }

                switch (state)
                {
                case ParseState.SExprStart:
                {
                    // SExpr ::= SExprStart (Atom | SExpr)* SExprFinish
                    switch (tok)
                    {
                    case Token.SExprStart:         // (
                    {
                        exprNest++;

                        if (parseEventHandler != null)
                        {
                            parseEventHandler(new ParseEventArgs(psz, context, ParseState.SExprStart, tok, sStart, sFinish));
                        }

                        state = ParseState.AtomOrSExpr;
                    }
                    break;

                    case Token.EOF:
                    {
                        sFinish = sStart;
                        state   = ParseState.Finish;
                    }
                    break;

                    default:
                    {
                        if (parseEventHandler != null)
                        {
                            parseEventHandler(
                                new ParseEventArgs(
                                    psz,
                                    context,
                                    ParseState.SExprStart,
                                    tok,
                                    sStart,
                                    sFinish,
                                    "Unexpected token found instead of SExprStart"));
                        }

                        state = ParseState.Failure;
                    }
                    break;
                    }
                }
                break;

                case ParseState.AtomOrSExpr:
                {
                    switch (tok)
                    {
                    case Token.DoubleQuotedText:
                    case Token.SingleQuotedText:
                    {
                        if (parseEventHandler != null)
                        {
                            var strToken            = psz.Substring(sStart, sFinish - sStart);
                            var fContainsWhitespace = Regex.IsMatch(strToken, ".*[\\s]+.*");
                            var cSkip = (fContainsWhitespace
                                        ? 0
                                        : 1);

                            parseEventHandler(new ParseEventArgs(psz, context, ParseState.Atom, tok, sStart + cSkip, sFinish - cSkip));
                        }
                        state = ParseState.AtomOrSExpr;
                    }
                    break;

                    case Token.ValidName:
                    case Token.ValidNumber:
                    case Token.Text:
                    {
                        if (parseEventHandler != null)
                        {
                            parseEventHandler(new ParseEventArgs(psz, context, ParseState.Atom, tok, sStart, sFinish));
                        }
                        state = ParseState.AtomOrSExpr;
                    }
                    break;

                    case Token.SExprStart:        // (
                    {
                        sFinish = sStart;         //rewind token
                        state   = ParseState.SExprStart;
                    }
                    break;

                    case Token.SExprFinish:       // )
                    {
                        sFinish = sStart;         //rewind token
                        state   = ParseState.SExprFinish;
                    }
                    break;

                    case Token.EOF:
                    {
                        state = ParseState.Finish;
                    }
                    break;

                    default:
                    {
                        if (parseEventHandler != null)
                        {
                            parseEventHandler(
                                new ParseEventArgs(
                                    psz,
                                    context,
                                    ParseState.Failure,
                                    tok,
                                    sStart,
                                    sFinish,
                                    "Unexpected token found without matching SExprFinish"));
                        }
                        state = ParseState.Failure;
                    }
                    break;
                    }
                }
                break;

                case ParseState.SExprFinish:
                {
                    switch (tok)
                    {
                    case Token.SExprFinish:         // )
                    {
                        exprNest--;

                        if (parseEventHandler != null)
                        {
                            parseEventHandler(new ParseEventArgs(psz, context, ParseState.SExprFinish, tok, sStart, sFinish));
                        }
                        state = (exprNest == 0)
                                    ? ParseState.Finish
                                    : ParseState.AtomOrSExpr;
                    }
                    break;

                    case Token.EOF:
                    {
                        sFinish = sStart;
                        state   = ParseState.Finish;
                    }
                    break;

                    default:
                    {
                        if (parseEventHandler != null)
                        {
                            parseEventHandler(
                                new ParseEventArgs(
                                    psz, context, ParseState.Failure, tok, sStart, sFinish, "Unexpected token found instead of SExprFinish"));
                        }
                        state = ParseState.Failure;
                    }
                    break;
                    }
                }
                break;

// ReSharper disable RedundantCaseLabel
                case ParseState.Failure:
// ReSharper restore RedundantCaseLabel
                default:
                {
                    if (parseEventHandler != null)
                    {
                        parseEventHandler(new ParseEventArgs(psz, context, ParseState.Failure, Token.MAX, sStart, sFinish, "Parser Failure"));
                    }
                }

                    return(null);
                }
            }
            // while (curpos < psz.Length)

            if (parseEventHandler != null)
            {
                parseEventHandler(new ParseEventArgs(psz, context, ParseState.Failure, Token.MAX, sStart, sFinish));
            }

            return(null);
        }