diff --git a/examples/c/nfft.cc b/examples/c/nfft.cc new file mode 100644 index 00000000..4b6489f9 --- /dev/null +++ b/examples/c/nfft.cc @@ -0,0 +1,36 @@ +#include +#include +#include + +int main() { + const int d = 1; // 维度(1D) + const int M = 1000; // 非均匀点数量 + const int N[] = {2048}; // 均匀网格大小(频域) + + // 分配内存 + nfft_plan plan; + nfft_init_1d(&plan, N[0], M); + + // 设置非均匀采样点 x_j ∈ [-0.5, 0.5) + for (int j = 0; j < M; ++j) { + plan.x[j] = (double)j / M - 0.5; // 示例:均匀分布,实际可任意 + } + + // 设置源系数 c_j(复数) + for (int j = 0; j < M; ++j) { + plan.f_hat[j][0] = 1.0; // 实部 + plan.f_hat[j][1] = 0.0; // 虚部 + } + + // 执行 NFFT(Type 1) + nfft_adjoint(&plan); // 注意:NFFT3 中 Type 1 用 nfft_adjoint! + + // 输出部分结果 + for (int k = 0; k < 10; ++k) { + std::cout << "f[" << k << "] = " << plan.f[k] << std::endl; + } + + // 清理 + nfft_finalize(&plan); + return 0; +} \ No newline at end of file diff --git a/examples/call.php b/examples/call.php deleted file mode 100644 index 338c62cd..00000000 --- a/examples/call.php +++ /dev/null @@ -1,16 +0,0 @@ -rootPath = $rootPath; + $this->parser = (new ParserFactory())->createForNewestSupportedVersion(); + // $this->prettyPrinter = new PrettyPrinter\Standard; $this->setBuildDir($rootPath . '/build'); $climate = new CLImate; $this->climate = $climate; @@ -278,27 +286,33 @@ class Translator extends \PhpAot\Core\Translator private function doConvert(string $phpCode): string { $this->climate->info('convert: ' . $this->file); - $parser = (new ParserFactory())->createForNewestSupportedVersion(); - $ast = $parser->parse($phpCode); + $ast = $this->parser->parse($phpCode); $traverser = new NodeTraverser; - $prettyPrinter = new PrettyPrinter\Standard; - $traverser->addVisitor(new Visitor()); + $stmts = $traverser->traverse($ast); $this->indentLevel = 0; + $this->strictTypes = false; + $this->resetNamespace(); $cppCode = ''; foreach($stmts as $v) { $type = $v->getType(); switch ($type) { + case 'Stmt_Declare': + $this->parseDeclare($v); + break; case 'Stmt_Namespace': $cppCode .= $this->parseNamespaceDef($v); break; case 'Stmt_Class': $cppCode .= $this->parseClassDef($v); break; + case 'Stmt_Use': + $cppCode .= $this->parseUse($v) . PHP_EOL; + break; case 'Stmt_Function': $cppCode .= $this->parseFunctionDef($v) . PHP_EOL; break; @@ -388,6 +402,13 @@ class Translator extends \PhpAot\Core\Translator $this->tmpVarIndex = 0; } + private function resetNamespace() + { + $this->useNamespaces = []; + $this->useFunctions = []; + $this->namespace = ''; + } + private function getFunctionName(Node $v): string { $names[] = $this->parseIdentifier($v->name); @@ -395,7 +416,7 @@ class Translator extends \PhpAot\Core\Translator $names[] = strtolower($this->class); } if ($this->namespace) { - $names[] = strtolower(str_replace('\\', '_', $this->namespace)); + $names[] = $this->escapeNamespace($this->namespace); } return implode('__', array_reverse($names)); } @@ -1161,7 +1182,7 @@ class Translator extends \PhpAot\Core\Translator return $out; } - private function parseLibs() + private function parseLibs(): string { $list = [ 'phpx', @@ -1411,21 +1432,45 @@ class Translator extends \PhpAot\Core\Translator return $this->parseBinaryOp($expr->left, $expr->right, '%'); } - private function parseFuncCall(mixed $expr): string + /** + * 查找原生函数 + * @param string $fname + * @return bool + */ + private function findNativeFunction(string $fname): string|false { - if ($expr->name->getType() === self::EXPR_VARIABLE) { - $fn = $this->parseIdentifier($expr->name); - $name = ''; - } elseif ($expr->name->getType() === 'Name') { - $name = $this->parseIdentifier($expr->name); + $possibleFunctionNames = [$fname,]; + if ($this->namespace) { + $possibleFunctionNames[] = $this->namespace . '__' . $fname; + } + if (isset($this->useFunctions[$fname])) { + $possibleFunctionNames[] = $this->escapeNamespace($this->useFunctions[$fname]) . '__' . $fname; + } + foreach($possibleFunctionNames as $name) { // 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误 if (isset($this->functionDeclInFile[$name]) and $this->functionDeclInFile[$name] === $this->file and !$this->isNativeFunction($name)) { $this->redoAfterDeclare[$name] = true; + return $name; } if ($this->isNativeFunction($name)) { - return self::PREFIX . $name . '(' . $this->parseCallArgs($expr->args, $name) . ')'; + return $name; + } + } + return false; + } + + private function parseFuncCall(mixed $expr): string + { + if ($expr->name->getType() === self::EXPR_VARIABLE) { + $fn = $this->parseIdentifier($expr->name); + $name = ''; + } elseif ($expr->name->getType() === 'Name') { + $name = $this->parseIdentifier($expr->name); + $nativeFn = $this->findNativeFunction($name); + if ($nativeFn) { + return self::PREFIX . $nativeFn . '(' . $this->parseCallArgs($expr->args, $name) . ')'; } if ($this->isInternalFunction($name)) { $fn = 'php::' . $name; @@ -1817,8 +1862,26 @@ class Translator extends \PhpAot\Core\Translator private function parseNamespaceDef(Node $node): string { - $this->namespace = $this->parseIdentifier($node->name); + $ns = $this->parseIdentifier($node->name); $code = ''; + + $this->resetNamespace(); + + if ($this->useCppNamespace) { + $ns = explode('\\', $ns); + $ns = array_filter($ns, function ($v) { + return $v !== ''; + }); + foreach ($ns as $name) { + $code .= 'namespace ' . $name . ' {' . PHP_EOL; + } + $ns_end = str_repeat('}', count($ns)); + $this->namespace = implode('::', $ns); + } else { + $this->namespace = $this->escapeNamespace($node->name->toString()); + $ns_end = ''; + } + foreach($node->stmts as $v2) { $type2 = $v2->getType(); switch ($type2) { @@ -1832,16 +1895,14 @@ class Translator extends \PhpAot\Core\Translator $code .= $this->parseFunctionDef($v2) . PHP_EOL; break; case 'Stmt_Use': - foreach ($v2->uses as $use) { - $this->uses[] = $use->name->toString(); - } + $code .= $this->parseUse($v2) . PHP_EOL; break; default: abort($v2); } } - $this->namespace = ''; - $this->uses = []; + $code .= $ns_end; + $this->resetNamespace(); return $code; } @@ -1952,6 +2013,11 @@ class Translator extends \PhpAot\Core\Translator } } + private function escapeNamespace(string $ns): string + { + return str_replace('\\', '__', strtolower($ns)); + } + private function unescapeVarName(string $name): string { return str_replace('_php__var__', '', $name); @@ -2666,16 +2732,14 @@ class Translator extends \PhpAot\Core\Translator } } - public function prepare(string $file) + public function prepare(string $file): void { $phpCode = $this->loadFile($file); $this->climate->info('prepare: ' . $this->file); - $parser = (new ParserFactory())->createForNewestSupportedVersion(); - $ast = $parser->parse($phpCode); + $ast = $this->parser->parse($phpCode); $traverser = new NodeTraverser; - $prettyPrinter = new PrettyPrinter\Standard; $traverser->addVisitor(new Visitor()); $stmts = $traverser->traverse($ast); @@ -2691,6 +2755,8 @@ class Translator extends \PhpAot\Core\Translator case 'Stmt_Function': $this->prepareFunctionDef($v) . PHP_EOL; break; + case 'Stmt_Declare': + case 'Stmt_Use': case 'Stmt_Const': break; default: @@ -2726,8 +2792,9 @@ class Translator extends \PhpAot\Core\Translator private function prepareNamespaceDef(Node $node): void { - $this->namespace = $this->parseIdentifier($node->name); - foreach($node->stmts as $v2) { + $this->resetNamespace(); + $this->namespace = $this->escapeNamespace($this->parseIdentifier($node->name)); + foreach ($node->stmts as $v2) { $type2 = $v2->getType(); switch ($type2) { case 'Stmt_Class': @@ -2743,8 +2810,7 @@ class Translator extends \PhpAot\Core\Translator abort($v2); } } - $this->namespace = ''; - $this->uses = []; + $this->resetNamespace(); } private function prepareClassDef(Node $v): string @@ -2791,6 +2857,11 @@ class Translator extends \PhpAot\Core\Translator return str_ends_with($file, '.stub.php'); } + /** + * @param string $file + * @return string + * @throws \Exception + */ private function loadFile(string $file): string { if (!file_exists($file)) { @@ -2826,4 +2897,45 @@ class Translator extends \PhpAot\Core\Translator { return $this->buildDir; } + + private function parseDeclare(mixed $v): void + { + $declares = $v->declares; + foreach ($declares as $declare) { + $key = $this->parseIdentifier($declare->key); + $value = $this->parseIdentifier($declare->value); + if ($key === 'ticks') { + $this->fatalError($v, 'declare(ticks=1) is not supported'); + } elseif ($key === 'encoding') { + if (strtolower($value) !== 'utf-8') { + $this->fatalError($v, 'declare(encoding="' . $value . '") is not supported, only UTF-8 is supported'); + } + } + $this->strictTypes = boolval(intval($value)); + } + } + + private function parseUse(mixed $v2): string + { + $code = ''; + if ($this->useCppNamespace) { + foreach ($v2->uses as $use) { + $code .= 'using ' . str_replace('\\', '::', $use->name->toString()) . ';' . PHP_EOL; + } + } else { + foreach ($v2->uses as $use) { + $id = $this->parseIdentifier($use->name); + if ($use->type == Node\Stmt\Use_::TYPE_NORMAL) { + $this->useNamespaces[] = $id; + } else { + $rpos = strrpos($id, '\\'); + $fn = substr($id, $rpos + 1); + $ns = substr($id, 0, $rpos); + // fn => namespace + $this->useFunctions[$fn] = $ns; + } + } + } + return $code; + } }