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 + -
显示快捷键?