Jump to content

PHP Extension Code Generator


daeken

Recommended Posts

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)

Link to post
Share on other sites

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

 

#!/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 = 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)

Link to post
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.