1<?php 2/** 3 * PHP_ParserGenerator, a php 5 parser generator. 4 * 5 * This is a direct port of the Lemon parser generator, found at 6 * {@link http://www.hwaci.com/sw/lemon/} 7 * 8 * PHP version 5 9 * 10 * LICENSE: 11 * 12 * Copyright (c) 2006, Gregory Beaver <cellog@php.net> 13 * All rights reserved. 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 19 * * Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * * Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in 23 * the documentation and/or other materials provided with the distribution. 24 * * Neither the name of the PHP_ParserGenerator nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 29 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 30 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 32 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 36 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * @category PHP 41 * @package PHP_ParserGenerator 42 * @author Gregory Beaver <cellog@php.net> 43 * @copyright 2006 Gregory Beaver 44 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 45 * @version CVS: $Id: Action.php 302382 2010-08-17 06:08:09Z jespino $ 46 * @link http://pear.php.net/package/PHP_ParserGenerator 47 * @since File available since Release 0.1.0 48 */ 49 50/** 51 * Every shift or reduce operation is stored as one of the following objects. 52 * 53 * @category PHP 54 * @package PHP_ParserGenerator 55 * @author Gregory Beaver <cellog@php.net> 56 * @copyright 2006 Gregory Beaver 57 * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 58 * @version Release: @package_version@ 59 * @link http://pear.php.net/package/PHP_ParserGenerator 60 * @since Class available since Release 0.1.0 61 */ 62class PHP_ParserGenerator_Action 63{ 64 const SHIFT = 1, 65 ACCEPT = 2, 66 REDUCE = 3, 67 ERROR = 4, 68 /** 69 * Was a reduce, but part of a conflict 70 */ 71 CONFLICT = 5, 72 /** 73 * Was a shift. Precedence resolved conflict 74 */ 75 SH_RESOLVED = 6, 76 /** 77 * Was a reduce. Precedence resolved conflict 78 */ 79 RD_RESOLVED = 7, 80 /** 81 * Deleted by compression 82 * @see PHP_ParserGenerator::CompressTables() 83 */ 84 NOT_USED = 8; 85 /** 86 * The look-ahead symbol that triggers this action 87 * @var PHP_ParserGenerator_Symbol 88 */ 89 public $sp; /* The look-ahead symbol */ 90 /** 91 * This defines the kind of action, and must be one 92 * of the class constants. 93 * 94 * - {@link PHP_ParserGenerator_Action::SHIFT} 95 * - {@link PHP_ParserGenerator_Action::ACCEPT} 96 * - {@link PHP_ParserGenerator_Action::REDUCE} 97 * - {@link PHP_ParserGenerator_Action::ERROR} 98 * - {@link PHP_ParserGenerator_Action::CONFLICT} 99 * - {@link PHP_ParserGenerator_Action::SH_RESOLVED} 100 * - {@link PHP_ParserGenerator_Action:: RD_RESOLVED} 101 * - {@link PHP_ParserGenerator_Action::NOT_USED} 102 */ 103 public $type; 104 /** 105 * The new state, if this is a shift, 106 * the parser rule index, if this is a reduce. 107 * 108 * @var PHP_ParserGenerator_State|PHP_ParserGenerator_Rule 109 */ 110 public $x; 111 /** 112 * The next action for this state. 113 * @var PHP_ParserGenerator_Action 114 */ 115 public $next; 116 117 /** 118 * Compare two actions 119 * 120 * This is used by {@link Action_sort()} to compare actions 121 */ 122 static function actioncmp(PHP_ParserGenerator_Action $ap1, PHP_ParserGenerator_Action $ap2) 123 { 124 $rc = $ap1->sp->index - $ap2->sp->index; 125 if ($rc === 0) { 126 $rc = $ap1->type - $ap2->type; 127 } 128 if ($rc === 0) { 129 if ($ap1->type == self::SHIFT) { 130 if ($ap1->x->statenum != $ap2->x->statenum) { 131 throw new Exception('Shift conflict: ' . $ap1->sp->name . 132 ' shifts both to state ' . $ap1->x->statenum . ' (rule ' . 133 $ap1->x->cfp->rp->lhs->name . ' on line ' . 134 $ap1->x->cfp->rp->ruleline . ') and to state ' . 135 $ap2->x->statenum . ' (rule ' . 136 $ap2->x->cfp->rp->lhs->name . ' on line ' . 137 $ap2->x->cfp->rp->ruleline . ')'); 138 } 139 } 140 if ($ap1->type != self::REDUCE 141 && $ap1->type != self::RD_RESOLVED 142 && $ap1->type != self::CONFLICT 143 ) { 144 throw new Exception('action has not been processed: ' . 145 $ap1->sp->name . ' on line ' . $ap1->x->cfp->rp->ruleline . 146 ', rule ' . $ap1->x->cfp->rp->lhs->name); 147 } 148 if ($ap2->type != self::REDUCE 149 && $ap2->type != self::RD_RESOLVED 150 && $ap2->type != self::CONFLICT 151 ) { 152 throw new Exception('action has not been processed: ' . 153 $ap2->sp->name . ' on line ' . $ap2->x->cfp->rp->ruleline . 154 ', rule ' . $ap2->x->cfp->rp->lhs->name); 155 } 156 $rc = $ap1->x->index - $ap2->x->index; 157 } 158 return $rc; 159 } 160 161 function display($processed = false) 162 { 163 $map = array( 164 self::ACCEPT => 'ACCEPT', 165 self::CONFLICT => 'CONFLICT', 166 self::REDUCE => 'REDUCE', 167 self::SHIFT => 'SHIFT' 168 ); 169 echo $map[$this->type] . ' for ' . $this->sp->name; 170 if ($this->type == self::REDUCE) { 171 echo ' - rule ' . $this->x->lhs->name . "\n"; 172 } elseif ($this->type == self::SHIFT) { 173 echo ' - state ' . $this->x->statenum . ', basis ' . $this->x->cfp->rp->lhs->name . "\n"; 174 } else { 175 echo "\n"; 176 } 177 } 178 179 /** 180 * create linked list of PHP_ParserGenerator_Actions 181 * 182 * @param PHP_ParserGenerator_Action|null $app 183 * @param int $type one of the class constants from PHP_ParserGenerator_Action 184 * @param PHP_ParserGenerator_Symbol $sp 185 * @param PHP_ParserGenerator_State|PHP_ParserGenerator_Rule $arg 186 */ 187 static function Action_add(&$app, $type, PHP_ParserGenerator_Symbol $sp, $arg) 188 { 189 $new = new PHP_ParserGenerator_Action; 190 $new->next = $app; 191 $app = $new; 192 $new->type = $type; 193 $new->sp = $sp; 194 $new->x = $arg; 195 echo ' Adding '; 196 $new->display(); 197 } 198 199 /** 200 * Sort parser actions 201 * 202 * @param PHP_ParserGenerator_Action $ap a parser action 203 * 204 * @see PHP_ParserGenerator_Data::FindActions() 205 * 206 * @return PHP_ParserGenerator_Action 207 */ 208 static function Action_sort(PHP_ParserGenerator_Action $ap) 209 { 210 $ap = PHP_ParserGenerator::msort($ap, 'next', array('PHP_ParserGenerator_Action', 'actioncmp')); 211 return $ap; 212 } 213 214 /** 215 * Print an action to the given file descriptor. Return FALSE if 216 * nothing was actually printed. 217 * 218 * @param resource $fp File descriptor to print on 219 * @param integer $indent Number of indents 220 * 221 * @see PHP_ParserGenerator_Data::ReportOutput() 222 * 223 * @return int|false 224 */ 225 function PrintAction($fp, $indent) 226 { 227 if (!$fp) { 228 $fp = STDOUT; 229 } 230 $result = 1; 231 switch ($this->type) 232 { 233 case self::SHIFT: 234 fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum); 235 break; 236 case self::REDUCE: 237 fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index); 238 break; 239 case self::ACCEPT: 240 fprintf($fp, "%${indent}s accept", $this->sp->name); 241 break; 242 case self::ERROR: 243 fprintf($fp, "%${indent}s error", $this->sp->name); 244 break; 245 case self::CONFLICT: 246 fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index); 247 break; 248 case self::SH_RESOLVED: 249 case self::RD_RESOLVED: 250 case self::NOT_USED: 251 $result = 0; 252 break; 253 } 254 return $result; 255 } 256} 257?> 258