从flex+bison输出AST到main.cpp

2024-02-12

免责声明:虽然我已经完成了本教程,但我是一名 flex-bison 菜鸟:http://ds9a.nl/lex-yacc/cvs/lex-yacc-howto.html http://ds9a.nl/lex-yacc/cvs/lex-yacc-howto.html

现在,我正在为 OPENGL-C++ 项目构建视频游戏。 main.cpp 包含所有游戏图形、逻辑等(相当易于管理,所以不是问题)。在游戏开始之前,它需要解析一个配置文件(假设它是任意格式,所以 INI 和 JSON API 是不可能的)。

我知道足够的 flex 和 bison 来识别文件中的模式并创建 AST(还使用 $ 表示法分配变量。现在,如何使这些变量在 main.cpp 中可用?


根据配置语言的复杂性,使用一次性解析器可能比创建 AST 然后遍历树更好。但这两种方法都是完全有效的。

也许你应该花几分钟(或几个小时:))阅读野牛手册 https://www.gnu.org/software/bison/manual/。在这里,我将只关注一般方法和您可能使用的 bison 功能。

最重要的一项是将额外参数传递到解析器的能力。特别是,您需要将引用或指针传递给将包含已解析配置的对象。您需要额外的输出参数,因为解析器本身只会返回成功或失败指示(您也需要)。

这是一个简单的示例,它仅构造一个名称到字符串的字典。请注意,与您提到的教程的作者不同,我更喜欢将扫描器和解析器编译为 C++,从而避免需要extern "C"接口。这适用于当前版本flex and bison,只要您不尝试将非 POD 对象放入解析器堆栈即可。不幸的是,这意味着我们不能直接使用 std::string ;我们需要使用指针(并且我们也不能使用智能指针。)

文件扫描仪.l

%{
  #include <string>
  #include "config.h"
  using std::string;
%}

%option noinput nounput noyywrap nodefault
%option yylineno
 // Set the output file to a C++ file. This could also be done on the
 // command-line
%option outfile="scanner.cc"

%%

"#".*                      ; /* Ignore comments */
[[:space:]]                ; /* Ignore whitespace */
[[:alpha:]̣_][[:alnum:]_]*  { yylval = new string(yytext, yyleng); return ID; }
[[:alnum:]_@]+             { yylval = new string(yytext, yyleng); return STRING; }
["][^"]*["]                { yylval = new string(yytext+1, yyleng-2); return STRING; }
.                          { return *yytext; }

现在是 bison 文件,它只识别分配。这需要 bison v3;需要进行一些小的调整才能与 bison v2.7 一起使用。

config.y

%code requires {
  #include <map>
  #include <string>
  #include <cstdio>
  using Config = std::map<std::string, std::string>;

  // The semantic type is a pointer to a std::string
  #define YYSTYPE std::string*

  // Forward declarations
  extern FILE* yyin;
  extern int yylineno; 
  int yylex();
  // Since we've defined an additional parse parameter, it will also
  // be passed to yyerror. So we need to adjust the prototype accordingly.
  void yyerror(Config&, const char*);
}

 // Set the generated code filenames. As with the flex file, this is
 // probably
 // better done on the command line.
%output "config.cc"
%defines "config.h"

 // The parser takes an additional argument, which is a reference to the
 // dictionary
 // which will be returned.
%parse-param { Config& config }

%token ID STRING

 // If semantic values are popped off the stack as the result of error
 // recovery,
 // they will leak, so we need to clean up.
%destructor { delete $$; } ID STRING

%%

config: %empty
      | config assignment
      ;

assignment: ID '=' STRING { config[*$1] = *$3;
                            delete $1; delete $3;
                          }
          | ID '=' ID     { config[*$1] = config[*$3];
                            delete $1; delete $3;
                          } 

%%
// The driver would normally go into a separate file. I've put it here
// for simplicity.

#include <iostream>
#include <cstring>

void yyerror(Config& unused, const char* msg) {
  std::cerr << msg << " at line " << yylineno << '\n';
}

int main(int argc, const char** argv) {
  if (argc > 1) {
    yyin = fopen(argv[1], "r");
    if (!yyin) {
      std::cerr << "Unable to open " << argv[1] << ": "
                << strerror(errno) << '\n';
      return 1;
    }
  } else {
    yyin = stdin;
  }
  Config config;
  int rv = yyparse(config);
  if (rv == 0)
    for (const auto& kv : config)
      std::cout << kv.first << ": \"" << kv.second << "\"\n";
  return rv;
}

编译:

flex scanner.l
bison config.y
g++ --std=c++11 -Wall config.cc scanner.cc

试试看:

$ cat sample.config
a=17
b= @a_single_token@
c = "A quoted string"
d9 =
"Another quoted string"
$ ./config sample.config
a: "17"
b: "@a_single_token@"
c: "A quoted string"
d9: "Another quoted string"
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

从flex+bison输出AST到main.cpp 的相关文章

  • 如何将 std::string& 转换为 C# 引用字符串

    我正在尝试将 C 函数转换为std string参考C 我的 API 如下所示 void GetStringDemo std string str 理想情况下 我希望在 C 中看到类似的东西 void GetStringDemoWrap r
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 没有特殊字符的密码验证器

    我是 RegEx 的新手 已经进行了大量搜索 但没有找到任何具体内容 我正在编写一个验证密码字符串的正则表达式 可接受的字符串必须至少具有 4 种字符类型中的 3 种 数字 小写字母 大写字母 特殊字符 我对包含有一个想法 也就是说 如果这
  • 类型中的属性名称必须是唯一的

    我正在使用 Entity Framework 5 并且有以下实体 public class User public Int32 Id get set public String Username get set public virtual
  • 如何在 Cassandra 中存储无符号整数?

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

    std list 线程安全吗 我假设不是这样 所以我添加了自己的同步机制 我认为我有正确的术语 但我仍然遇到问题 每个函数都由单独的线程调用 Thread1 不能等待 它必须尽可能快 std list
  • std::vector 与 std::stack

    有什么区别std vector and std stack 显然 向量可以删除集合中的项目 尽管比列表慢得多 而堆栈被构建为仅后进先出的集合 然而 堆栈对于最终物品操作是否更快 它是链表还是动态重新分配的数组 我找不到关于堆栈的太多信息 但
  • -webkit-box-shadow 与 QtWebKit 模糊?

    当时有什么方法可以实现 webkit box shadow 的工作模糊吗 看完这篇评论错误报告 https bugs webkit org show bug cgi id 23291 我认识到这仍然是一个问题 尽管错误报告被标记为RESOL
  • 无限循环与无限递归。两者都是未定义的吗?

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

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

    我当前正在处理的程序有问题 这是由于 vista Windows 7 中增强的安全性引起的 特别是 UIPI 它阻止完整性级别较低的窗口与较高完整性级别的窗口 对话 就我而言 我想告诉具有高完整性级别的窗口进入我们的应用程序 它在 XP 或
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 人脸 API DetectAsync 错误

    我想创建一个简单的程序来使用 Microsoft Azure Face API 和 Visual Studio 2015 检测人脸 遵循 https social technet microsoft com wiki contents ar
  • 结构体的内存大小不同?

    为什么第一种情况不是12 测试环境 最新版本的 gcc 和 clang 64 位 Linux struct desc int parts int nr sizeof desc Output 16 struct desc int parts
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 如何在 Android 中使用 C# 生成的 RSA 公钥?

    我想在无法假定 HTTPS 可用的情况下确保 Android 应用程序和 C ASP NET 服务器之间的消息隐私 我想使用 RSA 来加密 Android 设备首次联系服务器时传输的对称密钥 RSA密钥对已在服务器上生成 私钥保存在服务器
  • 为什么C++代码执行速度比java慢?

    我最近用 Java 编写了一个计算密集型算法 然后将其翻译为 C 令我惊讶的是 C 的执行速度要慢得多 我现在已经编写了一个更短的 Java 测试程序和一个相应的 C 程序 见下文 我的原始代码具有大量数组访问功能 测试代码也是如此 C 的
  • C# 使用“?” if else 语句设置值这叫什么

    嘿 我刚刚看到以下声明 return name null name NA 我只是想知道这在 NET 中叫什么 是吗 代表即然后执行此操作 这是一个俗称的 条件运算符 三元运算符 http en wikipedia org wiki Tern
  • 如何确定 CultureInfo 实例是否支持拉丁字符

    是否可以确定是否CultureInfo http msdn microsoft com en us library system globalization cultureinfo aspx我正在使用的实例是否基于拉丁字符集 我相信你可以使

随机推荐

  • XElement 添加一个 xmlns

    我正在使用 Linq to XML 创建一个新的 XML 文件 我从现有的 XML 文件中获取该文件的某些部分 我为此使用以下代码 var v2 new XDocument new XDeclaration 1 0 utf 16 new X
  • 使用 Mongoose 更新 _id = :id 的记录

    我正在尝试使用 Mongoose 更新现有记录 插入可以 但更新不行 这是我的片段 app post submit function req res var my visit new models visits date req body
  • 在 RedShift 中将值拆分为多行

    如何将字段 例如 CSV 字符串 拆分为多行的问题已经得到解答 将值拆分为多行 https stackoverflow com questions 13159526 split values over multiple rows 然而 这个
  • 如何在Java Web应用程序中动态设置会话超时?

    我需要为我的用户提供一个 Web 界面来更改会话超时间隔 因此 不同安装的 Web 应用程序的会话超时时间可能不同 但它们的会话超时时间不同 web xml不可能不同 有没有办法以编程方式设置会话超时 以便我可以使用 例如ServletCo
  • Greasemonkey 中未定义“文档”

    不到十分钟前 我决定为 Greasemonkey 编写第一个剧本 我对此的经验为零 另外 我的 JavaScript 有点生疏了 因为自从我上次用它编写代码以来已经有一段时间了 但我不明白为什么 Greasemonkey 给我这个错误 Li
  • PDF压缩库/工具

    我正在开发一个项目来减小 PDF 的大小并对其进行压缩 我想知道市场上是否有任何非常好的工具 库 NET 我确实尝试了一些工具 例如 Onstream Compression 但结果并不令人满意 一些额外的 兆 字节可以很容易地从 PDF
  • 从 Java 应用程序中执行 Pig

    是否可以在 Java 应用程序中运行 Apache Pig 作业 而无需分叉外部进程 Pig 和 Hadoop 似乎都是用 Java 编写的 但并不真正提供 Java API 我宁愿在 Java Spring 应用程序中使用这些工具 而不是
  • 打开本机相机后 Ionic 应用程序崩溃 - 错误 20

    我用的是科尔多瓦camera插件开启ionic 4捕捉一些图像 takePicture console log camera takePicture const options CameraOptions quality 100 desti
  • 使用 RXJava 进行缓存处理

    我正在尝试使用 rxJava 实现此工作流程 但我确定我是否误用或做错了事情 用户要求登录 如果登录结果在缓存中可用 则 发出 缓存的登录结果 否则 如果一切成功 则实际执行对 Web 服务的请求并缓存结果 如果发生错误 最多重试 3 次
  • 为什么我在这个解析器序列中遇到类型错误(Erik Meijer 的讲座 8)?

    我正在观看函数式编程基础知识Erik Meijer 的系列讲座 幻灯片由 Graham Hutton 制作 In 第 8 课 关于函数解析器 https www youtube com watch v OrAVS4QbMqo 定义后Pars
  • 读取多个 xlsx 文件,每个文件都有多个工作表 - purrr

    我有多个 Excel 文件 每个文件都有不同的工作表 我尝试使用 readxl 和 map 将其导入到 R 中 但是 我只能使用 for 循环来完成此操作 下面的代码工作正常 但我想知道是否有一个聪明的方法来做到这一点 我一直认为我可以用
  • Google AppEngine:表单处理“重复”StructuredProperty

    我如何与ndb StructuredProperty 重复 True 设计表单和处理程序时的属性 考虑这个例子 我有 3 种 ndb Model 类型 技术人员 his 教育 和他的 工作 经验 后两者是 SkilledPerson 的 S
  • 如何从数据框中获取特定列中具有最大值的行?

    我有一个像这样的数据框 df show 5 kv list1 list2 p k1 v2 1 2 5 9 5 1 7 9 6 3 1 4 9 0 5 k1 v3 1 2 5 8 9 5 1 7 9 6 3 1 4 15 0 9 k2 v2
  • 最好/常见的 RESTful url 动词和操作是什么?

    我正在尝试查找有关最佳和最常见的 RESTful url 操作的一些信息 例如 您使用什么 URL 来显示项目的详细信息 编辑项目 更新等 question show
  • 需要一个 linq 来生成自身连接

    根据这篇文章为什么 MYSQL 较高的 LIMIT 偏移量会减慢查询速度 https stackoverflow com questions 4481388 why does mysql higher limit offset slow t
  • 无条件地从 T 构造函数调用类 T 的纯虚实现?

    考虑到一个虚拟调用T来自类的构造函数的成员函数 直接或间接 T 最多可以下降到T的实现 执行以下代码 其中不合格的电话 是否有未定义的行为 请注意 为了避免噪音 如果您认为从构造函数调用时实际上不会调用成员函数 那么请不要在此处回答或评论
  • BUFFER_SIZE 在 Tensorflow 数据集改组中起什么作用?

    所以我一直在玩这个代码 https www tensorflow org tutorials generative dcgan https www tensorflow org tutorials generative dcgan并且几乎已
  • 如何在渲染时获取 C# ASP.NET ListView 中当前记录的索引

    我有一个如下所示的列表视图
  • nginx 重定向 POST 请求

    我有一个网络服务器接受https www example com API ooo xxx https www example com API aaa bbb and https www example com API xxx yyy ETC
  • 从flex+bison输出AST到main.cpp

    免责声明 虽然我已经完成了本教程 但我是一名 flex bison 菜鸟 http ds9a nl lex yacc cvs lex yacc howto html http ds9a nl lex yacc cvs lex yacc ho