1<?php 2 3/** 4 * Hoa 5 * 6 * 7 * @license 8 * 9 * New BSD License 10 * 11 * Copyright © 2007-2017, Hoa community. All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions are met: 15 * * Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * * Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * * Neither the name of the Hoa nor the names of its contributors may be 21 * used to endorse or promote products derived from this software without 22 * specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 25 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE 28 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37namespace Hoa\Compiler\Bin; 38 39use Hoa\Compiler; 40use Hoa\Consistency; 41use Hoa\Console; 42use Hoa\File; 43 44/** 45 * Class Hoa\Compiler\Bin\Pp. 46 * 47 * Play with PP. 48 * 49 * @copyright Copyright © 2007-2017 Hoa community 50 * @license New BSD License 51 */ 52class Pp extends Console\Dispatcher\Kit 53{ 54 /** 55 * Options description. 56 * 57 * @var array 58 */ 59 protected $options = [ 60 ['visitor', Console\GetOption::REQUIRED_ARGUMENT, 'v'], 61 ['visitor-class', Console\GetOption::REQUIRED_ARGUMENT, 'c'], 62 ['token-sequence', Console\GetOption::NO_ARGUMENT, 's'], 63 ['trace', Console\GetOption::NO_ARGUMENT, 't'], 64 ['help', Console\GetOption::NO_ARGUMENT, 'h'], 65 ['help', Console\GetOption::NO_ARGUMENT, '?'] 66 ]; 67 68 69 70 /** 71 * The entry method. 72 * 73 * @return int 74 */ 75 public function main() 76 { 77 $visitor = null; 78 $tokenSequence = false; 79 $trace = false; 80 81 while (false !== $c = $this->getOption($v)) { 82 switch ($c) { 83 case 'v': 84 switch (strtolower($v)) { 85 case 'dump': 86 $visitor = 'Hoa\Compiler\Visitor\Dump'; 87 88 break; 89 90 default: 91 return $this->usage(); 92 } 93 94 break; 95 96 case 'c': 97 $visitor = str_replace('.', '\\', $v); 98 99 break; 100 101 case 's': 102 $tokenSequence = true; 103 104 break; 105 106 case 't': 107 $trace = true; 108 109 break; 110 111 case '__ambiguous': 112 $this->resolveOptionAmbiguity($v); 113 114 break; 115 116 case 'h': 117 case '?': 118 default: 119 return $this->usage(); 120 } 121 } 122 123 $this->parser->listInputs($grammar, $language); 124 125 if (empty($grammar) || (empty($language) && '0' !== $language)) { 126 return $this->usage(); 127 } 128 129 $compiler = Compiler\Llk::load(new File\Read($grammar)); 130 $stream = new File\Read($language); 131 $data = $stream->readAll(); 132 133 try { 134 $ast = $compiler->parse($data); 135 } catch (Compiler\Exception $e) { 136 if (true === $tokenSequence) { 137 $this->printTokenSequence($compiler, $data); 138 echo "\n\n"; 139 } 140 141 throw $e; 142 143 return 1; 144 } 145 146 if (true === $tokenSequence) { 147 $this->printTokenSequence($compiler, $data); 148 echo "\n\n"; 149 } 150 151 if (true === $trace) { 152 $this->printTrace($compiler); 153 echo "\n\n"; 154 } 155 156 if (null !== $visitor) { 157 $visitor = Consistency\Autoloader::dnew($visitor); 158 echo $visitor->visit($ast); 159 } 160 161 return; 162 } 163 164 /** 165 * Print trace. 166 * 167 * @param \Hoa\Compiler\Llk\Parser $compiler Compiler. 168 * @return void 169 */ 170 protected function printTrace(Compiler\Llk\Parser $compiler) 171 { 172 $i = 0; 173 174 foreach ($compiler->getTrace() as $element) { 175 if ($element instanceof Compiler\Llk\Rule\Entry) { 176 $ruleName = $element->getRule(); 177 $rule = $compiler->getRule($ruleName); 178 179 echo str_repeat('> ', ++$i), 'enter ', $ruleName; 180 181 if (null !== $id = $rule->getNodeId()) { 182 echo ' (', $id, ')'; 183 } 184 185 echo "\n"; 186 } elseif ($element instanceof Compiler\Llk\Rule\Token) { 187 echo 188 str_repeat(' ', $i + 1), 189 'token ', $element->getTokenName(), 190 ', consumed ', $element->getValue(), "\n"; 191 } else { 192 echo 193 str_repeat('< ', $i--), 194 'ekzit ', $element->getRule(), "\n"; 195 } 196 } 197 198 return; 199 } 200 201 /** 202 * Print token sequence. 203 * 204 * @param \Hoa\Compiler\Llk\Parser $compiler Compiler. 205 * @param string $data Data to lex. 206 * @return void 207 */ 208 protected function printTokenSequence(Compiler\Llk\Parser $compiler, $data) 209 { 210 $lexer = new Compiler\Llk\Lexer(); 211 $sequence = $lexer->lexMe($data, $compiler->getTokens()); 212 $format = '%' . (strlen((string) count($sequence)) + 1) . 's ' . 213 '%-13s %-20s %s %6s' . "\n"; 214 215 $header = sprintf( 216 $format, 217 '#', 218 'namespace', 219 'token name', 220 'token value ', 221 'offset' 222 ); 223 224 echo $header, str_repeat('-', strlen($header)), "\n"; 225 226 foreach ($sequence as $i => $token) { 227 printf( 228 $format, 229 $i, 230 $token['namespace'], 231 $token['token'], 232 30 < $token['length'] 233 ? mb_substr($token['value'], 0, 29) . '…' 234 : 'EOF' === $token['token'] 235 ? str_repeat(' ', 30) 236 : $token['value'] . 237 str_repeat(' ', 30 - $token['length']), 238 $token['offset'] 239 ); 240 } 241 242 return; 243 } 244 245 /** 246 * The command usage. 247 * 248 * @return int 249 */ 250 public function usage() 251 { 252 echo 253 'Usage : compiler:pp <options> [grammar.pp] [language]', "\n", 254 'Options :', "\n", 255 $this->makeUsageOptionsList([ 256 'v' => 'Visitor name (only “dump” is supported).', 257 'c' => 'Visitor classname (using . instead of \ works).', 258 's' => 'Print token sequence.', 259 't' => 'Print trace.', 260 'help' => 'This help.' 261 ]), "\n"; 262 263 return; 264 } 265} 266 267__halt_compiler(); 268Compile and visit languages with grammars. 269