<?php
$meta #
#semval($) $this->yyval
#semval($,%t) $this->yyval
#semval(%n) $this->yyastk[$this->stackPos-(%l-%n)]
#semval(%n,%t) $this->yyastk[$this->stackPos-(%l-%n)]
#include;

/* This is an automatically GENERATED file, which should not be manually edited.
 * Instead edit one of the following:
 *  * the grammar file grammar/zend_language_parser.phpy
 *  * the parser skeleton grammar/kymacc.php.parser
 *  * the preprocessing script grammar/rebuildParser.php
 *
 * The skeleton for this parser was written by Moriyoshi Koizumi and is based on
 * the work by Masato Bito and is in the PUBLIC DOMAIN.
 */
#if -t
class #(-p)_Debug extends #(-p)
#endif
#ifnot -t
class #(-p)
#endif
{
#ifnot -t
    const TOKEN_NONE    = -1;
    const TOKEN_INVALID = #(YYBADCH);

    const TOKEN_MAP_SIZE = #(YYMAXLEX);

    const YYLAST       = #(YYLAST);
    const YY2TBLSTATE  = #(YY2TBLSTATE);
    const YYGLAST      = #(YYGLAST);
    const YYNLSTATES   = #(YYNLSTATES);
    const YYUNEXPECTED = #(YYUNEXPECTED);
    const YYDEFAULT    = #(YYDEFAULT);

    // {{{ Tokens
#tokenval
    const %s = %n;
#endtokenval
    // }}}

    /* @var array Map of token ids to their respective names */
    protected static $terminals = array(
        #listvar terminals
        , "???"
    );

    /* @var array Map which translates lexer tokens to internal tokens */
    protected static $translate = array(
        #listvar yytranslate
    );

    protected static $yyaction = array(
        #listvar yyaction
    );

    protected static $yycheck = array(
        #listvar yycheck
    );

    protected static $yybase = array(
        #listvar yybase
    );

    protected static $yydefault = array(
        #listvar yydefault
    );

    protected static $yygoto = array(
        #listvar yygoto
    );

    protected static $yygcheck = array(
        #listvar yygcheck
    );

    protected static $yygbase = array(
        #listvar yygbase
    );

    protected static $yygdefault = array(
        #listvar yygdefault
    );

    protected static $yylhs = array(
        #listvar yylhs
    );

    protected static $yylen = array(
        #listvar yylen
    );

    protected $yyval;
    protected $yyastk;
    protected $stackPos;
    protected $lexer;

    /**
     * Creates a parser instance.
     *
     * @param PHPParser_Lexer $lexer A lexer
     */
    public function __construct(PHPParser_Lexer $lexer) {
        $this->lexer = $lexer;
    }
#endif
#if -t
    protected static $yyproduction = array(
        #production-strings;
    );

    protected function yyprintln($msg) {
        echo $msg, "\n";
    }

    protected function YYTRACE_NEWSTATE($state, $tokenId) {
        $this->yyprintln(
            '% State ' . $state
          . ', Lookahead ' . ($tokenId == self::TOKEN_NONE ? '--none--' : self::$terminals[$tokenId])
        );
    }

    protected function YYTRACE_READ($tokenId) {
        $this->yyprintln('% Reading ' . self::$terminals[$tokenId]);
    }

    protected function YYTRACE_SHIFT($tokenId) {
        $this->yyprintln('% Shift ' . self::$terminals[$tokenId]);
    }

    protected function YYTRACE_ACCEPT() {
        $this->yyprintln('% Accepted.');
    }

    protected function YYTRACE_REDUCE($n) {
        $this->yyprintln('% Reduce by (' . $n . ') ' . self::$yyproduction[$n]);
    }

    protected function YYTRACE_POP($state) {
        $this->yyprintln('% Recovering, uncovers state ' . $state);
    }

    protected function YYTRACE_DISCARD($tokenId) {
        $this->yyprintln('% Discard ' . self::$terminals[$tokenId]);
    }
#endif

    /**
#ifnot -t
     * Parses PHP code into a node tree.
#endif
#if -t
     * Parses PHP code into a node tree and prints out debugging information.
#endif
     *
     * @param string $code The source code to parse
     *
     * @return PHPParser_Node[] Array of statements
     */
    public function parse($code) {
        $this->lexer->startLexing($code);

        // We start off with no lookahead-token
        $tokenId = self::TOKEN_NONE;

        // The attributes for a node are taken from the first and last token of the node.
        // From the first token only the startAttributes are taken and from the last only
        // the endAttributes. Both are merged using the array union operator (+).
        $startAttributes = array('startLine' => 1);
        $endAttributes   = array();

        // In order to figure out the attributes for the starting token, we have to keep
        // them in a stack
        $attributeStack = array($startAttributes);

        // Start off in the initial state and keep a stack of previous states
        $state = 0;
        $stateStack = array($state);

        // AST stack (?)
        $this->yyastk = array();

        // Current position in the stack(s)
        $this->stackPos = 0;

        for (;;) {
#if -t
            $this->YYTRACE_NEWSTATE($state, $tokenId);

#endif
            if (self::$yybase[$state] == 0) {
                $yyn = self::$yydefault[$state];
            } else {
                if ($tokenId === self::TOKEN_NONE) {
                    // Fetch the next token id from the lexer and fetch additional info by-ref.
                    // The end attributes are fetched into a temporary variable and only set once the token is really
                    // shifted (not during read). Otherwise you would sometimes get off-by-one errors, when a rule is
                    // reduced after a token was read but not yet shifted.
                    $origTokenId = $this->lexer->getNextToken($tokenValue, $startAttributes, $nextEndAttributes);

                    // map the lexer token id to the internally used token id's
                    $tokenId = $origTokenId >= 0 && $origTokenId < self::TOKEN_MAP_SIZE
                        ? self::$translate[$origTokenId]
                        : self::TOKEN_INVALID;

                    if ($tokenId === self::TOKEN_INVALID) {
                        throw new RangeException(sprintf(
                            'The lexer returned an invalid token (id=%d, value=%s)',
                            $origTokenId, $tokenValue
                        ));
                    }

                    $attributeStack[$this->stackPos] = $startAttributes;
#if -t

                    $this->YYTRACE_READ($tokenId);
#endif
                }

                if ((($yyn = self::$yybase[$state] + $tokenId) >= 0
                     && $yyn < self::YYLAST && self::$yycheck[$yyn] == $tokenId
                     || ($state < self::YY2TBLSTATE
                        && ($yyn = self::$yybase[$state + self::YYNLSTATES] + $tokenId) >= 0
                        && $yyn < self::YYLAST
                        && self::$yycheck[$yyn] == $tokenId))
                    && ($yyn = self::$yyaction[$yyn]) != self::YYDEFAULT) {
                    /*
                     * >= YYNLSTATE: shift and reduce
                     * > 0: shift
                     * = 0: accept
                     * < 0: reduce
                     * = -YYUNEXPECTED: error
                     */
                    if ($yyn > 0) {
                        /* shift */
#if -t
                        $this->YYTRACE_SHIFT($tokenId);

#endif
                        ++$this->stackPos;

                        $stateStack[$this->stackPos]     = $state = $yyn;
                        $this->yyastk[$this->stackPos]   = $tokenValue;
                        $attributeStack[$this->stackPos] = $startAttributes;
                        $endAttributes = $nextEndAttributes;
                        $tokenId = self::TOKEN_NONE;

                        if ($yyn < self::YYNLSTATES)
                            continue;

                        /* $yyn >= YYNLSTATES means shift-and-reduce */
                        $yyn -= self::YYNLSTATES;
                    } else {
                        $yyn = -$yyn;
                    }
                } else {
                    $yyn = self::$yydefault[$state];
                }
            }

            for (;;) {
                /* reduce/error */
                if ($yyn == 0) {
                    /* accept */
#if -t
                    $this->YYTRACE_ACCEPT();
#endif
                    return $this->yyval;
                } elseif ($yyn != self::YYUNEXPECTED) {
                    /* reduce */
#if -t
                    $this->YYTRACE_REDUCE($yyn);
#endif
                    try {
                        $this->{'yyn' . $yyn}(
                            $attributeStack[$this->stackPos - self::$yylen[$yyn]]
                            + $endAttributes
                        );
                    } catch (PHPParser_Error $e) {
                        if (-1 === $e->getRawLine()) {
                            $e->setRawLine($startAttributes['startLine']);
                        }

                        throw $e;
                    }

                    /* Goto - shift nonterminal */
                    $this->stackPos -= self::$yylen[$yyn];
                    $yyn = self::$yylhs[$yyn];
                    if (($yyp = self::$yygbase[$yyn] + $stateStack[$this->stackPos]) >= 0
                         && $yyp < self::YYGLAST
                         && self::$yygcheck[$yyp] == $yyn) {
                        $state = self::$yygoto[$yyp];
                    } else {
                        $state = self::$yygdefault[$yyn];
                    }

                    ++$this->stackPos;

                    $stateStack[$this->stackPos]     = $state;
                    $this->yyastk[$this->stackPos]   = $this->yyval;
                    $attributeStack[$this->stackPos] = $startAttributes;
                } else {
                    /* error */
                    $expected = array();

                    $base = self::$yybase[$state];
                    for ($i = 0; $i < self::TOKEN_MAP_SIZE; ++$i) {
                        $n = $base + $i;
                        if ($n >= 0 && $n < self::YYLAST && self::$yycheck[$n] == $i
                         || $state < self::YY2TBLSTATE
                            && ($n = self::$yybase[$state + self::YYNLSTATES] + $i) >= 0
                            && $n < self::YYLAST && self::$yycheck[$n] == $i
                        ) {
                            if (self::$yyaction[$n] != self::YYUNEXPECTED) {
                                if (count($expected) == 4) {
                                    /* Too many expected tokens */
                                    $expected = array();
                                    break;
                                }

                                $expected[] = self::$terminals[$i];
                            }
                        }
                    }

                    $expectedString = '';
                    if ($expected) {
                        $expectedString = ', expecting ' . implode(' or ', $expected);
                    }

                    throw new PHPParser_Error(
                        'Syntax error, unexpected ' . self::$terminals[$tokenId] . $expectedString,
                        $startAttributes['startLine']
                    );
                }

                if ($state < self::YYNLSTATES)
                    break;
                /* >= YYNLSTATES means shift-and-reduce */
                $yyn = $state - self::YYNLSTATES;
            }
        }
    }
#ifnot -t
#reduce

    protected function yyn%n($attributes) {
        %b
    }
#noact

    protected function yyn%n() {
        $this->yyval = $this->yyastk[$this->stackPos];
    }
#endreduce
#endif
}
#tailcode;
