&reftitle.examples;
Примеры использования лексера
Токенизация списка целых чисел через запятую
id */
$token = array(
"COMMA" => 1,
"CRLF" => 2,
"DECIMAL" => 3,
);
/* id => name */
$tokenIdToName = array_flip($token);
$lex = new Lexer;
$lex->push("[\x2c]", $token["COMMA"]);
$lex->push("[\r][\n]", $token["CRLF"]);
$lex->push("[\d]+", $token["DECIMAL"]);
$lex->build();
$in = "0,1,2\r\n3,42,5\r\n6,77,8\r\n";
$lex->consume($in);
do {
$lex->advance();
$tok = $lex->getToken();
if (Token::UNKNOWN == $tok->id) {
throw new LexerException("Неизвестный токен '{$tok->value}' по смещению {$lex->marker}.");
}
echo "ТОКЕН: ", $tokenIdToName[$tok->id], PHP_EOL;
} while (Token::EOI != $tok->id);
]]>
Токенизировать оператор присваивания
push("\$[a-zA-Z_][a-zA-Z0-9_]*", 1);
$lex->push("=", 2);
$lex->push("\d+", 3);
$lex->push(";", 4);
$lex->build();
$lex->consume('$x = 42; $y = 24;');
do {
$lex->advance();
$tok = $lex->getToken();
var_dump($tok);
} while (Token::EOI != $tok->id);
]]>
Пример использования парсера
Простой калькулятор
token("INTEGER");
$p->left("'+' '-' '*' '/'");
$p->push("start", "exp");
$prod_add = $p->push("exp", "exp '+' exp");
$prod_sub = $p->push("exp", "exp '-' exp");
$prod_mul = $p->push("exp", "exp '*' exp");
$prod_div = $p->push("exp", "exp '/' exp");
$p->push("exp", "INTEGER"); /* Индекс производства не используется. */
$p->build();
$lex = new Lexer;
$lex->push("[+]", $p->tokenId("'+'"));
$lex->push("[-]", $p->tokenId("'-'"));
$lex->push("[*]", $p->tokenId("'*'"));
$lex->push("[/]", $p->tokenId("'/'"));
$lex->push("\\d+", $p->tokenId("INTEGER"));
$lex->push("\\s+", Token::SKIP);
$lex->build();
$exp = array(
"1 + 1",
"33 / 10",
"100 * 45",
"17 - 45",
);
foreach ($exp as $in) {
if (!$p->validate($in, $lex)) {
throw new ParserException("Не удалось проверить ввод");
}
$p->consume($in, $lex);
while (Parser::ACTION_ERROR != $p->action && Parser::ACTION_ACCEPT != $p->action) {
switch ($p->action) {
case Parser::ACTION_ERROR:
throw new ParserException("Parser error");
break;
case Parser::ACTION_SHIFT:
case Parser::ACTION_GOTO:
case Parser::ACTION_ACCEPT:
break;
case Parser::ACTION_REDUCE:
switch ($p->reduceId) {
case $prod_add:
$l = $p->sigil(0);
$r = $p->sigil(2);
echo "$l + $r = " . ($l + $r) . "\n";
break;
case $prod_sub:
$l = $p->sigil(0);
$r = $p->sigil(2);
echo "$l - $r = " . ($l - $r) . "\n";
break;
case $prod_mul:
$l = $p->sigil(0);
$r = $p->sigil(2);
echo "$l * $r = " . ($l * $r) . "\n";
break;
case $prod_div:
$l = $p->sigil(0);
$r = $p->sigil(2);
echo "$l / $r = " . ($l / $r) . "\n";
break;
}
break;
}
$p->advance();
}
}
]]>
Разобрать слова из предложения
token("WORD");
$p->push("START", "SENTENCE");
$p->push("SENTENCE", "WORDS");
$prod_word_0 = $p->push("WORDS", "WORDS WORD");
$prod_word_1 = $p->push("WORDS", "WORD");
$p->build();
$lex = new Lexer;
$lex->push("[^\s]{-}[\.,\:\;\?]+", $p->tokenId("WORD"));
$lex->push("[\s\.,\:\;\?]+", Token::SKIP);
$lex->build();
$in = "Dis-moi où est ton papa?";
$p->consume($in, $lex);
do {
switch ($p->action) {
case Parser::ACTION_ERROR:
throw new ParserException("Error");
break;
case Parser::ACTION_SHIFT:
case Parser::ACTION_GOTO:
/* var_dump($p->trace());*/
break;
case Parser::ACTION_REDUCE:
$rid = $p->reduceId();
if ($rid == $prod_word_1) {
var_dump($p->sigil(0));
} if ($rid == $prod_word_0) {
var_dump($p->sigil(1));
}
break;
}
$p->advance();
} while (Parser::ACTION_ACCEPT != $p->action);
]]>