Author Topic: PHP Extension Code Generator  (Read 6508 times)

0 Members and 1 Guest are viewing this topic.

Offline daekenTopic starter

  • Enthusiast
  • Posts: 54
    • View Profile
    • http://www.alleykatsoft.com/
PHP Extension Code Generator
« on: November 08, 2003, 11:56:14 PM »
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:
Code: [Select]

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:
Code: [Select]

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.

Offline Derek

  • Enthusiast
  • Posts: 398
    • View Profile
    • http://Shadowed.asleep.net
PHP Extension Code Generator
« Reply #1 on: November 09, 2003, 12:09:01 AM »
great! this will cut the time of developing extensions by 1/4, atleast :)

idea:

Code: [Select]

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

                   
Code: [Select]
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

Offline daekenTopic starter

  • Enthusiast
  • Posts: 54
    • View Profile
    • http://www.alleykatsoft.com/
PHP Extension Code Generator
« Reply #2 on: November 09, 2003, 01:38:11 AM »
New version, new parser, and a new feature: optional parameters.

Code: [Select]
#!/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:
Code: [Select]

int foo(string $bar[, int $bleh]); Simple function!

bool is_even([mixed $var = 5]); Checks if a variable is even.



Output:
Code: [Select]

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.

Offline metalblend

  • Devotee
  • Posts: 885
    • View Profile
    • http://www.phirebrush.com
PHP Extension Code Generator
« Reply #3 on: November 09, 2003, 05:10:10 AM »
..had to edit that and change to CODE tags.

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

Offline daekenTopic starter

  • Enthusiast
  • Posts: 54
    • View Profile
    • http://www.alleykatsoft.com/
PHP Extension Code Generator
« Reply #4 on: November 09, 2003, 10:31:15 AM »
Ah, thanks.                    
Black and white are all I see in my infancy.

Offline Derek

  • Enthusiast
  • Posts: 398
    • View Profile
    • http://Shadowed.asleep.net
PHP Extension Code Generator
« Reply #5 on: November 09, 2003, 11:40:38 AM »
great :)                    
Code: [Select]
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