- end: documentation ( source)
- ctype_space: documentation ( source)
- key: documentation ( source)
<?php
interface ILexer {
/**
* return associative array containing tokens for parser
* @param string $input code to tokenize
* @return array
*/
public function tokenize($input);
}
interface INameValidator {
/**
* Checks if name is valid. In a case of failure trigger syntax error.
* @param string $name
* @return void
*/
public function validate($name);
}
interface IParser {
/**
* Sets array of keywords.
* @param array $keywords associative array where key is keyword and value respective php instruction.
* @return void
*/
public function setKeywords(array $keywords);
/**
* Parses code. Checks for syntax errors.
* If no error occurs returns data for compiler to assemble php class
* otherwise trigger syntax error.
* @param string $input code to parse.
* @return array IParserResult
*/
public function parse($input);
}
interface IParseResult {
public function getDefinition();
public function getName();
public function getConstants();
}
//I know this lexer sucks.
class Lexer extends CompilerElement implements ILexer {
// Potential hidden dependency
private $specialChars = array(
'{' => 'start_body',
'}' => 'end_body'
);
public function tokenize($input) {
if (!is_string($input)) {
$this->getErrorManager()->ariseFatal(get_class($this).'::parse expects parameter 1 to be string. '.gettype($input).' given.');
}
$tokens = array();
$token = $this->getEmptyToken();
$tokenMetadata = $this->getDefaultTokenMetadata();
$inputLength = strlen($input);
for ($i = 0; $i < $inputLength; $i++) {
$current = $input[$i];
//check if special character
if (isset($this->specialChars[$current])) {
$token[$this->specialChars[$current]] = $current;
if ($i !== $inputLength - 1)
continue;
}
if (isset($token['end_body'])) {
$tokens[] = $token;
$token = $this->getEmptyToken();
$tokenMetadata = $this->getDefaultTokenMetadata();
if ($i === $inputLength - 1)
continue;
}
$isWhitespace = ctype_space($current);
if (isset($token['start_body'])) {
//skip if whitespace
if ($isWhitespace) {
continue;
}
if ($current === ',') {
$tokenMetadata['newItem'] = true;
$tokenMetadata['newItemNameResolved'] = false;
continue;
}
if ($current === '=') {
$tokenMetadata['newItemNameResolved'] = true;
continue;
}
if ($tokenMetadata['newItem']) {
$token['e_'.$current] = null;
$tokenMetadata['newItem'] = false;
} else {
end($token);
$lastKey = key($token);
if (!$tokenMetadata['newItemNameResolved']) {
unset($token[$lastKey]);
$token[$lastKey.$current] = null;
} else {
$token[$lastKey] .= $current;
}
}
continue;
}
if (!$tokenMetadata['typeResolved']) {
if ($isWhitespace) {
if (strlen($token['type']) === 0) {
continue;
} else {
$tokenMetadata['typeResolved'] = true;
}
} else {
$token['type'] .= $current;
}
} else if (!$tokenMetadata['nameResolved']) {
if ($isWhitespace) {
if (strlen($token['name']) === 0) {
continue;
} else {
$tokenMetadata['nameResolved'] = true;
}
} else {
$token['name'] .= $current;
}
}
}
return $tokens;
}
private function getEmptyToken() {
return array(
'type' => '',
'name' => ''
);
}
private function getDefaultTokenMetadata() {
return array(
'typeResolved' => false,
'nameResolved' => false,
'newItem' => true,
'newItemNameResolved' => false
);
}
public function __construct(IErrorManager $errorManager) {
parent::__construct($errorManager);
}
}