예제 #1
0
        ParsePrefixOp(ref OperatorData prevOpData,
                      Operator <TTerm, TAfterString, TUserState> op,
                      ref Reply <TTerm> reply,
                      CharStream <TUserState> stream)
        {
            var opData = new OperatorData();

            opData.Line       = stream.Line;
            opData.LineBegin  = stream.LineBegin;
            opData.IndexToken = stream.IndexToken;
            opData.Operator   = op;
            var userState = stream.UserState;

    #if DEBUG
            var ok = stream.Skip(op.String);
            Debug.Assert(ok);
    #else
            stream.Skip((uint)op.String.Length);
    #endif
            var stateTag = stream.StateTag;
            var asReply  = op.AfterStringParser.Invoke(stream);
            if (asReply.Status == ReplyStatus.Ok)
            {
                opData.AfterStringValue = asReply.Result;
                var prevOp = prevOpData.Operator;
                if (prevOp.Precedence != op.Precedence ||
                    prevOp.Type != OperatorType.Prefix ||
                    (prevOp.Associativity | op.Associativity) != Associativity.None)
                {
                    reply.Error = asReply.Error;
                    var nextOp = ParseExpression(ref opData, ref reply, stream);
                    if (reply.Status == ReplyStatus.Ok)
                    {
                        reply.Result = op.Mapping1.Invoke(opData.AfterStringValue, reply.Result);
                    }
                    return(nextOp);
                }
                // backtrack to the beginning of the operator
                stream.Seek(opData.IndexToken);
                stream.SetLine_WithoutCheckAndWithoutIncrementingTheStateTag(opData.Line);
                stream.SetLineBegin_WithoutCheckAndWithoutIncrementingTheStateTag(opData.LineBegin);
                stream.UserState = userState;
                stream.StateTag  = stateTag - 1;
                ReportConflict(ref prevOpData, op, asReply.Result, ref reply, stream);
                return(null);
            }
            else if (asReply.Status == ReplyStatus.Error && stateTag == stream.StateTag)
            {
                // backtrack to the beginning of the operator
                stream.Seek(opData.IndexToken);
                stream.StateTag = stateTag - 1;
                return(ErrorOp);
            }
            else
            {
                reply.Error  = asReply.Error;
                reply.Status = asReply.Status;
                return(null);
            }
        }
예제 #2
0
        ParseExpressionContinue(ref OperatorData prevOpData,
                                Operator <TTerm, TAfterString, TUserState> op,
                                ref Reply <TTerm> reply,
                                CharStream <TUserState> stream)
        {
            var opData = new OperatorData();

            for (;;)
            {
                opData.Line       = stream.Line;
                opData.LineBegin  = stream.LineBegin;
                opData.IndexToken = stream.IndexToken;
                opData.Operator   = op;
        #if DEBUG
                var ok = stream.Skip(op.String);
                Debug.Assert(ok);
        #else
                stream.Skip((uint)op.String.Length);
        #endif
                var stateTag = stream.StateTag;
                var asReply  = op.AfterStringParser.Invoke(stream);
                if (asReply.Status == ReplyStatus.Ok)
                {
                    opData.AfterStringValue = asReply.Result;
                    reply.Error             = asReply.Error;
                    if (op.Type == OperatorType.Infix)
                    {
                        var result1 = reply.Result;
                        if (!op.IsTernary)
                        {
                            var nextOp = ParseExpression(ref opData, ref reply, stream);
                            if (reply.Status == ReplyStatus.Ok)
                            {
                                reply.Result = op.Mapping2.Invoke(opData.AfterStringValue, result1, reply.Result);
                            }
                            op = nextOp;
                            if (op == null)
                            {
                                break;
                            }
                            goto CheckNextOp;
                        }
                        else
                        {
                            ParseExpression(ref ZeroPrecedenceOperatorData, ref reply, stream);
                            if (reply.Status != ReplyStatus.Ok)
                            {
                                goto ReturnNull;
                            }
                            var result2 = reply.Result;
                            if (stream.Skip(op.TernaryRightString))
                            {
                                stateTag = stream.StateTag;
                                asReply  = op.AfterTernaryRightStringParser.Invoke(stream);
                                if (asReply.Status == ReplyStatus.Ok)
                                {
                                    reply.Error = asReply.Error;
                                    var nextOp = ParseExpression(ref opData, ref reply, stream);
                                    if (reply.Status == ReplyStatus.Ok)
                                    {
                                        reply.Result = op.Mapping3.Invoke(opData.AfterStringValue, asReply.Result, result1, result2, reply.Result);
                                    }
                                    op = nextOp;
                                    if (op == null)
                                    {
                                        break;
                                    }
                                    goto CheckNextOp;
                                }
                                else if (asReply.Status != ReplyStatus.Error || stateTag != stream.StateTag)
                                {
                                    reply.Error  = asReply.Error;
                                    reply.Status = asReply.Status;
                                    goto ReturnNull;
                                }
                                else
                                {
                                    // backtrack
                                    stream.Skip(-op.TernaryRightString.Length);
                                    stream.StateTag -= 2;
                                }
                            }
                            HandleMissingTernary2ndStringError(ref opData, ref reply, stream);
                            goto ReturnNull;
                        }
                    }
                    else
                    {
                        Debug.Assert(op.Type == OperatorType.Postfix);
                        reply.Result = op.Mapping1.Invoke(opData.AfterStringValue, reply.Result);
                        var lastOp = op;
                        op = PeekOp(stream, RhsOps);
                        // we check for adjacent postfix operators here ...
                        if (op != null)
                        {
                            if (op.Type == OperatorType.Postfix && lastOp.Precedence <= op.Precedence)
                            {
                                if (lastOp.Precedence < op.Precedence ||
                                    (lastOp.Associativity | op.Associativity) != Associativity.None)
                                {
                                    continue;
                                }
                                // ... so we can report conflicting postfix operators
                                HandlePossibleConflict(ref opData, op, ref reply, stream);
                                goto ReturnNull;
                            }
                        }
                        else
                        {
                            reply.Error = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator);
                            break;
                        }
                    }
CheckNextOp:
                    var prevOp = prevOpData.Operator;
                    if (prevOp.Precedence < op.Precedence)
                    {
                        continue;
                    }
                    if (prevOp.Precedence > op.Precedence)
                    {
                        break;
                    }
                    // prevOp.Precedence == op.Precedence
                    if (op.Type == OperatorType.Infix)
                    {
                        var assoc = prevOp.Associativity & op.Associativity;
                        if (assoc == Associativity.Left || prevOp.Type == OperatorType.Prefix)
                        {
                            break;
                        }
                        if (assoc == Associativity.Right)
                        {
                            continue;
                        }
                    }
                    else // op.OperatorType == OperatorType.Postfix
                    {
                        if (prevOp.Type == OperatorType.Infix)
                        {
                            continue;
                        }
                        Debug.Assert(prevOp.Type == OperatorType.Prefix);
                        if ((prevOp.Associativity | op.Associativity) != Associativity.None)
                        {
                            break;
                        }
                    }
                    HandlePossibleConflict(ref prevOpData, op, ref reply, stream);
                }
                else // asReply.Status != ReplyStatus.Ok
                {
                    if (asReply.Status == ReplyStatus.Error && stateTag == stream.StateTag)
                    {
                        // backtrack
                        stream.Seek(opData.IndexToken);
                        stream.StateTag -= 2;
                        reply.Error      = ErrorMessageList.Merge(reply.Error, ExpectedInfixOrPostfixOperator);
                    }
                    else
                    {
                        reply.Error  = asReply.Error;
                        reply.Status = asReply.Status;
                    }
                }
ReturnNull:
                op = null;
                break;
            }
            return(op);
        }