Advertisement
snake5

simple interpreter in PHP

Mar 30th, 2012
249
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 6.26 KB | None | 0 0
  1. <?php
  2.  
  3. define( '_SPADDING', '    ' );
  4. function _spad( $data )
  5. {
  6.     return str_replace( "\n", "\n" . _SPADDING, $data );
  7. }
  8. function _sdumpa( $data )
  9. {
  10.     $out = "";
  11.     foreach( $data as $k => $v )
  12.         $out .= "\n" . _SPADDING . "$k=" . _spad( _sdump( $v ) );
  13.     return $out;
  14. }
  15. function _sdump( $data )
  16. {
  17.     if( is_object( $data ) )
  18.     {
  19.         $type = get_class( $data );
  20.         return "($type)" . _sdumpa( (array) $data );
  21.     }
  22.     if( is_array( $data ) )
  23.         return "(Array)" . _sdumpa( $data );
  24.     else
  25.         return $data;
  26. }
  27. function struct_dump( $data )
  28. {
  29.     echo "<pre>";
  30.     echo _sdump( $data );
  31.     echo "</pre>";
  32. }
  33. function hdr( $h )
  34. {
  35.     echo "<h3>$h</h3>";
  36. }
  37.  
  38.  
  39. $code =
  40. "
  41. set( 'x', add( 3, mul( 4, 5 ) ) );\n
  42. print( get( 'x' ) );
  43. ";
  44.  
  45. hdr( "Code" );
  46. echo "<pre>$code</pre>";
  47.  
  48.  
  49. $tokens = array();
  50.  
  51. function crtok( $type, $data )
  52. {
  53.     return (object) array( "type" => $type, "data" => $data );
  54. }
  55.  
  56. $codelen = strlen( $code );
  57. for( $i = 0; $i < $codelen; ++$i )
  58. {
  59.     $fc = $code[ $i ];
  60.     // whitespace
  61.     if( strpos( " \n\r\t", $fc ) !== false )
  62.         continue;
  63.    
  64.     // special symbol
  65.     if( strpos( "(,);", $fc ) !== false )
  66.     {
  67.         $tokens[] = crtok( "spec", $fc );
  68.     }
  69.    
  70.     // identifier
  71.     if( ctype_alpha( $fc ) )
  72.     {
  73.         $name = '';
  74.         while( $i < $codelen && ctype_alnum( $code[ $i ] ) )
  75.             $name .= $code[ $i++ ];
  76.         $tokens[] = crtok( "ident", $name );
  77.         $i--;
  78.         continue;
  79.     }
  80.    
  81.     // number
  82.     if( ctype_digit( $fc ) )
  83.     {
  84.         $num = "";
  85.         while( $i < $codelen && ctype_digit( $code[ $i ] ) )
  86.             $num .= $code[ $i++ ];
  87.         $tokens[] = crtok( "number", $num );
  88.         $i--;
  89.         continue;
  90.     }
  91.    
  92.     // string
  93.     if( strpos( "\'\"", $fc ) !== false )
  94.     {
  95.         $i++;
  96.         $string = "";
  97.         $escaped = false;
  98.         while( $i < $codelen )
  99.         {
  100.             if( $code[ $i ] == '\\' )
  101.                 $escaped = !$escaped;
  102.             else
  103.                 $escaped = false;
  104.             if( $code[ $i ] == $fc && !$escaped )
  105.                 break;
  106.             $string .= $code[ $i++ ];
  107.         }
  108.         $tokens[] = crtok( "string", $string );
  109.     }
  110. }
  111. function dumptokpart( $tokens, $b, $e )
  112. {
  113.     for( ; $b < $e; ++$b )
  114.     {
  115.         echo $tokens[ $b ]->type;
  116.         echo "(\"";
  117.         echo $tokens[ $b ]->data;
  118.         echo "\"); ";
  119.     }
  120.     echo "<br/>";
  121. }
  122.  
  123. hdr( "Tokens" );
  124. dumptokpart( $tokens, 0, count( $tokens ) );
  125.  
  126. hdr( 'Function tree generation' );
  127.  
  128. $functree = array();
  129.  
  130. function errif( $test, $out ){ if( $test ) echo "$out<br/>"; }
  131. function read_args( $tokens, $begin, $end )
  132. {
  133.     echo "readargs: ";
  134.     dumptokpart( $tokens, $begin, $end );
  135.    
  136.     $out = array();
  137.    
  138.     $i = $begin;
  139.     $b = $i;
  140.     $level = 0;
  141.     while( $i <= $end )
  142.     {
  143.         if( ( $tokens[ $i ]->data == ',' || $tokens[ $i ]->data == ')' ) && $level == 0 )
  144.         {
  145.             $e = $i;
  146.             // check all tokens from $b to $e
  147.             if( $b < $e )
  148.             {
  149.                 $ft = $tokens[ $b ];
  150.                 if( $ft->type == "string" )
  151.                     $out[] = $ft;
  152.                 else if( $ft->type == "number" )
  153.                     $out[] = $ft;
  154.                 else if( $ft->type == "ident" )
  155.                 {
  156.                     // a function!
  157.                     $out[] = make_func( $tokens, $b, $e );
  158.                 }
  159.                 else
  160.                     echo "unexpected token: $ft->type<br/>";
  161.             }
  162.             else
  163.                 echo "expected argument<br/>";
  164.             $b = $i + 1;
  165.         }
  166.         if( $tokens[ $i ]->data == '(' ) $level++;
  167.         else if( $tokens[ $i ]->data == ')' ) $level--;
  168.         $i++;
  169.     }
  170.    
  171.     return $out;
  172. }
  173. function make_func( $tokens, $b, $e )
  174. {
  175.     echo "makefunc: ";
  176.     dumptokpart( $tokens, $b, $e );
  177.    
  178.     errif( $tokens[ $b ]->type != 'ident', 'type of first not ident' );
  179.     errif( $tokens[ $b + 1 ]->data != '(', 'data of second not (' );
  180.     errif( $tokens[ $e - 1 ]->data != ')', 'data of last not )' );
  181.    
  182.     $name = $tokens[ $b ]->data;
  183.     $args = read_args( $tokens, $b + 2, $e - 1 );
  184.     return (object) array( "name" => $name, "args" => $args );
  185. }
  186.  
  187. for( $i = 0; $i < count( $tokens ); ++$i )
  188. {
  189.     $b = $i;
  190.     while( $i < count( $tokens ) && $tokens[ $i ]->data != ';' )
  191.         $i++;
  192.     if( $i - $b <= 1 )
  193.         continue;
  194.    
  195.     // process tokens from $beg to $i
  196.     $functree[] = make_func( $tokens, $b, $i );
  197. }
  198.  
  199. hdr( 'Function tree' );
  200. struct_dump( $functree );
  201.  
  202.  
  203. // the low-level code
  204. // flip the tree into a list of functions, assign registers and constants
  205.  
  206. global $constants, $funclist, $oplist;
  207.  
  208. $constants = array();
  209. $funclist = array();
  210. $oplist = array();
  211.  
  212. function const_add( $data )
  213. {
  214.     global $constants;
  215.     if( ( $at = array_search( $data, $constants, true ) ) !== false )
  216.         return $at;
  217.     $constants[] = $data;
  218.     return count( $constants ) - 1;
  219. }
  220. function fl_add( $func )
  221. {
  222.     global $funclist;
  223.     $args = array();
  224.     foreach( $func->args as $arg )
  225.     {
  226.         if( isset( $arg->name ) )
  227.         {
  228.             // it's a function
  229.             $reg = fl_add( $arg );
  230.             $args[] = crtok( "reg", $reg );
  231.         }
  232.         else
  233.         {
  234.             // it's a constant
  235.             $args[] = crtok( "const", const_add( $arg->data ) );
  236.         }
  237.     }
  238.    
  239.     $funclist[] = (object) array( "name" => $func->name, "args" => $args );
  240.     return count( $funclist ) - 1;
  241. }
  242.  
  243. foreach( $functree as $func )
  244.     fl_add( $func );
  245.  
  246.  
  247. hdr( "Function list" );
  248. echo "FuncList: ";  struct_dump( $funclist );
  249. echo "Constants: "; struct_dump( $constants );
  250.  
  251.  
  252. global $variables, $output;
  253. $variables = array();
  254. $output = "";
  255. function scrapi_add( $a1, $a2 ){ return $a1 + $a2; }
  256. function scrapi_sub( $a1, $a2 ){ return $a1 - $a2; }
  257. function scrapi_mul( $a1, $a2 ){ return $a1 * $a2; }
  258. function scrapi_div( $a1, $a2 ){ return $a1 / $a2; }
  259. function scrapi_set( $at, $val ){ global $variables; $variables[ $at ] = $val; }
  260. function scrapi_get( $at ){ global $variables; return $variables[ $at ]; }
  261. function scrapi_print( $what ){ global $output; $output .= $what; }
  262. $API = array(
  263.     'add' => 'scrapi_add',
  264.     'sub' => 'scrapi_sub',
  265.     'mul' => 'scrapi_mul',
  266.     'div' => 'scrapi_div',
  267.     'set' => 'scrapi_set',
  268.     'get' => 'scrapi_get',
  269.     'print' => 'scrapi_print'
  270. );
  271.  
  272. hdr( "Execution" );
  273. $ptr = 0;
  274. foreach( $funclist as $op )
  275. {
  276.     if( !isset( $API[ $op->name ] ) )
  277.         echo "function not found: $op->name<br/>";
  278.     else
  279.     {
  280.         $args = array();
  281.         foreach( $op->args as $arg )
  282.         {
  283.             if( $arg->type == "const" )
  284.                 $args[] = $constants[ $arg->data ];
  285.             else
  286.                 $args[] = $variables[ $arg->data ];
  287.         }
  288.         echo "$op->name( " . implode( ", ", $args ) . " );<br/>";
  289.         $ret = call_user_func_array( $API[ $op->name ], $args );
  290.         if( isset( $ret ) )
  291.             $variables[ $ptr ] = $ret;
  292.     }
  293.     $ptr++;
  294. }
  295. hdr( "End of execution" );
  296. echo "Output: ";
  297. echo "<div style='border: 2px inset #ccc'>$output</div>";
  298. echo "Variables: "; struct_dump( $variables );
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement