语法平衡问题

2023-12-29

是否可以强制灵气提升以这种方式表现,生成的语法可以根据一些运行时可计算的条件/规则/速率进行调整?例如,输入由语言结构组成,这会在解析过程中导致不同的选择,有些更频繁,另一些则更少。但替代方案的顺序会影响效率,即语法的运行时最优性。在某些情况下,不可能提前确定在任意输入(可能是强聚类)的情况下将更频繁地选择哪种替代方案。

我知道可以附加符号qi::symbols在运行时,但对于其他一些解析器来说,类似的行为也是可取的。


遗憾的是您忘记了(?)包含示例语法。所以我自己做了一个。它解析这样的语言:

begin
    declare x : int;
    declare y : string;

    let x = 42;
    let y = "Life the universe and everything";

    for(ch : y)
    begin
        if (call is_alpha(ch))
        begin
            declare z : string;
            let z = call to_upper(ch);
            call print(z);
        end; 
        else call print("?");
    end;
end;

现在。您可能会注意到,每个“语言构造”(正如您在OP中提到的那样)都有一个介绍关键字。这是故意的。

因为,现在我们可以使用qi::symbols使用这些介绍者关键字来调度规则(这称为 Nabialek 技巧):

// let's have some language constructs
feature_vardecl    = identifier >> ':' >> type >> ';';
feature_assignment = identifier >> "=" >> expression >> ';';
feature_block      = *statement >> kw["end"] >> ';' | statement;
feature_forloop    = '(' >> identifier >> ':' >> identifier > ')' >> statement;
feature_func_call  = invocation > ';';
feature_if         = ('(' > expression > ')' > statement) >> (kw["else"] > statement);

language_constructs.add
    ("declare", &feature_vardecl)
    ("let",     &feature_assignment)
    ("begin",   &feature_block)
    ("if",      &feature_if)
    ("for",     &feature_forloop)
    ("call",    &feature_func_call);

可以看到,我们将对应语法规则的地址作为值存储在字典中。现在,我们采用纳比亚莱克技巧(使用qi::_a本地调用子规则):

statement  = 
      (kw[language_constructs] [ qi::_a = qi::_1 ] > qi::lazy(*qi::_a))
    | (expression > ';');

如果您想要更“轻量级”的语法,您只需删除一些功能即可:

language_constructs.add
    ("let",     &feature_assignment)
    ("begin",   &feature_block)
    ("call",    &feature_func_call);

You could甚至动态添加功能language_constructs响应输入(例如输入中的版本标识符,或者只是在解析失败时)。我不确定这是否是一个好主意,但是......这都是可能的。


解析上述程序的功能齐全的示例(如果在input.txt)完成特别的“单元测试”、不同的关键字检查支持、调试等:

See it 住在科利鲁 http://coliru.stacked-crooked.com/a/45645a23834913bd

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/repository/include/qi_distinct.hpp>
#include <fstream>

namespace qi = boost::spirit::qi;
namespace phx= boost::phoenix;

using It      = std::string::const_iterator;
using Skipper = qi::space_type;
using Rule    = qi::rule<It, Skipper>;

template <typename G, size_t N>
    bool test(const char (&raw)[N], const G& grammar)
{
    std::string const input(raw, raw+N-1);
    auto f(std::begin(input)), l(std::end(input));
    try
    {
        bool ok = qi::phrase_parse(f, l, grammar, qi::space);
        // if (f!=l) std::cerr << "remaining unparsed: '" << std::string(f,l) << "'\n";
        return ok && (f == l); 
    } catch (qi::expectation_failure<It> const& e)
    {
        // std::cout << "Expectation failure '" << e.what() << "' at '" << std::string(e.first, e.last) << "'\n";
        return false;
    }
}

template <typename It, typename Skipper>
struct toy_grammar : qi::grammar<It, Skipper>
{
    toy_grammar() : toy_grammar::base_type(start)
    {
        using boost::spirit::repository::distinct;
        static const auto kw = distinct(qi::char_("a-zA-Z_0-9"));

        keywords.add("let")("declare")("begin")("end")("for")("call")("if")("else");

        identifier = !kw[keywords] >> qi::lexeme [ qi::alpha >> *qi::char_("a-zA-Z_0-9") ];

        assert( test("z", identifier));
        assert( test("Afgjkj_123123", identifier));
        assert(!test("1", identifier));

        type       = qi::lexeme [ kw["int"] | kw["double"]| kw["string"] | kw["boolean"]];

        assert( test("int",     type));
        assert( test("double",  type));
        assert( test("string",  type));
        assert( test("boolean", type));
        assert(!test("intzies", type));
        assert(!test("Int",     type));

        literal    = qi::lexeme [
                    qi::real_parser<double, qi::strict_real_policies<double>>()
                    | qi::int_
                    | qi::as_string ['"' >> *~qi::char_('"') >> '"']
                    | kw [ qi::bool_ ]
                    ];

        assert( test("42",     literal));
        assert( test("42.",    literal));
        assert( test(".0",     literal));
        assert( test("-3e+7",  literal));
        assert( test("-inf",   literal));
        assert( test("-99",    literal));
        assert( test("\"\"",   literal));
        assert( test("\"\0\"", literal));
        assert( test("true",   literal));
        assert( test("false",  literal));
        assert(!test("trueish",literal));
        assert(!test("yes",    literal));

        invocation = identifier > '(' > -(expression % ',') > ')';

        // arhem, this part left as an exercise for the reader :)
        expression = literal | identifier | (kw["call"] > invocation); 

        assert( test("-99",       expression));
        assert( test("\"santa\"", expression));
        assert( test("clause",    expression));
        assert( test("true",      expression));
        assert( test("call foo()",    expression));
        assert( test("call foo(bar, inf, false)", expression));
        assert(!test("call 42()",     expression));

        // let's have some language constructs
        feature_vardecl    = identifier >> ':' >> type >> ';';
        feature_assignment = identifier >> "=" >> expression >> ';';
        feature_block      = *statement >> kw["end"] >> ';' | statement;
        feature_forloop    = '(' >> identifier >> ':' >> identifier > ')' >> statement;
        feature_func_call  = invocation > ';';
        feature_if_else    = ('(' > expression > ')' > statement) >> (kw["else"] > statement);

        language_constructs.add
            ("declare", &feature_vardecl)
            ("let",     &feature_assignment)
            ("begin",   &feature_block)
            ("if",      &feature_if_else)
            ("for",     &feature_forloop)
            ("call",    &feature_func_call);

        statement  = 
              (kw[language_constructs] [ qi::_a = qi::_1 ] > qi::lazy(*qi::_a))
            | (expression > ';');

        assert( test("declare x : int;"                                       , statement));
        assert( test("let y = true;"                                          , statement));
        assert( test("call foo();",                                             statement));
        assert( test("call foo(bar, inf, false);",                              statement));

        assert( test("begin end;",                                              statement));
        assert( test("begin let y = x; end;",                                   statement));
        assert( test("begin let y = x; call foo(y); end;",                      statement));
        assert( test("for (x : collection) begin let y = x; call foo(y); end;", statement));

        BOOST_SPIRIT_DEBUG_NODES((identifier)(type)(literal)(expression)(invocation)(statement)
                (feature_vardecl)(feature_assignment)(feature_block)(feature_forloop)(feature_func_call)(feature_if_else)
                );

        start = statement;
    }
  private:
    qi::symbols<char, Rule const*> language_constructs;
    qi::symbols<char, qi::unused_type> keywords;

    Rule start,
         identifier, type, literal, expression, invocation, 
         feature_assignment, feature_vardecl, feature_block, feature_forloop, feature_func_call, feature_if_else;

    qi::rule<It, Skipper, qi::locals<Rule const*> > statement;
};

int main()
{
    using namespace std;
    ifstream ifs("input.txt", ios::binary);
    string const input(istreambuf_iterator<char>(ifs), {});

    auto f(begin(input)), l(end(input));
    try
    {
        static const toy_grammar<It, Skipper> p;
        bool ok = qi::phrase_parse(
                f, l,
                p,
                qi::space);

        assert(ok);

        if (f!=l)
            cout << "Program remaining unparsed: '" << string(f,l) << "'\n";
    } catch (qi::expectation_failure<It> const& e)
    {
        cout << "Expectation failure '" << e.what() << "' at '" << string(e.first, e.last) << "'\n";
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

语法平衡问题 的相关文章

  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 如何在 Cassandra 中存储无符号整数?

    我通过 Datastax 驱动程序在 Cassandra 中存储一些数据 并且需要存储无符号 16 位和 32 位整数 对于无符号 16 位整数 我可以轻松地将它们存储为有符号 32 位整数 并根据需要进行转换 然而 对于无符号 64 位整
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 无限循环与无限递归。两者都是未定义的吗?

    无副作用的无限循环是未定义的行为 看here https coliru stacked crooked com view id 24e0a58778f67cd4举个例子参考参数 https en cppreference com w cpp
  • 用于 FTP 的文件系统观察器

    我怎样才能实现FileSystemWatcherFTP 位置 在 C 中 这个想法是 每当 FTP 位置添加任何内容时 我都希望将其复制到我的本地计算机 任何想法都会有所帮助 这是我之前问题的后续使用 NET 进行选择性 FTP 下载 ht
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • x:将 ViewModel 方法绑定到 DataTemplate 内的事件

    我基本上问同样的问题这个人 https stackoverflow com questions 10752448 binding to viewmodels property from a template 但在较新的背景下x Bind V
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 实例化类时重写虚拟方法

    我有一个带有一些虚函数的类 让我们假设这是其中之一 public class AClassWhatever protected virtual string DoAThingToAString string inputString retu
  • 编译时展开 for 循环内的模板参数?

    维基百科 here http en wikipedia org wiki Template metaprogramming Compile time code optimization 给出了 for 循环的编译时展开 我想知道我们是否可以
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • C++ 中的 include 和 using 命名空间

    用于使用cout 我需要指定两者 include
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 从 mvc 控制器使用 Web api 控制器操作

    我有两个控制器 一个mvc控制器和一个api控制器 它们都在同一个项目中 HomeController Controller DataController ApiController 如果我想从 HomeController 中使用 Dat

随机推荐

  • 带有蒙版的 svg 在 chrome 上看不到

    我正在尝试使用 React 动态创建的一些 svg 路径进行掩码 问题是生成的 html 代码无法立即在 Chrome 和 Safari 上正确呈现 调整浏览器窗口大小或从检查器中选中 取消选中样式属性时会出现正确的结果 我觉得问题出在其中
  • Google Cloud LB:更改“服务器错误”默认 html 页面

    默认情况下 如果负载平衡找不到将流量重定向到的后端 例如 如果所有可用后端都已关闭 则会显示以下 html 页面 成绩单 错误 服务器错误 服务器遇到临时错误 无法完成您的请求 请在 30 秒后重试 我想使用我自己的静态 html 页面 我
  • 替换 IE 的 Twitter Bootstrap 导航栏中的背景

    我正在尝试用我自己的图像替换 Twitter Bootstrap 导航栏的背景图像 它适用于 Chrome Firefox 和 Safari 但不适用于 Internet Explorer 我对 IE 缺少什么 在IE中仍然是纯黑色 nav
  • 如何签署 XLA(Excel 加载项)?

    可以通过代码做到这一点吗 也许有可能 但据我所知 任何预构建的 API 都无法做到这一点 如果您可以从代码中签署代码 它将允许自我修改保持签名状态 这将是一个安全问题 现在 VBA 确实允许二进制读 写 您可以在应用程序上安装一个监视器 观
  • vb.net 无法 Console.SetWindowPosition

    我正在 VB NET 中创建 Windows 控制台应用程序 但无法设置相对于屏幕的窗口位置 简而言之 我想要一个使窗口居中于屏幕的功能 我尝试过使用Console SetWindowPosition w h 方法和Console Wind
  • Excel VBA 对象构造函数和析构函数

    我需要在 VBA 中创建一些需要相互引用的自定义对象 但我遇到了一些问题 首先 VBA 中的对象构造函数如何工作 有构造函数吗 第二 有析构函数吗 VBA 如何处理对象生命周期的结束 如果我有一个引用其他对象的对象 这是它们唯一的引用 那么
  • javascript onmouseout 应用于由孩子触发的 div

    我无法通过谷歌找到解决方案 但我认为这将是一个相当常见的问题 我有一个 div 我已经应用了 onmouseout 事件处理程序 该处理程序用于使用 jquerys slideup 函数滚动菜单 因为我希望鼠标离开时隐藏菜单 问题是该 di
  • 检查 Service Worker 中的窗口是否处于活动状态

    我正在尝试运行一个在窗口处于非活动状态时发送推送通知的 Web 应用程序 为此 我有一个 Service Worker 来帮助接收来自我的 php 服务器的通知 通过 Firebase 但是 我不确定如何通过我的服务工作人员检查窗口是否处于
  • 替换 Google App Engine (GAE) 中的 PIL (ImageDraw) 功能

    因此 Google App Engine 看起来不会包含 Python 图像库 有一个图片API http code google com appengine docs python images 但它微不足道 不足以满足我的需要 我想知道
  • Android 互联网连接检查问题

    我是 Android 开发新手 正在开发一个 Android 应用程序 该应用程序需要手机通过 Wifi EDGE 或 3G 连接到互联网 这是我用来检查互联网连接是否可用的代码 public static boolean isConnec
  • 在文件系统中移动该类后,出现“Class XXX 不是有效实体或映射的超类”

    我在 Aib PlatformBundle Entity User php 中有一个实体类 我尝试通过以下方式创建其表单类没有任何问题 php 应用程序 控制台学说 生成 表单 AibPlatformBundle 用户 现在我已将命名空间更
  • 如何获取文本的子串?

    我的文本长度约为 700 我怎样才能只得到大约 30 个前字符 如果你的文字在your text变量 您可以使用 your text 0 29
  • 在 jQuery 中将 JSON 数组转换为 HTML 表

    有没有一种非常简单的方法可以获取 JSON 对象数组并将其转换为 HTML 表 不包括一些字段 或者我必须手动执行此操作 使用 jQuery 将使这变得更简单 以下代码将获取一个数组数组并将它们存储转换为行和单元格 getJSON url
  • 泽西岛 URL 转发

    在 Jersey REST 方法中 我想转发到另一个网站 我怎样才能做到这一点 Path public class News GET Produces MediaType TEXT HTML Path go news id public S
  • 如何基于通用类型“T”初始化 TypeORM 存储库?

    我想启动一个基于通用类型的 TypeORM 存储库 例如 import Connection Repository from typeorm export class GenericService
  • 输入类型数字“仅数字值”验证

    我如何验证输入type number 仅当值是数字或 null 时才有效 仅使用响应式表单 无指令 仅数字 0 9 和 允许 不允许有 e 或任何其他字符 到目前为止我尝试过的 模板
  • 修改linux内核定时器

    我必须运行延迟敏感的应用程序 并且被要求将计时器分辨率更改为 1000 Hz 或更高 我在网上搜索了一下 找到了有关 CONFIG HZ 等的页面 但是 文件中似乎还有其他几个相关设置 因此我想确保不会弄乱这些设置 我在这里发布一些输出 c
  • C++:指向 std::string 转换的 char 指针是否复制内容?

    当我转换一个char to std string使用构造函数 char ps Hello std string str ps 我知道 std 容器在被要求存储值时倾向于复制值 是复制整个字符串还是仅复制指针 如果之后我这样做str Bye
  • 包“com.sun.webkit.dom”在模块“javafx.web”中声明,该模块不会将其导出到模块

    试图从Java 8 to Java 9 我得到这个错误 包 com sun webkit dom 在模块 javafx web 中声明 其中 不将其导出到模块 我该如何解决这个问题 以便预编译器 Intellij 和运行时我不明白这个问题
  • 语法平衡问题

    是否可以强制灵气提升以这种方式表现 生成的语法可以根据一些运行时可计算的条件 规则 速率进行调整 例如 输入由语言结构组成 这会在解析过程中导致不同的选择 有些更频繁 另一些则更少 但替代方案的顺序会影响效率 即语法的运行时最优性 在某些情