The script in (almost) full

As opposed to wasting space by printing such a long script several times over, I have only been printing parts so far. However, as we are done, here is the complete script, sans the gettoken() function which is unchanged:

<?php
    define
("FOO_NUMBER", 0);
    
define("FOO_VARIABLE", 1);
    
define("FOO_ASSIGNEQUALS", 2);
    
define("FOO_PRINT", 3);
    
define("FOO_STRING", 4);
    
define("FOO_SEMICOLON", 5);
    
define("FOO_PLUS", 6);
    
define("FOO_MULTIPLY", 7);
    
define("IS_OPERATOR", 0);
    
define("IS_OPERAND", 1);

    
// you can change the values in $precedence, as long you keep the order the same
    
$precedence = array (FOO_PRINT => 0, FOO_ASSIGNEQUALS => 1, FOO_PLUS => 2, FOO_MULTIPLY => 3);

    class
token {
        public
$type;
        public
$token;
        public
$val;

        public function
__construct($type, $token, $val) {
            
$this->type = $type;
            
$this->token = $token;
            
$this->val = $val;
        }
    }

    
// this function converts variables to values as appropriate
    
function getval($token) {
        GLOBAL
$variables;
        if (
$token->token == FOO_VARIABLE) {
            return
$variables[$token->val];
        } else {
            return
$token->val;
        }
    }

    function
execute(&$stack) {
        GLOBAL
$variables;
        
$operator = array_pop($stack);

        if (
$stack[count($stack) - 1]->type == IS_OPERATOR) {
            
$right = execute($stack);
        } else {
            
$right = array_pop($stack);
        }

        if (
count($stack)) {
            if (
$stack[count($stack) - 1]->type == IS_OPERATOR) {
                
$left = execute($stack);
            } else {
                
$left = array_pop($stack);
            }
        }

        switch(
$operator->token) {
            case
FOO_ASSIGNEQUALS:
                
$variables[$left->val] = getval($right);
                break;
            case
FOO_PLUS:
                return new
token(IS_OPERAND, FOO_NUMBER, getval($left) + getval($right));
            case
FOO_MULTIPLY:
                return new
token(IS_OPERAND, FOO_NUMBER, getval($left) * getval($right));
            case
FOO_PRINT:
                print
getval($right);
                print
"\n";
        }
    }

    function
main() {
        GLOBAL
$lasttoken, $precedence;

        while(
1) {
            
$stack = array();
            
$operators = array();

            do {
                
$token = gettoken();

                switch(
$token) {
                    case
FOO_NUMBER:
                        case
FOO_VARIABLE:
                        case
FOO_STRING:
                            
$stack[] = new token(IS_OPERAND, $token, $lasttoken);
                            break;
                        default:
                            if (
$token != FOO_SEMICOLON) {
                                
// this removes higher-precedence operators in places of a new, lower-precedence one

                                
while (count($operators) && $precedence[$operators[count($operators) - 1]->token] > $precedence[$token]) {
                                    
$higher_op = array_pop($operators);
                                    
array_push($stack, $higher_op);
                                }

                                
$operators[] = new token(IS_OPERATOR, $token, NULL);
                            }
                }
            } while (
$token != FOO_SEMICOLON);

            while (
count($operators)) array_push($stack, array_pop($operators));

            
execute($stack);
        }
    }

    function
gettoken() {
        
// this is unchanged
    
}

    
$script = fopen("script.foo", "r");
    
$characters = array_merge(range('a', 'z'), range('A', 'z'));
    
$characters[] = "_";
    
$variables = array();

    function
cleanup() {
        GLOBAL
$script;
        
fclose($script);
    }

    
register_shutdown_function("cleanup");
    
main();
?>

Even with the gettoken() function all but removed, that is still probably the longest script in the entire book. Still, you like typing, right?

 

Next chapter: Mini-language conclusion >>

Previous chapter: Operator precedence

Jump to:

 

Home: Table of Contents

Follow us on Identi.ca or Twitter

Username:   Password:
Create Account | About TuxRadar