parser.php

来自「太烦了」· PHP 代码 · 共 1,122 行 · 第 1/3 页

PHP
1,122
字号
<?php/* vim: set expandtab tabstop=4 shiftwidth=4: */// +----------------------------------------------------------------------+// | Copyright (c) 2002-2004 Brent Cook                                        |// +----------------------------------------------------------------------+// | This library is free software; you can redistribute it and/or        |// | modify it under the terms of the GNU Lesser General Public           |// | License as published by the Free Software Foundation; either         |// | version 2.1 of the License, or (at your option) any later version.   |// |                                                                      |// | This library is distributed in the hope that it will be useful,      |// | but WITHOUT ANY WARRANTY; without even the implied warranty of       |// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |// | Lesser General Public License for more details.                      |// |                                                                      |// | You should have received a copy of the GNU Lesser General Public     |// | License along with this library; if not, write to the Free Software  |// | Foundation, Inc., 59 Temple Place, Suite 330,Boston,MA 02111-1307 USA|// +----------------------------------------------------------------------+// | Authors: Brent Cook <busterbcook@yahoo.com>                          |// |          Jason Pell <jasonpell@hotmail.com>                          |// |          Lauren Matheson <inan@canada.com>                           |// |          John Griffin <jgriffin316@netscape.net>                     |// +----------------------------------------------------------------------+//// $Id: Parser.php,v 1.23 2004/05/11 05:09:02 busterb Exp $//require_once PEAR_DIR . 'PEAR.php';require_once PEAR_DIR . 'SQL/Lexer.php';/** * A sql parser * * @author  Brent Cook <busterbcook@yahoo.com> * @version 0.5 * @access  public * @package SQL_Parser */class SQL_Parser{    var $lexer;    var $token;// symbol definitions    var $functions = array();    var $types = array();    var $symbols = array();    var $operators = array();    var $synonyms = array();    var $dialects = array("ANSI", "MySQL");// {{{ function SQL_Parser($string = null)    function SQL_Parser($string = null, $dialect = "ANSI") {        $this->setDialect($dialect);        if (is_string($string)) {            $this->lexer = new Lexer($string, 1);            $this->lexer->symbols =& $this->symbols;        }    }// }}}// {{{ function setDialect($dialect)    function setDialect($dialect) {        if (in_array($dialect, $this->dialects)) {            include PEAR_DIR . 'SQL/Dialect_'.$dialect.'.php';            $this->types = array_flip($dialect['types']);            $this->functions = array_flip($dialect['functions']);            $this->operators = array_flip($dialect['operators']);            $this->commands = array_flip($dialect['commands']);            $this->synonyms = $dialect['synonyms'];            $this->symbols = array_merge(                $this->types,                $this->functions,                $this->operators,                $this->commands,                array_flip($dialect['reserved']),                array_flip($dialect['conjunctions']));        } else {            return $this->raiseError('Unknown SQL dialect:'.$dialect);        }    }// }}} // {{{ getParams(&$values, &$types)    function getParams(&$values, &$types) {        $values = array();        $types = array();        while ($this->token != ')') {            $this->getTok();            if ($this->isVal() || ($this->token == 'ident') || ($this->token == 'sys_var')) {                $values[] = $this->lexer->tokText;                $types[] = $this->token;            } elseif ($this->token == ')') {                return false;            } else {                return $this->raiseError('Expected a value');            }            $this->getTok();            if (($this->token != ',') && ($this->token != ')')) {                return $this->raiseError('Expected , or )');            }        }    }// }}}    // {{{ raiseError($message)    function raiseError($message) {        $end = 0;        if ($this->lexer->string != '') {            while (($this->lexer->lineBegin+$end < $this->lexer->stringLen)               && ($this->lexer->string{$this->lexer->lineBegin+$end} != "\n")){                ++$end;            }        }                $message = 'Parse error: '.$message.' on line '.            ($this->lexer->lineNo+1)."\n";        $message .= substr($this->lexer->string, $this->lexer->lineBegin, $end)."\n";        $length = is_null($this->token) ? 0 : strlen($this->lexer->tokText);        $message .= str_repeat(' ', abs($this->lexer->tokPtr -                                $this->lexer->lineBegin - $length))."^";        $message .= ' found: "'.$this->lexer->tokText.'"';        return PEAR::raiseError($message);    }    // }}}    // {{{ isType()    function isType() {        return isset($this->types[$this->token]);    }    // }}}    // {{{ isVal()    function isVal() {       return (($this->token == 'real_val') ||               ($this->token == 'int_val') ||               ($this->token == 'text_val') ||               ($this->token == 'null'));    }    // }}}    // {{{ isFunc()    function isFunc() {        return isset($this->functions[$this->token]);    }    // }}}    // {{{ isCommand()    function isCommand() {        return isset($this->commands[$this->token]);    }    // }}}    // {{{ isReserved()    function isReserved() {        return isset($this->symbols[$this->token]);    }    // }}}    // {{{ isOperator()    function isOperator() {        return isset($this->operators[$this->token]);    }    // }}}    // {{{ getTok()    function getTok() {        $this->token = $this->lexer->lex();        //echo $this->token."\t".$this->lexer->tokText."\n";    }    // }}}    // {{{ &parseFieldOptions()    function parseFieldOptions()    {        // parse field options        $namedConstraint = false;        $options = array();        while (($this->token != ',') && ($this->token != ')') &&                ($this->token != null)) {            $option = $this->token;            $haveValue = true;            switch ($option) {                case 'constraint':                    $this->getTok();                    if ($this->token = 'ident') {                        $constraintName = $this->lexer->tokText;                        $namedConstraint = true;                        $haveValue = false;                    } else {                        return $this->raiseError('Expected a constraint name');                    }                    break;                case 'default':                    $this->getTok();                    if ($this->isVal()) {                        $constraintOpts = array('type'=>'default_value',                                                'value'=>$this->lexer->tokText);                    } elseif ($this->isFunc()) {                        $results = $this->parseFunctionOpts();                        if (PEAR::isError($results)) {                            return $results;                        }                        $results['type'] = 'default_function';                        $constraintOpts = $results;                    } else {                        return $this->raiseError('Expected default value');                    }                    break;                case 'primary':                    $this->getTok();                    if ($this->token == 'key') {                        $constraintOpts = array('type'=>'primary_key',                                                'value'=>true);                    } else {                        return $this->raiseError('Expected "key"');                    }                    break;                case 'not':                    $this->getTok();                    if ($this->token == 'null') {                        $constraintOpts = array('type'=>'not_null',                                                'value' => true);                    } else {                        return $this->raiseError('Expected "null"');                    }                    break;                case 'check':                    $this->getTok();                    if ($this->token != '(') {                        return $this->raiseError('Expected (');                    }                    $results = $this->parseSearchClause();                    if (PEAR::isError($results)) {                        return $results;                    }                    $results['type'] = 'check';                    $constraintOpts = $results;                    if ($this->token != ')') {                        return $this->raiseError('Expected )');                    }                    break;                case 'unique':                    $this->getTok();                    if ($this->token != '(') {                        return $this->raiseError('Expected (');                    }                    $constraintOpts = array('type'=>'unique');                    $this->getTok();                    while ($this->token != ')') {                        if ($this->token != 'ident') {                            return $this->raiseError('Expected an identifier');                        }                        $constraintOpts['column_names'][] = $this->lexer->tokText;                        $this->getTok();                        if (($this->token != ')') && ($this->token != ',')) {                            return $this->raiseError('Expected ) or ,');                        }                    }                    if ($this->token != ')') {                        return $this->raiseError('Expected )');                    }                    break;                case 'month': case 'year': case 'day': case 'hour':                case 'minute': case 'second':                    $intervals = array(                                    array('month'=>0,                                          'year'=>1),                                    array('second'=>0,                                          'minute'=>1,                                          'hour'=>2,                                          'day'=>3));                    foreach ($intervals as $class) {                        if (isset($class[$option])) {                            $constraintOpts = array('quantum_1'=>$this->token);                            $this->getTok();                            if ($this->token == 'to') {                                $this->getTok();                                if (!isset($class[$this->token])) {                                    return $this->raiseError(                                        'Expected interval quanta');                                }                                if ($class[$this->token] >=                                    $class[$constraintOpts['quantum_1']]) {                                    return $this->raiseError($this->token.                                        ' is not smaller than '.                                        $constraintOpts['quantum_1']);                                }                                 $constraintOpts['quantum_2'] = $this->token;                            } else {                                $this->lexer->unget();                            }                            break;                        }                    }                    if (!isset($constraintOpts['quantum_1'])) {                        return $this->raiseError('Expected interval quanta');                    }                    $constraintOpts['type'] = 'values';                    break;                case 'null':                    $haveValue = false;                    break;                default:                    return $this->raiseError('Unexpected token '                                        .$this->lexer->tokText);            }            if ($haveValue) {                if ($namedConstraint) {                    $options['constraints'][$constraintName] = $constraintOpts;                    $namedConstraint = false;                } else {                    $options['constraints'][] = $constraintOpts;                }            }            $this->getTok();        }        return $options;    }    // }}}    // {{{ parseSearchClause()    function parseSearchClause($subSearch = false)    {        $clause = array();        // parse the first argument        $this->getTok();        if ($this->token == 'not') {            $clause['neg'] = true;            $this->getTok();        }        $foundSubclause = false;        if ($this->token == '(') {            $clause['arg_1']['value'] = $this->parseSearchClause(true);            $clause['arg_1']['type'] = 'subclause';            if ($this->token != ')') {                return $this->raiseError('Expected ")"');            }            $foundSubclause = true;        } else if ($this->isReserved()) {            return $this->raiseError('Expected a column name or value');        } else {            $clause['arg_1']['value'] = $this->lexer->tokText;            $clause['arg_1']['type'] = $this->token;        }        // parse the operator        if (!$foundSubclause) {            $this->getTok();            if (!$this->isOperator()) {                return $this->raiseError('Expected an operator');            }            $clause['op'] = $this->token;            $this->getTok();            switch ($clause['op']) {                case 'is':                    // parse for 'is' operator                    if ($this->token == 'not') {                        $clause['neg'] = true;                        $this->getTok();                    }                    if ($this->token != 'null') {                        return $this->raiseError('Expected "null"');                    }                    $clause['arg_2']['value'] = '';                    $clause['arg_2']['type'] = $this->token;                    break;                case 'not':

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?