|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 00017 define("LEXER_ENTER", 1); 00019 define("LEXER_MATCHED", 2); 00021 define("LEXER_UNMATCHED", 3); 00023 define("LEXER_EXIT", 4); 00025 define("LEXER_SPECIAL", 5); 00026 00035 class ParallelRegex { 00036 var $_patterns; 00037 var $_labels; 00038 var $_regex; 00039 var $_case; 00040 00047 function ParallelRegex($case) { 00048 $this->_case = $case; 00049 $this->_patterns = array(); 00050 $this->_labels = array(); 00051 $this->_regex = null; 00052 } 00053 00062 function addPattern($pattern, $label = true) { 00063 $count = count($this->_patterns); 00064 $this->_patterns[$count] = $pattern; 00065 $this->_labels[$count] = $label; 00066 $this->_regex = null; 00067 } 00068 00078 function match($subject, &$match) { 00079 if (count($this->_patterns) == 0) { 00080 return false; 00081 } 00082 if (!preg_match($this->_getCompoundedRegex(), $subject, $matches)) { 00083 $match = ""; 00084 return false; 00085 } 00086 $match = $matches[0]; 00087 for ($i = 1; $i < count($matches); $i++) { 00088 if ($matches[$i]) { 00089 return $this->_labels[$i - 1]; 00090 } 00091 } 00092 return true; 00093 } 00094 00102 function _getCompoundedRegex() { 00103 if ($this->_regex == null) { 00104 for ($i = 0; $i < count($this->_patterns); $i++) { 00105 $this->_patterns[$i] = '(' . str_replace( 00106 array('/', '(', ')'), 00107 array('\/', '\(', '\)'), 00108 $this->_patterns[$i]) . ')'; 00109 } 00110 $this->_regex = "/" . implode("|", $this->_patterns) . "/" . $this->_getPerlMatchingFlags(); 00111 } 00112 return $this->_regex; 00113 } 00114 00120 function _getPerlMatchingFlags() { 00121 return ($this->_case ? "msS" : "msSi"); 00122 } 00123 } 00124 00132 class StateStack { 00133 var $_stack; 00134 00140 function StateStack($start) { 00141 $this->_stack = array($start); 00142 } 00143 00149 function getCurrent() { 00150 return $this->_stack[count($this->_stack) - 1]; 00151 } 00152 00159 function enter($state) { 00160 array_push($this->_stack, $state); 00161 } 00162 00170 function leave() { 00171 if (count($this->_stack) == 1) { 00172 return false; 00173 } 00174 array_pop($this->_stack); 00175 return true; 00176 } 00177 } 00178 00190 class Lexer { 00191 var $_regexes; 00192 var $_parser; 00193 var $_mode; 00194 var $_mode_handlers; 00195 var $_case; 00196 00206 function Lexer(&$parser, $start = "accept", $case = false) { 00207 $this->_case = $case; 00208 $this->_regexes = array(); 00209 $this->_parser = &$parser; 00210 $this->_mode = new StateStack($start); 00211 $this->_mode_handlers = array(); 00212 } 00213 00225 function addPattern($pattern, $mode = "accept") { 00226 if (!isset($this->_regexes[$mode])) { 00227 $this->_regexes[$mode] = new ParallelRegex($this->_case); 00228 } 00229 $this->_regexes[$mode]->addPattern($pattern); 00230 } 00231 00245 function addEntryPattern($pattern, $mode, $new_mode) { 00246 if (!isset($this->_regexes[$mode])) { 00247 $this->_regexes[$mode] = new ParallelRegex($this->_case); 00248 } 00249 $this->_regexes[$mode]->addPattern($pattern, $new_mode); 00250 } 00251 00260 function addExitPattern($pattern, $mode) { 00261 if (!isset($this->_regexes[$mode])) { 00262 $this->_regexes[$mode] = new ParallelRegex($this->_case); 00263 } 00264 $this->_regexes[$mode]->addPattern($pattern, "__exit"); 00265 } 00266 00278 function addSpecialPattern($pattern, $mode, $special) { 00279 if (!isset($this->_regexes[$mode])) { 00280 $this->_regexes[$mode] = new ParallelRegex($this->_case); 00281 } 00282 $this->_regexes[$mode]->addPattern($pattern, "_$special"); 00283 } 00284 00291 function mapHandler($mode, $handler) { 00292 $this->_mode_handlers[$mode] = $handler; 00293 } 00294 00305 function parse($raw) { 00306 if (!isset($this->_parser)) { 00307 return false; 00308 } 00309 $length = strlen($raw); 00310 while (is_array($parsed = $this->_reduce($raw))) { 00311 list($unmatched, $matched, $mode) = $parsed; 00312 if (!$this->_dispatchTokens($unmatched, $matched, $mode)) { 00313 return false; 00314 } 00315 if (strlen($raw) == $length) { 00316 return false; 00317 } 00318 $length = strlen($raw); 00319 } 00320 if (!$parsed) { 00321 return false; 00322 } 00323 return $this->_invokeParser($raw, LEXER_UNMATCHED); 00324 } 00325 00339 function _dispatchTokens($unmatched, $matched, $mode = false) { 00340 if (!$this->_invokeParser($unmatched, LEXER_UNMATCHED)) { 00341 return false; 00342 } 00343 if ($mode === "__exit") { 00344 if (!$this->_invokeParser($matched, LEXER_EXIT)) { 00345 return false; 00346 } 00347 return $this->_mode->leave(); 00348 } 00349 if (strncmp($mode, "_", 1) == 0) { 00350 $mode = substr($mode, 1); 00351 $this->_mode->enter($mode); 00352 if (!$this->_invokeParser($matched, LEXER_SPECIAL)) { 00353 return false; 00354 } 00355 return $this->_mode->leave(); 00356 } 00357 if (is_string($mode)) { 00358 $this->_mode->enter($mode); 00359 return $this->_invokeParser($matched, LEXER_ENTER); 00360 } 00361 return $this->_invokeParser($matched, LEXER_MATCHED); 00362 } 00363 00372 function _invokeParser($content, $is_match) { 00373 if (($content === "") || ($content === false)) { 00374 return true; 00375 } 00376 $handler = $this->_mode->getCurrent(); 00377 if (isset($this->_mode_handlers[$handler])) { 00378 $handler = $this->_mode_handlers[$handler]; 00379 } 00380 return $this->_parser->$handler($content, $is_match); 00381 } 00382 00397 function _reduce(&$raw) { 00398 if (!isset($this->_regexes[$this->_mode->getCurrent()])) { 00399 return false; 00400 } 00401 if ($raw === "") { 00402 return true; 00403 } 00404 if ($action = $this->_regexes[$this->_mode->getCurrent()]->match($raw, $match)) { 00405 $count = strpos($raw, $match); 00406 $unparsed = substr($raw, 0, $count); 00407 $raw = substr($raw, $count + strlen($match)); 00408 return array($unparsed, $match, $action); 00409 } 00410 return true; 00411 } 00412 } 00413 ?>