Jump to content


Photo

PHP Extension Code Generator


  • Please log in to reply
5 replies to this topic

#1 daeken

daeken
  • Members
  • PipPip
  • Member
  • 22 posts
  • LocationChambersburg, PA

Posted 09 November 2003 - 04:56 AM

Well, after about half an hour of work, I have a full rewrite of my skeleton generator. This time, instead of a C header file, you create a function definition file. Example:
int foo(string $bar, int $bleh); Simple function!bool is_even(mixed $var); Checks if a variable is even.

Another notable difference is that it generates full documentation in the C code, and parses parameters. Example output of that above definition file is:
function_entry openal_functions[] = {  ZEND_FE(foo, NULL)  ZEND_FE(is_even, NULL)  {NULL, NULL, NULL}};/* {{{ proto int foo(string bar, int bleh)   Simple function! */PHP_FUNCTION(foo){  char *bar;  int bar_len;  int bleh;  if(ZEND_NUM_ARGS() < 2) WRONG_PARAM_COUNT;  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &bar, &bar_len, &bleh) == FAILURE)    return;}/* {{{ proto bool is_even(mixed var)   Checks if a variable is even. */PHP_FUNCTION(is_even){  zval *var;  if(ZEND_NUM_ARGS() < 1) WRONG_PARAM_COUNT;  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &var) == FAILURE)    return;}

As you can see, this does all the really hard work for you, leading to more efficient extension building :)

And now for the code...
[php:1:7617edc449]
#!/usr/local/bin/php
<?php
if($_SERVER[\'argc\'] < 3)
{
echo \'Usage: \', $_SERVER[\'argv\'][0], \' <extension name> <definition>\', chr(10);
exit;
}
$file = file($_SERVER[\'argv\'][2]);
$defs = array();
foreach($file as $line)
{
$parts = explode(\' \', trim($line));
$arr = array();
$arr[\'return\'] = $parts[0];
$arr[\'name\'] = substr($parts[1], 0, strpos($parts[1], \'(\'));
$arr[\'params\'] = array();
$arr[\'desc\'] = trim(substr($line, strpos($line, \';\') + 1));
$pos = strpos($line, \'(\') + 1;
$line = substr($line, $pos, strrpos($line, \')\') - $pos);
$params = explode(\',\', $line);
foreach($params as $part)
{
list($type, $name) = explode(\' \', trim($part));
$arr[\'params\'][str_replace(\'$\', (string) null, $name)] = $type;
}
$defs[] = $arr;
}
echo \'function_entry \', $_SERVER[\'argv\'][1], \'_functions[] = {\', chr(10);
foreach($defs as $arr)
echo \' ZEND_FE(\', $arr[\'name\'], \', NULL)\', chr(10);
echo \' {NULL, NULL, NULL}\', chr(10), \'};\', chr(10), chr(10), chr(10);
foreach($defs as $arr)
{
echo \'/* {{{ proto \', $arr[\'return\'], \' \', $arr[\'name\'], \'(\';
$i = 0;
foreach($arr[\'params\'] as $name => $type)
{
echo $type, \' \', $name;
if(++$i != count($arr[\'params\']))
echo \', \';
}
echo \')\', chr(10), \' \', $arr[\'desc\'], \' */\', chr(10), \'PHP_FUNCTION(\', $arr[\'name\'], \')\', chr(10), \'{\', chr(10);
$format = (string) null;
$params = (string) null;
$i = 0;
foreach($arr[\'params\'] as $name => $type)
{
switch($type)
{
case \'int\':
echo \' int \', $name, \';\', chr(10);
$format .= \'l\';
$params .= \'&\' . $name;
break;
case \'string\':
echo \' char *\', $name, \';\', chr(10), \' int \', $name, \'_len;\', chr(10);
$format .= \'s\';
$params .= \'&\' . $name . \', &\' . $name . \'_len\';
break;
case \'bool\':
case \'boolean\':
echo \' zend_bool \', $name, \';\', chr(10);
$format .= \'b\';
$params .= \'&\' . $name;
break;
case \'array\':
echo \' zval *\', $name, \';\', chr(10);
$format .= \'a\';
$params .= \'&\' . $name;
break;
case \'mixed\':
case \'resource\':
echo \' zval *\', $name, \';\', chr(10);
$format .= \'z\';
$params .= \'&\' . $name;
break;
case \'object\':
echo \' zval *\', $name, \';\', chr(10);
$format .= \'o\';
$params .= \'&\' . $name;
break;
case \'double\':
case \'float\':
echo \' double \', $name, \';\', chr(10);
$format .= \'d\';
$params .= \'&\' . $name;
break;
}
if(++$i != count($arr[\'params\']))
$params .= \', \';
}
echo \' if(ZEND_NUM_ARGS() < \', count($arr[\'params\']), \') WRONG_PARAM_COUNT;\', chr(10), \' if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, \"\', $format, \'\", \', $params, \') == FAILURE)\', chr(10), \' return;\', chr(10), \'}\', chr(10), chr(10);
}
?>
[/php:1:7617edc449]

Have fun :)

Happy hacking,
Lord Daeken M. BlackBlade
(Cody Brocious)
Black and white are all I see in my infancy.

#2 Derek

Derek
  • Members
  • PipPipPip
  • Advanced Member
  • 31 posts
  • LocationTennessee

Posted 09 November 2003 - 05:09 AM

great! this will cut the time of developing extensions by 1/4, atleast :)

idea:

int foo(string $bar, int $bleh[, string my_optional_var]);

function comment(s)

{

	if (i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
   return  	} else {    return s  	}  }
ext/skeleton/create_stubs, lines 40-47. - PHP Core

#3 daeken

daeken
  • Members
  • PipPip
  • Member
  • 22 posts
  • LocationChambersburg, PA

Posted 09 November 2003 - 06:38 AM

New version, new parser, and a new feature: optional parameters.

#!/usr/local/bin/php<?phpif($_SERVER[\'argc\'] < 3){  echo \'Usage: \', $_SERVER[\'argv\'][0], \' <extension name> <definition>\', chr(10);  exit;}$file = file($_SERVER[\'argv\'][2]);$defs = array();foreach($file as $line){  $parts = explode(\' \', trim($line));  $arr = array();  $arr[\'return\'] = $parts[0];  $arr[\'name\'] = substr($parts[1], 0, strpos($parts[1], \'(\'));  $arr[\'params\'] = array();  $arr[\'desc\'] = trim(substr($line, strpos($line, \';\') + 1));  $pos = strpos($line, \'(\') + 1;  $line = trim(substr($line, $pos, strrpos($line, \')\') - $pos));  $last = 0;  $opt = false;  preg_match_all(\'/([|])?[s]*(.+?)[s]+$([^s[],=]+)[s]*=?[s]*([^s[]]*)[s]*([|])*,?[s]*/\', $line, $matches);  for($i = 0; $i < count($matches[0]); ++$i)  {    $type = $matches[2][$i];    $name = $matches[3][$i];    $def = $matches[4][$i];    if($matches[1][$i] == \'[\')      $opt = $tempopt = true;    elseif($matches[5][$i] == \'[\')      $tempopt = true;    elseif($matches[5][$i] == \']\' || empty($matches[5][$i]))      $tempopt = false;    $arr[\'params\'][$name] = array($type, $opt, $def);    $opt = $tempopt;  }  $defs[] = $arr;}echo \'function_entry \', $_SERVER[\'argv\'][1], \'_functions[] = {\', chr(10);foreach($defs as $arr)  echo \'  ZEND_FE(\', $arr[\'name\'], \', NULL)\', chr(10);echo \'  {NULL, NULL, NULL}\', chr(10), \'};\', chr(10), chr(10), chr(10);foreach($defs as $arr){  echo \'/* {{{ proto \', $arr[\'return\'], \' \', $arr[\'name\'], \'(\';  $i = 0;  $optcount = 0;  foreach($arr[\'params\'] as $name => $temp)  {    list($type, $opt, $default) = $temp;    if(!$opt)    {      echo str_repeat(\']\', $optcount);      $optcount = 0;    }    if($opt)    {      if($i != 0)        echo \' \';      echo \'[\';      ++$optcount;    }    if(++$i > 1)      echo \', \';    echo $type, \' \', $name;    if($opt && !empty($default))      echo \' = \', $default;  }  echo str_repeat(\']\', $optcount);  echo \')\', chr(10), \'   \', $arr[\'desc\'], \' */\', chr(10), \'PHP_FUNCTION(\', $arr[\'name\'], \')\', chr(10), \'{\', chr(10);  $format = (string) null;  $params = (string) null;  $i = 0;  foreach($arr[\'params\'] as $name => $temp)  {    list($type, $opt, $default) = $temp;    switch($type)    {    case \'int\':      echo \'  int \', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = 0\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'l\';      $params .= \'&\' . $name;      break;    case \'string\':      echo \'  char *\', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = NULL\';      echo \';\', chr(10), \'  int \', $name, \'_len\';      if($opt && !empty($default))        echo \' = \', strlen($default) - 2;      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'s\';      $params .= \'&\' . $name . \', &\' . $name . \'_len\';      break;    case \'bool\':    case \'boolean\':      echo \'  zend_bool \', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = FALSE\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'b\';      $params .= \'&\' . $name;      break;    case \'array\':      echo \'  zval *\', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = NULL\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'a\';      $params .= \'&\' . $name;      break;    case \'mixed\':    case \'resource\':      echo \'  zval *\', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = NULL\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'z\';      $params .= \'&\' . $name;      break;    case \'object\':      echo \'  zval *\', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = NULL\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'o\';      $params .= \'&\' . $name;      break;    case \'double\':    case \'float\':      echo \'  double \', $name;      if($opt && !empty($default))        echo \' = \', $default;      elseif($opt)        echo \' = 0\';      echo \';\', chr(10);      if($opt)        $format .= \'|\';      $format .= \'d\';      $params .= \'&\' . $name;      break;    }    if(++$i != count($arr[\'params\']))      $params .= \', \';  }  $need = 0;  foreach($arr[\'params\'] as $name => $temp)  {    if(!$temp[1])      ++$need;  }  echo \'  if(ZEND_NUM_ARGS() < \', $need, \') WRONG_PARAM_COUNT;\', chr(10), \'  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "\', $format, \'", \', $params, \') == FAILURE)\', chr(10), \'    return;\', chr(10), \'}\', chr(10), chr(10);}?>

Example definition:
int foo(string $bar[, int $bleh]); Simple function!bool is_even([mixed $var = 5]); Checks if a variable is even.

Output:
function_entry openal_functions[] = {  ZEND_FE(foo, NULL)  ZEND_FE(is_even, NULL)  {NULL, NULL, NULL}};/* {{{ proto int foo(string bar [, int bleh])   Simple function! */PHP_FUNCTION(foo){  char *bar;  int bar_len;  int bleh = 0;  if(ZEND_NUM_ARGS() < 1) WRONG_PARAM_COUNT;  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &bar, &bar_len, &bleh) == FAILURE)    return;}/* {{{ proto bool is_even([mixed var = 5])   Checks if a variable is even. */PHP_FUNCTION(is_even){  zval *var = 5;  if(ZEND_NUM_ARGS() < 0) WRONG_PARAM_COUNT;  if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|z", &var) == FAILURE)    return;}

Have fun!

Happy hacking,
Lord Daeken M. BlackBlade
(Cody Brocious)
Black and white are all I see in my infancy.

#4 metalblend

metalblend
  • Members
  • PipPipPip
  • Advanced Member
  • 89 posts
  • LocationCalifornia, USA

Posted 09 November 2003 - 10:10 AM

..had to edit that and change to CODE tags.

phpBB\'s PHP tags destroy & and && operators :(

#5 daeken

daeken
  • Members
  • PipPip
  • Member
  • 22 posts
  • LocationChambersburg, PA

Posted 09 November 2003 - 03:31 PM

Ah, thanks.
Black and white are all I see in my infancy.

#6 Derek

Derek
  • Members
  • PipPipPip
  • Advanced Member
  • 31 posts
  • LocationTennessee

Posted 09 November 2003 - 04:40 PM

great :)
function comment(s)

{

	if (i_know_what_to_do_shut_up_i_dont_need_your_help_mode) {
   return  	} else {    return s  	}  }
ext/skeleton/create_stubs, lines 40-47. - PHP Core




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users