public static Int32 Parse(List<Token> src, Int32 begin, out Expr expr)
    {
        //expr = null;

        Int32 current;
        Int32 saved;

        if (Parser.IsKeyword(src[begin], KeywordVal.SIZEOF)) {
            // 1. sizeof
            current = begin + 1;

            // 1.1. try to match type_name
            saved = current;
            TypeName type_name;
            current = ParseTypeName(src, current, out type_name);
            if (current != -1) {
                // 1.1. -- successful match
                expr = new SizeofType(type_name);
                return current;
            }

            // 1.2. type_name match failed, try unary_expression
            current = saved;
            current = _unary_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            // 1.2. -- successful match
            expr = new SizeofExpr(expr);
            return current;

        } // sizeof

        // 2. postfix_expression
        current = _postfix_expression.Parse(src, begin, out expr);
        if (current != -1) {
            // successful match
            return current;
        }

        // now only operators are left
        if (src[begin].type != TokenType.OPERATOR) {
            return -1;
        }

        current = begin;
        OperatorVal val = ((TokenOperator)src[begin]).val;
        switch (val) {
        case OperatorVal.INC:
            // '++'
            current++;

            current = _unary_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new PreIncrement(expr);
            return current;

        case OperatorVal.DEC:
            // '--'
            current++;

            current = _unary_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new PreDecrement(expr);
            return current;

        case OperatorVal.BITAND:
            // '&' (reference)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new Reference(expr);
            return current;

        case OperatorVal.MULT:
            // '*' (dereference)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new Dereference(expr);
            return current;

        case OperatorVal.ADD:
            // '+' (positive)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new Positive(expr);
            return current;

        case OperatorVal.SUB:
            // '-' (negative)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new Negative(expr);
            return current;

        case OperatorVal.TILDE:
            // '~' (bitwise not)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new BitwiseNot(expr);
            return current;

        case OperatorVal.NOT:
            // '!' (logical not)
            current++;

            current = _cast_expression.Parse(src, current, out expr);
            if (current == -1) {
                expr = null;
                return -1;
            }

            expr = new LogicalNot(expr);
            return current;

        default:

            // no match
            return -1;

        } // case (val)
    }
    public static Int32 Parse(List<Token> src, Int32 begin, out Expr expr)
    {
        // step 1. match primary_expression
        Int32 current = _primary_expression.Parse(src, begin, out expr);
        if (current == -1) {
            expr = null;
            return -1;
        }

        // step 2. match postfixes
        while (true) {

            if (src[current].type != TokenType.OPERATOR) {
                return current;
            }

            OperatorVal val = ((TokenOperator)src[current]).val;
            switch (val) {
            case OperatorVal.LBRACKET:
                // '['
                current++;

                // 1. match expression
                Expr idx;
                current = _expression.Parse(src, current, out idx);
                if (current == -1) {
                    expr = null;
                    return -1;
                }

                // 2. match ']'
                if (!Parser.IsOperator(src[current], OperatorVal.RBRACKET)) {
                    expr = null;
                    return -1;
                }
                current++;

                // successful match
                expr = new Dereference(new Add(expr, idx));
                // expr = new ArrayElement(expr, idx);
                break;

            case OperatorVal.LPAREN:
                // '('
                current++;

                // 1. match arglist, if no match, assume empty arglist
                List<Expr> args;
                Int32 saved = current;
                current = _argument_expression_list.Parse(src, current, out args);
                if (current == -1) {
                    args = new List<Expr>();
                    current = saved;
                }

                // 2. match ')'
                if (!Parser.IsOperator(src[current], OperatorVal.RPAREN)) {
                    expr = null;
                    return -1;
                }
                current++;

                // successful match
                expr = new FuncCall(expr, args);
                break;

            case OperatorVal.PERIOD:
                // '.'
                current++;

                // match identifier
                if (src[current].type != TokenType.IDENTIFIER) {
                    expr = null;
                    return -1;
                }
                String attrib = ((TokenIdentifier)src[current]).val;
                current++;

                // successful match
                expr = new SyntaxTree.Attribute(expr, new Variable(attrib));
                break;

            case OperatorVal.RARROW:
                // '->'
                current++;

                if (src[current].type != TokenType.IDENTIFIER) {
                    return -1;
                }
                String pattrib = ((TokenIdentifier)src[current]).val;
                current++;

                // successful match
                expr = new SyntaxTree.Attribute(new Dereference(expr), new Variable(pattrib));
                // expr = new PointerAttribute(expr, new Variable(pattrib));
                break;

            case OperatorVal.INC:
                // '++'
                current++;

                // successful match
                expr = new PostIncrement(expr);
                break;

            case OperatorVal.DEC:
                // '--'

                current++;

                // successful match
                expr = new PostDecrement(expr);
                break;

            default:

                // no more postfix
                return current;

            } // case (val)

        } // while (true)
    }