<?php 
/** 
 * This file contains the Parser class. 
 *  
 * @author Gonzalo Chumillas <[email protected]> 
 * @package parser 
 */ 
require_once dirname(__DIR__) . "/parser/exceptions/parser-exception.php"; 
require_once dirname(__DIR__) . "/parser/tokenizer.php"; 
 
/** 
 * class Parser 
 * Parses a string. 
 */ 
abstract class Parser extends Tokenizer { 
    /** 
     * This flag indicates that we want to perform a "non-greedy" analysis. 
     */ 
    const UNGREEDY = 0x4; 
     
    /** 
     * @var string|Parser 
     */ 
    private $target; 
     
    /** 
     * Flags. 
     * @var int 
     */ 
    private $flags; 
     
    /** 
     * @param string|Parser $target 
     * @param int $flags = 0 
     */ 
    public function __construct($target, $flags = 0) { 
        $this->target = $target; 
        $this->flags = $flags; 
         
        if ($this->target instanceof Parser) { 
            parent::__construct($target->getString(), $flags); 
            $this->offset = $target->getOffset(); 
        } else { 
            parent::__construct($target, $flags); 
        } 
    } 
     
    /** 
     * Parses a string. 
     * @return mixed 
     */ 
    abstract protected function _parse(); 
     
    /** 
     * Tries to parse a string and throws an exception if unsuccessful. 
     * This is the habitual use of the parser method: 
     *  
     * <code> 
     * $p = new MyCustomParser($string); 
     * $info = $p->parse(); 
     * if (!$info) { 
     *     echo "Invalid expression"; 
     * } 
     * </code> 
     *  
     * @throws Exception 
     * @return mixed 
     */ 
    public function parse() { 
        $ungreedy = Parser::UNGREEDY & $this->flags; 
        $ret = $this->_parse(); 
         
        if ($ret) { 
            if ($this->target instanceof Parser) { 
                $this->target->setOffset($this->offset); 
            } else 
            if (!$ungreedy && !$this->end()) { 
                throw new ParserException($this, "Unrecognized expression"); 
            } 
        } 
         
        return $ret; 
    } 
     
    /** 
     * Matches the string against a function and moves the offset forward if the function returns TRUE. 
     * @param string $method_name Method name 
     * @param array $args Additional arguments 
     * @throws Exception 
     * @return mixed 
     */ 
    protected function is($method_name, $args = NULL /* ... additional arguments */) { 
        if (!method_exists($this, $method_name)) { 
            throw new Exception("The method `$method_name` does not exist"); 
        } 
         
        if (!is_callable(array($this, $method_name))) { 
            throw new Exception("The method `$method_name` is inaccessible"); 
        } 
         
        $offset = $this->offset;  // saves offset 
        $ret = call_user_func_array(array($this, $method_name), array_slice(func_get_args(), 1)); 
        if (!$ret) { 
            $this->offset = $offset;  // restores offset 
        } 
         
        return $ret; 
    } 
} 
 
 |