1<?php declare(strict_types=1); 2 3require __DIR__ . '/phpyLang.php'; 4 5$parserToDefines = [ 6 'Php7' => ['PHP7' => true], 7 'Php8' => ['PHP8' => true], 8]; 9 10$grammarFile = __DIR__ . '/php.y'; 11$skeletonFile = __DIR__ . '/parser.template'; 12$tmpGrammarFile = __DIR__ . '/tmp_parser.phpy'; 13$tmpResultFile = __DIR__ . '/tmp_parser.php'; 14$resultDir = __DIR__ . '/../lib/PhpParser/Parser'; 15 16$kmyacc = getenv('KMYACC'); 17if (!$kmyacc) { 18 // Use phpyacc from dev dependencies by default. 19 $kmyacc = __DIR__ . '/../vendor/bin/phpyacc'; 20} 21 22$options = array_flip($argv); 23$optionDebug = isset($options['--debug']); 24$optionKeepTmpGrammar = isset($options['--keep-tmp-grammar']); 25 26/////////////////// 27/// Main script /// 28/////////////////// 29 30foreach ($parserToDefines as $name => $defines) { 31 echo "Building temporary $name grammar file.\n"; 32 33 $grammarCode = file_get_contents($grammarFile); 34 $grammarCode = replaceIfBlocks($grammarCode, $defines); 35 $grammarCode = preprocessGrammar($grammarCode); 36 37 file_put_contents($tmpGrammarFile, $grammarCode); 38 39 $additionalArgs = $optionDebug ? '-t -v' : ''; 40 41 echo "Building $name parser.\n"; 42 $output = execCmd("$kmyacc $additionalArgs -m $skeletonFile -p $name $tmpGrammarFile"); 43 44 $resultCode = file_get_contents($tmpResultFile); 45 $resultCode = removeTrailingWhitespace($resultCode); 46 47 ensureDirExists($resultDir); 48 file_put_contents("$resultDir/$name.php", $resultCode); 49 unlink($tmpResultFile); 50 51 if (!$optionKeepTmpGrammar) { 52 unlink($tmpGrammarFile); 53 } 54} 55 56//////////////////////////////// 57/// Utility helper functions /// 58//////////////////////////////// 59 60function ensureDirExists($dir) { 61 if (!is_dir($dir)) { 62 mkdir($dir, 0777, true); 63 } 64} 65 66function execCmd($cmd) { 67 $output = trim(shell_exec("$cmd 2>&1") ?? ''); 68 if ($output !== "") { 69 echo "> " . $cmd . "\n"; 70 echo $output; 71 } 72 return $output; 73} 74 75function replaceIfBlocks(string $code, array $defines): string { 76 return preg_replace_callback('/\n#if\s+(\w+)\n(.*?)\n#endif/s', function ($matches) use ($defines) { 77 $value = $defines[$matches[1]] ?? false; 78 return $value ? $matches[2] : ''; 79 }, $code); 80} 81