编写一个简单的语法解析器

2023-12-21

这就是我想做的 - 在 Php 中:给定一个字符串,得到如下结果:

  • (a()?b|c)a 是一个返回 true 或 false 的函数。这应该给b or c打电话后a()
  • (a()?(b()?d|e)|c)。同样的原则。最终结果应该是d, e or c
  • (a()?(b()?d|e)|(c()?f|g))。同样的原则。最终结果应该是d, e, f or g

我面临的问题是a(在我之前的示例中)也可以是一个表达式,如下所示:

((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))

我正在尝试使用正则表达式来做到这一点,但这不起作用。

$res=preg_match_all('/\([^.\(]+\)/', $str, $matches);

所以最后我想像这样调用我的函数:

$final_string=compute("(a(x(y(z()?o|p)))?(b()?d|e)|(c()?f|g))");

最终结果为$final_string应该d, e, f or g

我很确定以前已经做过一些事情,但在谷歌上找不到它。 你会怎么做?

更准确地说,我希望如何分析字符串:

$str =
    "
    (myfunction(12684444)
    ?   {* comment *}
        (
            myfunction(1)|
            myfunction(2)|
            myfunction(80)|
            myfunction(120)|
            myfunction(184)|
            myfunction(196)
        ?   {* comment *}
            AAAAA
            {* /comment *}
        |
            {* Ignore all other values: *}
            BBBBB
        ) {* /comment *}

    |   {* comment *}
        CCCC
    )";

我相信您正在寻找这样的东西。一路上散布着解释性评论。

如果您要将语法扩展到超出您现有的范围(实际上即使您没有),请编写一个适当的解析器,而不是尝试在单个正则表达式中完成所有操作。这是一个有趣的练习,展示了 PCRE 的一些威力,但它可以very很容易变得难以维护的混乱。


测试字符串:

$tests = [
    "a",
    "a()",
    "a(b)",
    "(a?b|c)",
    "(a()?(b()?d|e)|(c()?f|g))",
    "((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))",
    "(a(d(f))?b(e(f))|c)"
];

供以后使用。


Regex:

$regex = <<<'REGEX'
/
(?(DEFINE)
    # An expression is any function, ternary, or string.
    (?<expression>
        (?&function) | (?&ternary) | (?&string)
    )
)

^(?<expr>

    # A function is a function name (consisting of one or more word characters)
    # followed by an opening parenthesis, an optional parameter (expression),
    # and a closing parenthesis.
    # Optional space is allowed around the parentheses.
    (?<function>
        (?<func_name> \w+ )
        \s*\(\s*
        (?<parameter> (?&expression)? )
        \s*\)\s*
    )

    |

    # A ternary is an opening parenthesis followed by an 'if' expression,
    # a question mark, an expression evaluated when the 'if' is true,
    # a pipe, an expression evaluated when the 'if' is false, and a closing
    # parenthesis.
    # Whitespace is allowed after '('; surrounding '?' and '|'; and before ')'.
    (?<ternary>
        \(\s*
        (?<if> (?&expression) )
        \s*\?\s*
        (?<true> (?&expression) )
        \s*\|\s*
        (?<false> (?&expression) )
        \s*\)
    )

    |

    # A string, for simplicity's sake here, we'll call a sequence of word
    # characters.
    (?<string> \w+ )
)$
/x
REGEX;

自由使用命名捕获组有很大帮助,就像x(PCRE_EXTENDED) 修饰符以允许注释和空格。这(?(DEFINE)...)块允许您定义仅供参考使用的子模式。


正则表达式演示:

foreach ($tests as $test) {
    if (preg_match($regex, $test, $m)) {
        echo "expression: $m[expr]\n";

        if ($m['function']) {
            echo "function: $m[function]\n",
                 "function name: $m[func_name]\n",
                 "parameter: $m[parameter]\n";
        } elseif ($m['ternary']) {
            echo "ternary: $m[ternary]\n",
                 "if: $m[if]\n",
                 "true: $m[true]\n",
                 "false: $m[false]\n";
        } else {
            echo "string: $m[string]\n";
        }

        echo "\n";
    }
}

Output:

expression: a
string: a

expression: a()
function: a()
function name: a
parameter: 

expression: a(b)
function: a(b)
function name: a
parameter: b

expression: (a?b|c)
ternary: (a?b|c)
if: a
true: b
false: c

expression: (a()?(b()?d|e)|(c()?f|g))
ternary: (a()?(b()?d|e)|(c()?f|g))
if: a()
true: (b()?d|e)
false: (c()?f|g)

expression: ((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))
ternary: ((h() ? a | i) ? (b() ? d | e) | (c() ? f | g))
if: (h() ? a | i)
true: (b() ? d | e)
false: (c() ? f | g)

expression: (a(d(f))?b(e(f))|c)
ternary: (a(d(f))?b(e(f))|c)
if: a(d(f))
true: b(e(f))
false: c

有点冗长,但足以很好地展示匹配的内容。


Example compute()功能:

function compute($expr) {
    $regex = '/.../x'; // regex from above
    if (!preg_match($regex, $expr, $m)) {
        return false;
    }

    if ($m['function']) {
        if ($m['parameter']) {
            return $m['func_name'](compute($m['parameter']));
        } else {
            return $m['func_name']();
        }
    }

    if ($m['ternary']) {
        return compute($m['if']) ? compute($m['true']) : compute($m['false']);
    }

    return $m['string'];
}

非常简单 - 执行匹配的函数,评估匹配的三元表达式,或返回匹配的字符串;在适当的地方递归。


compute() demo:

function a() {return true;}
function b() {return false;}
function d() {return true;}
function e() {return false;}
function h() {return true;}

foreach ($tests as $test) {
    $result = compute($test);
    echo "$test returns: ";
    var_dump($result);
}

Output:

a returns: string(1) "a"
a() returns: bool(true)
a(b) returns: bool(true)
(a?b|c) returns: string(1) "b"
(a()?(b()?d|e)|(c()?f|g)) returns: string(1) "e"
((h() ? a | i) ? (b() ? d | e) | (c() ? f | g)) returns: string(1) "e"
(a(d(f))?b(e(f))|c) returns: bool(false)

我很确定这是正确的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

编写一个简单的语法解析器 的相关文章

随机推荐

  • 在 Eclipse 中,我可以同时拥有多个控制台视图,每个视图显示不同的控制台吗?

    我正在开发一些在调试模式下记录到控制台的应用程序 我想从 Eclipse 内部运行和调试它们 并同时查看每个的控制台 但是 我有一个控制台选项卡 一次显示一个控制台输出 有没有办法可以将控制台拆分为多个视图 以便可以并排控制台输出 Yes
  • 以 Rails 4 形式将

    我有一个 Rails 4 表单 它在表单页面上使用 AJAX 构建部件列表 一旦零件清单建立在 ul 我想将列表作为 params 哈希中的参数值数组提交 My form div h2 prohibited this service fro
  • 如何使用下载链接从 Azure Blob 存储下载文件

    我制作了一个 Azure 云服务 您可以在其中使用 Blob 将文件上传和删除到云存储 我成功编写了一个方法 您可以从云服务中删除上传的 blob public string DeleteImage string Name Uri uri
  • 使用 Xamarin Forms 打开 PDF

    我有一个 pdf 文件 已使用 xamarin 表单添加为 Android 和 IOS 项目的 AndroidAsset 和 BundleResource 我只是希望能够使用设备默认的任何 pdf 查看器从任何设备打开这些文件 本质上 我只
  • 将 error_info 添加到 std::exception

    我正在整合boost exception到现有代码中 部分代码现在使用BOOST THROW EXCEPTION 但有些人可能仍然会抛出标准std exception 我想在中间捕获站点添加 error info 根据文档 如果异常是boo
  • Base64 电子邮件附件无法上传

    我正在使用以下脚本http stuporglue org recieve e mail and save attachments with a php script http stuporglue org recieve e mail an
  • Dlib(支持 GPU)无法正常工作,不确定?

    我的系统配置 Windows 10 Nvidia 940mx 2GB GDDR5 GPU 8GB RAM 第 8 代 i5 安装的软件 CUDA工具包9 0 cuDNN 7 1 4 在使用以下命令安装上述要求后 我已成功安装了具有 GPU
  • C# string.Substring() 或 string.Remove() [重复]

    这个问题在这里已经有答案了 我想知道使用是否是更好的做法 var a b Substring 6 Or var a b Remove 0 6 哪一个更高效 更快 显然 substring 有更多选项可供选择 但没有什么是 Remove 不能
  • NGINX/JENKINS:您的反向代理设置似乎已损坏

    我已经尝试了至少六个关于如何让 NGINX 与 Jenkins 一起工作的示例 我最近的 NGINX 配置基于以下示例 https wiki jenkins io display JENKINS Running Jenkins behind
  • 删除 Windows 性能计数器类别

    我有一个自定义性能计数器类别 Visual Studio Server Explorer 拒绝删除它 声称它 未注册或属于系统类别 如果不以编程方式执行此操作 如何删除该类别 有我可以删除的注册表项吗 据我所知 有没办法安全地删除它们 除非
  • WCF:System.Net.SocketException - 通常只允许每个套接字地址(协议/网络地址/端口)使用一次

    我有一个 WCF 服务和一个 Web 应用程序 Web 应用程序以连续方式 也称为轮询 调用此 WCF 服务 在我们的生产环境中 我很少收到此错误 因为 这是一个内部活动 用户不知道何时抛出此错误 无法连接到http localhost Q
  • 键转义序列不适用于 tmux

    我一直在使用iTerm2 and vim一阵子 当我需要使用组合键时 我遇到了一些问题 例如CTRL F10 and SHIFT F10里面一个vim会话在里面运行iTerm2 定义键绑定非常简单 例如
  • JavaScript 中的逻辑运算符——如何使用它们?

    我不明白怎么办 and 适用于布尔值和其他数据类型 你如何使用它们 JavaScript 中的所有值要么是 真 要么是 假 a b计算结果为第一个假操作数 a b计算结果为第一个真实操作数 两个运算符都不会计算返回后的任何操作数 如果所有操
  • 永远运行不完的正则表达式

    我写了一个小而朴素的正则表达式 它应该查找括号内的文本 re search r s name 我知道由于某些原因这不是最好的方法 但它运行得很好 我正在寻找的只是一个解释 解释为什么对于某些字符串 这个表达式开始花费指数更长的时间 然后永远
  • Rails 3 - 多个控制器之间共享的代码 - 将其放在哪里?

    我有两个控制器需要一段代码 但不是全部 这个方法属于哪里呢 我读过有关帮助程序的内容 但那些似乎是用于与视图相关的代码 有人提出了 lib 文件夹 但这似乎离控制器逻辑 太远 我在视图或模型中不需要它 有人遇到过此类问题吗 有三个选项 最简
  • 如何让 Gitlab 6.5 在 Apache 2.4 代理下显示其图标?

    我无法修复由 Apache 2 4 代理的 Gitlab 上的图标 我的失败可能是因为我没有使用乘客 乘客提供了自己的一系列更深层次的问题 但我采取了在代理下运行它的所有步骤 gitlab 我也跑了 sudo u git H bundle
  • 如何重写 CursorAdapterbindView

    我正在尝试显示来自Cursor in a ListView 每行包含一个ImageView and a TextView 我有一个CustomCursorAdapter延伸CursorAdapter in bindView我评估来自光标的数
  • 数据仓库 - 具有多对多关系的缓慢变化的维度

    举个例子 假设我有一个包含两个维度和一个度量的事实表 事实货币表 项目密钥 int PersonKey 整数 现金金额 两个维度的定义如下 DimProject 0 型维度 即静态 项目密钥 int 项目名称 varchar 50 DimP
  • Glide 预加载不保存在缓存中

    我想在向用户显示图像之前预加载图像 我有一个 ViewPager 其中每个页面都是一张图像 当活动开始时 它会调用 Glide with this load uri preload 之后 所有图像都被预加载 理论上 为了测试预加载是否有效
  • 编写一个简单的语法解析器

    这就是我想做的 在 Php 中 给定一个字符串 得到如下结果 a b c a 是一个返回 true 或 false 的函数 这应该给b or c打电话后a a b d e c 同样的原则 最终结果应该是d e or c a b d e c