yosymfony/parser-utils

解析器实用工具

v2.0.0 2018-06-29 15:31 UTC

This package is auto-updated.

Last update: 2024-09-13 05:04:32 UTC


README

这是一个用于在PHP中编写递归下降解析器的库。

Build Status

要求

  • PHP >= 7.1

安装

首选的安装方法是 composer

composer require yosymfony/parser-utils

示例

首先,您需要创建一个词法分析器。这个分析器将识别令牌

use Yosymfony\ParserUtils\BasicLexer;

$lexer = new BasicLexer([
    '/^([0-9]+)/x' => 'T_NUMBER',
    '/^(\+)/x' => 'T_PLUS',
    '/^(-)/x' => 'T_MINUS',
    '/^\s+/' => 'T_SPACE',  // We do not surround it with parentheses because
                            // this is not meaningful for us in this case
]);

其次,您需要一个解析器来消费词法分析器提供的令牌。`AbstractParser` 类包含一个名为 `parseImplementation` 的抽象方法,该方法接收一个 `TokenStream` 作为参数。

use Yosymfony\ParserUtils\AbstractParser;

class Parser extends AbstractParser
{
    protected function parseImplementation(TokenStream $stream)
    {
        $result = $stream->matchNext('T_NUMBER');

        while ($stream->isNextAny(['T_PLUS', 'T_MINUS'])) {
            switch ($stream->moveNext()->getName()) {
                case 'T_PLUS':
                    $result += $stream->matchNext('T_NUMBER');
                    break;
                case 'T_MINUS':
                    $result -= $stream->matchNext('T_NUMBER');
                    break;
                default:
                    throw new SyntaxErrorException("Something went wrong");
                    break;
            }
        }

        return $result;
    }
}

现在,您可以查看结果

$parser = new Parser($lexer);
$parser->parse('1 + 1');          // 2

BasicLexer 类

词法分析器负责识别令牌。这个分析器按行工作。如果您想为输入的每一行生成一个特殊的 `T_NEWLINE` 令牌,请在令牌化之前调用 `$lexer->generateNewlineTokens()`。您可以使用 `setNewlineTokenName` 方法设置此特殊令牌的名称。

$lexer = new BasicLexer([...]);
$lexer->generateNewlineTokens()
      ->setNewlineTokenName('T_NL');

$lexer->tokenize('...');

此外,还有一个特殊的令牌 `T_EOS`,它确定输入字符串的结束。要启用此功能,请在令牌化之前调用 `$lexer->generateEosToken()`。您可以使用 `setEosTokenName` 方法设置此特殊令牌的名称。

$lexer = new BasicLexer([...]);
$lexer->generateEosToken()
      ->setEosTokenName('T_MY_EOS');

$lexer->tokenize('...');

TokenStream 类

此类允许您处理由词法分析器返回的令牌列表。

  • moveNext: 将指针向前移动一个令牌。返回一个 `Token` 对象或 `null`(如果没有更多令牌)。例如:`$ts->moveNext()`。

  • matchNext: 匹配下一个令牌并返回其值。此方法将指针向前移动一个令牌。如果下一个令牌不匹配,则抛出 `SyntaxErrorException` 异常。例如:`$number = $ts->matchNext('T_NUMBER')`。

  • isNext: 检查下一个令牌是否与作为参数传递的令牌名称匹配。例如:`$ts->isNext('T_PLUS') // true 或 false`。

  • skipWhile: 在令牌与作为参数传递的令牌名称匹配时跳过令牌。此方法将指针向前移动 "n" 个令牌,直到最后一个与令牌名称匹配的令牌。例如:`$ts->skipWhile('T_PLUS')`

  • skipWhileAny: 在令牌与作为参数传递的令牌名称之一匹配时跳过令牌。此方法将指针向前移动 "n" 个令牌,直到最后一个与一个或多个令牌名称匹配的令牌。例如:`$ts->skipWhileAny(['T_PLUS', 'T_MINUS'])`

  • isNextSequence: 检查流中的后续令牌是否与令牌序列匹配。例如:`$ts->isNextSequence(['T_NUMBER', 'T_PLUS', 'T_NUMBER']) // true 或 false`。

  • isNextAny: 检查传递的令牌中的任何一个是否是下一个令牌。例如:`$fs->isNextAny(['T_PLUS', 'T_SUB']) // true 或 false`。

  • hasPendingTokens: 有待处理的令牌吗?例如:`$fs->hasPendingTokens() // true 或 false`。

  • reset: 将流重置到开始位置。

令牌

令牌是 `Token` 类的实例,该类包含以下方法

  • getName: 返回令牌的名称。例如:`T_SUM`。
  • getValue: 返回令牌的值。
  • getLine: 返回令牌所在的行。

单元测试

您可以使用以下命令运行单元测试

$ cd parser-utils
$ composer test

许可证

此库是开源软件,受MIT许可证许可。