pull/1/head
韩天峰 8 months ago
parent 2654e6f39b
commit bf83ceee87
  1. 2
      bin/compiler.php
  2. 33
      examples/leibniz.cpp
  3. 20
      examples/pi.php
  4. 19
      main.cc
  5. 3
      main.php
  6. 1
      rounds.txt
  7. 133
      src/Php/Translator.php

@ -19,7 +19,7 @@ try {
$info = pathinfo($file);
$cppFile = './tmp/' . $info['filename'] . '.cc';
$translator->save($code, $cppFile);
// $translator->compileFile($cppFile);
$translator->compileFile($cppFile);
} catch (Error $error) {
echo "Parse error: {$error->getMessage()}\n";
return;

@ -0,0 +1,33 @@
#include <cstdio>
#include <cstdlib>
unsigned rounds;
double pi = 1.0;
int main()
{
auto infile = std::fopen("rounds.txt", "r"); // open file
if (infile == NULL) {
perror("open file");
return EXIT_FAILURE;
}
if (std::fscanf(infile, "%u", &rounds) != 1) { // read from file
perror("read file");
return EXIT_FAILURE;
}
std::fclose(infile); // close file
rounds += 2u; // do this outside the loop
for (long i=2u ; i < rounds ; ++i) // use ++i instead of i++
{
double x = -1.0 + 2.0 * (i & 0x1); // allows vectorization
pi += (x / (2u * i - 1u)); // double / unsigned = double
}
pi *= 4;
std::printf("%.16f\n", pi); // print 16 decimal digits of pi
return EXIT_SUCCESS;
}

@ -0,0 +1,20 @@
<?php
function main()
{
ini_set("precision", 17);
$rounds = (int)file_get_contents("./rounds.txt", true);
$stop = $rounds + 2;
var_dump($stop);
$begin = microtime(true);
$x = 1.0;
$pi = 1.0;
for ($i = 2; $i <= $stop; $i++) {
$x = -1.0 + 2.0 * ($i & 0x1);
$pi += $x / (2 * $i - 1);
}
$pi *= 4.0;
print $pi . "\ntime: " . (microtime(true) - $begin) . "\n";
}

@ -0,0 +1,19 @@
#include "sapi/embed/php_embed.h"
#include <phpx.h>
void php_main();
int main(int argc, char **argv) {
php_embed_init(argc, argv);
int rc = 0;
zend_first_try {
php_main();
}
zend_catch {
rc = EG(exit_status);
}
zend_end_try();
php_embed_shutdown();
return rc;
}

@ -0,0 +1,3 @@
<?php
include __DIR__ . '/examples/pi.php';
main();

@ -0,0 +1 @@
100000000

@ -13,24 +13,31 @@ use PhpParser\PrettyPrinter;
class Translator extends \PhpAot\Core\Translator
{
protected string $phpxDir = '~/workspace/phpx';
const TYPE_VAR = 'php::Variant';
const TYPE_INT = 'php::Int';
const TYPE_FLOAT = 'php::Float';
protected string $phpxDir = '~/workspace/projects/phpx';
protected string $lang = 'PHP';
protected array $typeMap = [];
protected array $zendTypeMap = [
'int' => 'php::Int',
'float' => 'php::Float',
'int' => self::TYPE_INT,
'float' => self::TYPE_FLOAT,
'bool' => 'bool',
];
protected array $headers = [
'phpx.h',
];
protected int $optimizeLevel = 5;
protected string $namespace = '';
protected array $uses = [];
protected string $class = '';
const PREFIX = 'php_';
public function __construct()
{
}
@ -98,6 +105,11 @@ class Translator extends \PhpAot\Core\Translator
return $node->getType();
}
protected function getDetectedType($name)
{
return $this->typeMap[$name] ?? 'php::Variant';
}
public function getZendType(string $type): string
{
return $this->zendTypeMap[$type] ?? 'zval *';
@ -118,7 +130,7 @@ class Translator extends \PhpAot\Core\Translator
if ($v->returnType) {
$returnType = $this->getZendType($this->parseIdentifier($v->returnType));
} else {
$returnType = 'php::Variant';
$returnType = 'void';
}
$params = $this->parseParams($v->params);
@ -137,7 +149,7 @@ class Translator extends \PhpAot\Core\Translator
echo $msg . PHP_EOL;
}
protected function parseIdentifier($expr)
protected function parseIdentifier(Node $expr)
{
$type = $expr->getType();
switch ($type) {
@ -146,10 +158,11 @@ class Translator extends \PhpAot\Core\Translator
case 'Expr_Variable':
return $expr->name;
case 'Scalar_Int':
case 'Scalar_Float':
return $expr->value;
case 'Scalar_Float':
return $expr->getAttribute('rawValue');
case 'Scalar_String':
return '"' . str_replace("\n", '\n', $expr->value) . '"';
return '"' . $this->escapeString($expr->value) . '"';
default:
return $this->parseExpr($expr);
}
@ -172,7 +185,7 @@ class Translator extends \PhpAot\Core\Translator
$lines = [];
foreach ($stmts as $v) {
$class = $v->getType();
$this->writeLog('Line ' . $this->getLine($v) . ': ' . $class);
// $this->writeLog('Line ' . $this->getLine($v) . ': ' . $class);
switch ($class) {
case 'Stmt_Expression':
$lines[] = $this->parseExpr($v->expr) . ';';
@ -230,6 +243,8 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseBooleanNot($expr);
case 'Expr_BinaryOp_Plus':
return $this->parseBinaryOpPlus($expr);
case 'Expr_BinaryOp_Div':
return $this->parseBinaryOpDiv($expr);
case 'Expr_BinaryOp_Smaller':
return $this->parseBinaryOpSmaller($expr);
case 'Expr_BinaryOp_SmallerOrEqual':
@ -268,6 +283,8 @@ class Translator extends \PhpAot\Core\Translator
return $this->parseBinaryOpLogicalOr($expr);
case 'Expr_BinaryOp_LogicalXor':
return $this->parseBinaryOpLogicalXor($expr);
case 'Expr_BinaryOp_Minus':
return $this->parseBinaryOpMinus($expr);
case 'Expr_Array':
return $this->parseArray($expr);
case 'Expr_ArrayDimFetch':
@ -303,6 +320,16 @@ class Translator extends \PhpAot\Core\Translator
case 'Scalar_String':
case 'Expr_Variable':
return $this->parseIdentifier($expr);
case 'Scalar_InterpolatedString':
return $this->parseInterpolatedString($expr);
case 'Expr_Cast_Int':
return $this->parseCastInt($expr);
case 'Expr_ConstFetch':
return $this->parseConstFetch($expr);
case 'Expr_UnaryMinus':
return $this->parseUnaryMinus($expr);
case 'InterpolatedStringPart':
return $this->parseInterpolatedStringPart($expr);
default:
debug($expr);
}
@ -347,7 +374,7 @@ class Translator extends \PhpAot\Core\Translator
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' * ' . $right;
return '(' . $left . ') * (' . $right . ')';
}
private function detectType($var, $expr): string
@ -440,19 +467,20 @@ class Translator extends \PhpAot\Core\Translator
return $out;
}
public function compileFile($file)
public function compileFile($file): void
{
$cmd = 'g++ -c ' . $file . ' -o ' . $file . '.o ' . $this->parseIncludes() . $this->parseLdflags() . $this->parseLibs();
$cmd .= ' -O' . $this->optimizeLevel;
echo $cmd . PHP_EOL;
shell_exec($cmd);
}
private function parseBinaryOpConcat(mixed $expr)
private function parseBinaryOpConcat(mixed $expr): string
{
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return 'concat(' . $left . ', ' . $right . ')';
return 'php::concat(' . $left . ', ' . $right . ')';
}
private function parseFor(mixed $v): string
@ -510,7 +538,7 @@ class Translator extends \PhpAot\Core\Translator
private function parseAssignOpPlus(mixed $expr): string
{
$var = $this->parseIdentifier($expr->var);
return $var . ' += ' . $this->parseIdentifier($expr->expr);
return $var . ' += (' . $this->parseIdentifier($expr->expr) . ')';
}
private function parseArrayDimFetch($node): string
@ -520,7 +548,7 @@ class Translator extends \PhpAot\Core\Translator
return $var . '[' . $dim . ']';
}
private function parseBinaryOpShiftLeft($node)
private function parseBinaryOpShiftLeft($node): string
{
$left = $this->parseIdentifier($node->left);
$right = $this->parseIdentifier($node->right);
@ -528,7 +556,7 @@ class Translator extends \PhpAot\Core\Translator
return $left . ' << ' . $right;
}
private function parseBinaryOpShiftRight($node)
private function parseBinaryOpShiftRight($node): string
{
$left = $this->parseIdentifier($node->left);
$right = $this->parseIdentifier($node->right);
@ -565,9 +593,9 @@ class Translator extends \PhpAot\Core\Translator
{
$name = $this->parseIdentifier($expr->name);
if (empty($expr->args)) {
return 'php::exec("' . $name . '")';
return 'php::call("' . $name . '")';
} else {
return 'php::exec("' . $name . '", ' . $this->parseArgs($expr->args) . ')';
return 'php::call("' . $name . '", {' . $this->parseArgs($expr->args) . '})';
}
}
@ -752,12 +780,28 @@ class Translator extends \PhpAot\Core\Translator
return $code;
}
private function optimizeBinaryOpCompare(string $left, string $right, string $op): string
{
if ($this->getDetectedType($left) == self::TYPE_INT and $this->getDetectedType($right) == self::TYPE_VAR) {
return $left . ' ' . $op . ' ' . $right . '.toInt()';
}
if ($this->getDetectedType($left) == self::TYPE_FLOAT and $this->getDetectedType($right) == self::TYPE_VAR) {
return $left . ' ' . $op . ' ' . $right . '.toFloat()';
}
return '';
}
private function parseBinaryOpSmallerOrEqual(Node $expr): string
{
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' <= ' . $right;
$optimized = $this->optimizeBinaryOpCompare($left, $right, '<=');
if (!$optimized) {
return $left . ' <= ' . $right;
} else {
return $optimized;
}
}
private function parseBinaryOpGreaterOrEqual(Node $expr): string
@ -859,4 +903,57 @@ class Translator extends \PhpAot\Core\Translator
$this->class = '';
return $code;
}
private function parseCastInt(Node $node): string
{
$code = $this->parseExpr($node->expr);
return '(' . $code . ').toInt()';
}
private function parseConstFetch(Node $expr)
{
return $this->parseIdentifier($expr->name);
}
private function parseUnaryMinus(Node $expr): string
{
$code = $this->parseExpr($expr->expr);
return '-' . $code;
}
private function parseBinaryOpDiv(Node $expr): string
{
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' / (' . $right . ')';
}
private function parseBinaryOpMinus(Node $expr): string
{
$left = $this->parseIdentifier($expr->left);
$right = $this->parseIdentifier($expr->right);
return $left . ' - (' . $right . ')';
}
private function parseInterpolatedString(Node $expr): string
{
$parts = $expr->parts;
$list = [];
foreach ($parts as $part) {
$list[] = $this->parseExpr($part);
}
return 'php::concat({' . implode(', ', $list) . '})';
}
private function escapeString($str): string
{
$search = ["\n", "\r", "\t", "\""];
$replace = ['\n', '\r', '\t', '\"'];
return str_replace($search, $replace, $str);
}
private function parseInterpolatedStringPart(Node $expr): string
{
return '"' . $this->escapeString($expr->value) . '"';
}
}

Loading…
Cancel
Save