* All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the distribution. * * Neither the name of the PHP_ParserGenerator nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @category PHP * @package PHP_ParserGenerator * @author Gregory Beaver * @copyright 2006 Gregory Beaver * @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @version CVS: $Id: Symbol.php 302382 2010-08-17 06:08:09Z jespino $ * @link http://pear.php.net/package/PHP_ParserGenerator * @since File available since Release 0.1.0 */ /** * Symbols (terminals and nonterminals) of the grammar are stored in this class * * @category PHP * @package PHP_ParserGenerator * @author Gregory Beaver * @copyright 2006 Gregory Beaver * @license http://www.opensource.org/licenses/bsd-license.php New BSD License * @version Release: @package_version@ * @link http://pear.php.net/package/PHP_ParserGenerator * @since Class available since Release 0.1.0 */ class PHP_ParserGenerator_Symbol { /** * Symbols that start with a capital letter like FOO. * * These are tokens directly from the lexer */ const TERMINAL = 1; /** * Symbols that start with a lower-case letter like foo. * * These are grammar rules like "foo ::= BLAH." */ const NONTERMINAL = 2; /** * Multiple terminal symbols. * * These are a grammar rule that consists of several terminals like * FOO|BAR|BAZ. Note that non-terminals cannot be in a multi-terminal, * and a multi-terminal acts like a single terminal. * * "FOO|BAR FOO|BAZ" is actually two multi-terminals, FOO|BAR and FOO|BAZ. */ const MULTITERMINAL = 3; const LEFT = 1; const RIGHT = 2; const NONE = 3; const UNK = 4; /** * Name of the symbol * * @var string */ public $name; /** * Index of this symbol. * * This will ultimately end up representing the symbol in the generated * parser * @var int */ public $index; /** * Symbol type * * One of PHP_ParserGenerator_Symbol::TERMINAL, * PHP_ParserGenerator_Symbol::NONTERMINAL or * PHP_ParserGenerator_Symbol::MULTITERMINAL * @var int */ public $type; /** * Linked list of rules that use this symbol, if it is a non-terminal. * @var PHP_ParserGenerator_Rule */ public $rule; /** * Fallback token in case this token doesn't parse * @var PHP_ParserGenerator_Symbol */ public $fallback; /** * Precendence, if defined. * * -1 if no unusual precedence * @var int */ public $prec = -1; /** * Associativity if precedence is defined. * * One of PHP_ParserGenerator_Symbol::LEFT, * PHP_ParserGenerator_Symbol::RIGHT, PHP_ParserGenerator_Symbol::NONE * or PHP_ParserGenerator_Symbol::UNK * @var unknown_type */ public $assoc; /** * First-set for all rules of this symbol * * @var array */ public $firstset; /** * True if this symbol is a non-terminal and can generate an empty * result. * * For instance "foo ::= ." * @var boolean */ public $lambda; /** * Code that executes whenever this symbol is popped from the stack during * error processing. * * @var string|0 */ public $destructor = 0; /** * Line number of destructor code * @var int */ public $destructorln; /** * Unused relic of the C version of Lemon. * * The data type of information held by this object. Only used * if this is a non-terminal * @var string */ public $datatype; /** * Unused relic of the C version of Lemon. * * The data type number. In the parser, the value * stack is a union. The .yy%d element of this * union is the correct data type for this object * @var string */ public $dtnum; /**#@+ * The following fields are used by MULTITERMINALs only */ /** * Number of terminal symbols in the MULTITERMINAL * * This is of course the same as count($this->subsym) * @var int */ public $nsubsym; /** * Array of terminal symbols in the MULTITERMINAL * @var array an array of {@link PHP_ParserGenerator_Symbol} objects */ public $subsym = array(); /**#@-*/ /** * Singleton storage of symbols * * @var array an array of PHP_ParserGenerator_Symbol objects */ private static $_symbol_table = array(); /** * Return a pointer to the (terminal or nonterminal) symbol "x". * Create a new symbol if this is the first time "x" has been seen. * (this is a singleton) * @param string * @return PHP_ParserGenerator_Symbol */ public static function Symbol_new($x) { if (isset(self::$_symbol_table[$x])) { return self::$_symbol_table[$x]; } $sp = new PHP_ParserGenerator_Symbol; $sp->name = $x; $sp->type = preg_match('/[A-Z]/', $x[0]) ? self::TERMINAL : self::NONTERMINAL; $sp->rule = 0; $sp->fallback = 0; $sp->prec = -1; $sp->assoc = self::UNK; $sp->firstset = array(); $sp->lambda = false; $sp->destructor = 0; $sp->datatype = 0; self::$_symbol_table[$sp->name] = $sp; return $sp; } /** * Return the number of unique symbols * * @return int */ public static function Symbol_count() { return count(self::$_symbol_table); } public static function Symbol_arrayof() { return array_values(self::$_symbol_table); } public static function Symbol_find($x) { if (isset(self::$_symbol_table[$x])) { return self::$_symbol_table[$x]; } return 0; } /** * Sort function helper for symbols * * Symbols that begin with upper case letters (terminals or tokens) * must sort before symbols that begin with lower case letters * (non-terminals). Other than that, the order does not matter. * * We find experimentally that leaving the symbols in their original * order (the order they appeared in the grammar file) gives the * smallest parser tables in SQLite. * @param PHP_ParserGenerator_Symbol * @param PHP_ParserGenerator_Symbol */ public static function sortSymbols($a, $b) { $i1 = $a->index + 10000000*(ord($a->name[0]) > ord('Z')); $i2 = $b->index + 10000000*(ord($b->name[0]) > ord('Z')); return $i1 - $i2; } /** * Return true if two symbols are the same. */ public static function same_symbol(PHP_ParserGenerator_Symbol $a, PHP_ParserGenerator_Symbol $b) { if ($a === $b) return 1; if ($a->type != self::MULTITERMINAL) return 0; if ($b->type != self::MULTITERMINAL) return 0; if ($a->nsubsym != $b->nsubsym) return 0; for ($i = 0; $i < $a->nsubsym; $i++) { if ($a->subsym[$i] != $b->subsym[$i]) return 0; } return 1; } }