railt/lexer

此包已被废弃,不再维护。作者建议使用phplrt/lexer包。

状态和状态无关的词法分析器的快速实现

1.3.2 2019-01-18 03:54 UTC

This package is auto-updated.

Last update: 2022-02-01 13:13:35 UTC


README

Railt

Travis CI 68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f38663462306532383932386266326234343562322f746573745f636f766572616765 68747470733a2f2f6170692e636f6465636c696d6174652e636f6d2f76312f6261646765732f38663462306532383932386266326234343562322f6d61696e7461696e6162696c697479

PHP 7.1+ railt.org Discord Latest Stable Version Total Downloads License MIT

词法分析器

注意:所有问题和疑问请发送至 https://github.com/railt/railt/issues

注意:测试不能总是正确通过。这可能是因为PPA服务器无法更新gcc和g++导致的。Lexertl构建需要Travis CI内部支持现代编译器。在这种情况下,将显示带有消息“构建错误”的灰色徽章。

为了快速了解其工作原理,只需编写约4行代码

$lexer = Railt\Component\Lexer\Factory::create(['T_WHITESPACE' => '\s+', 'T_DIGIT' => '\d+'], ['T_WHITESPACE']);

foreach ($lexer->lex(Railt\Component\Io\File::fromSources('23 42')) as $token) {
    echo $token . "\n";
}

此示例将读取源文本并返回由其组成的令牌集

  1. T_DIGIT 值为 "23"
  2. T_DIGIT 值为 "42"

Factory类的第二个参数是lex方法结果中忽略的令牌名称列表。这就是为什么我们只得到了两个有效的令牌T_DIGIT。虽然这并不完全正确,但答案中包含一个T_EOI(输入结束)令牌,也可以通过添加Factory类的第二个参数数组从输出中删除。

...现在让我们尝试了解更多!

词法分析器包含两种类型的运行时

  1. 基本 - 一个状态的算法集。
  2. 多状态 - 具有在令牌之间进行状态转换可能的算法集。

由于同一算法(有状态 vs 无状态)的几个实现之间几乎没有速度差异,因此决定废弃不可变的有状态词法分析器。

use Railt\Component\Lexer\Factory;

/**
 * List of available tokens in format "name => pcre"
 */
$tokens = ['T_DIGIT' => '\d+', 'T_WHITESPACE' => '\s+'];

/**
 * List of skipped tokens
 */
$skip   = ['T_WHITESPACE'];

/**
 * Options:
 *   0 - Nothing.
 *   2 - With PCRE lookahead support.
 *   4 - With multistate support.
 */
$flags = Factory::LOOKAHEAD | Factory::MULTISTATE;

/**
 * Create lexer and tokenize sources. 
 */
$lexer = Factory::create($tokens, $skip, $flags);

为了对源文本进行标记化,必须使用->lex(...)方法,它返回TokenInterface对象的迭代器。

foreach ($lexer->lex(File::fromSources('23 42')) as $token) {
    echo $token . "\n";
}

TokenInterface提供方便的API以获取有关令牌的信息

interface TokenInterface
{
    public function getName(): string;
    public function getOffset(): int;
    public function getValue(int $group = 0): ?string;
    public function getGroups(): iterable;
    public function getBytes(): int;
    public function getLength(): int;
}

驱动程序

工厂返回可用的实现之一,但是您也可以自己创建它。

基本

原生正则表达式

NativeRegex实现基于PHP内置的PCRE函数。

use Railt\Component\Lexer\Driver\NativeRegex;
use Railt\Component\Io\File;

$lexer = new NativeRegex(['T_WHITESPACE' => '\s+', 'T_DIGIT' => '\d+'], ['T_WHITESPACE', 'T_EOI']);

foreach ($lexer->lex(File::fromSources('23 42')) as $token) {
    echo $token->getName() . ' -> ' . $token->getValue() . ' at ' . $token->getOffset() . "\n";
}

// Outputs:
// T_DIGIT -> 23 at 0
// T_DIGIT -> 42 at 3

Lexertl

基于C++ lexertl库的实验性词法分析器。要使用它,您需要支持Parle扩展

use Railt\Component\Lexer\Driver\ParleLexer;
use Railt\Component\Io\File;

$lexer = new ParleLexer(['T_WHITESPACE' => '\s+', 'T_DIGIT' => '\d+'], ['T_WHITESPACE', 'T_EOI']);

foreach ($lexer->lex(File::fromSources('23 42')) as $token) {
    echo $token->getName() . ' -> ' . $token->getValue() . ' at ' . $token->getOffset() . "\n";
}

// Outputs:
// T_DIGIT -> 23 at 0
// T_DIGIT -> 42 at 3

请注意:库与PCRE正则表达式语法不完全兼容。请参阅官方文档

多状态

此功能尚未实现。