从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 的相关文章

  • 如何验证文件名称在 Windows 中是否有效?

    是否有一个 Windows API 函数可以将字符串值传递给该函数 该函数将返回一个指示文件名是否有效的值 我需要验证文件名是否有效 并且我正在寻找一种简单的方法来完成此操作 而无需重新发明轮子 我正在直接使用 C 但针对的是 Win32
  • 是否可以强制 XMLWriter 将元素写入单引号中?

    这是我的代码 var ptFirstName tboxFirstName Text writer WriteAttributeString first ptFirstName 请注意 即使我使用 ptFirstName 也会以双引号结束 p
  • Qt-Qlist 检查包含自定义类

    有没有办法覆盖加载自定义类的 Qt QList 的比较机制 即在 java 中你只需要重写一个比较方法 我有一个带有我的自定义类模型的 QList QList
  • 将数组向左或向右旋转一定数量的位置,复杂度为 o(n)

    我想编写一个程序 根据用户的输入 正 gt 负 include
  • pthread_cond_timedwait() 和 pthread_cond_broadcast() 解释

    因此 我在堆栈溢出和其他资源上进行了大量搜索 但我无法理解有关上述函数的一些内容 具体来说 1 当pthread cond timedwait 因为定时器值用完而返回时 它如何自动重新获取互斥锁 互斥锁可能被锁定在其他地方 例如 在生产者
  • linux perf:如何解释和查找热点

    我尝试了linux perf https perf wiki kernel org index php Main Page今天很实用 但在解释其结果时遇到了困难 我习惯了 valgrind 的 callgrind 这当然是与基于采样的 pe
  • C++ 子字符串返回错误结果

    我有这个字符串 std string date 20121020 我正在做 std cout lt lt Date lt lt date lt lt n std cout lt lt Year lt lt date substr 0 4 l
  • 实时服务器上的 woff 字体 MIME 类型错误

    我有一个 asp net MVC 4 网站 我在其中使用 woff 字体 在 VS IIS 上运行时一切正常 然而 当我将 pate 上传到 1and1 托管 实时服务器 时 我得到以下信息 网络错误 404 未找到 http www co
  • Newtonsoft JSON PreserveReferences处理自定义等于用法

    我目前在使用 Newtonsoft Json 时遇到一些问题 我想要的很简单 将要序列化的对象与所有属性和子属性进行比较以确保相等 我现在尝试创建自己的 EqualityComparer 但它仅与父对象的属性进行比较 另外 我尝试编写自己的
  • 将布尔参数传递给 SQL Server 存储过程

    我早些时候问过这个问题 我以为我找到了问题所在 但我没有 我在将布尔参数传递给存储过程时遇到问题 这是我的 C 代码 public bool upload false protected void showDate object sende
  • 在 Visual Studio 2008 上设置预调试事件

    我想在 Visual Studio 中开始调试程序之前运行一个任务 我每次调试程序时都需要运行此任务 因此构建后事件还不够好 我查看了设置的 调试 选项卡 但没有这样的选项 有什么办法可以做到这一点吗 你唯一可以尝试的 IMO 就是尝试Co
  • C#:如何防止主窗体过早显示

    在我的 main 方法中 我像往常一样启动主窗体 Application EnableVisualStyles Application SetCompatibleTextRenderingDefault false Application
  • Json.NET - 反序列化接口属性引发错误“类型是接口或抽象类,无法实例化”

    我有一个类 其属性是接口 public class Foo public int Number get set public ISomething Thing get set 尝试反序列化Foo使用 Json NET 的类给我一条错误消息
  • 指针减法混乱

    当我们从另一个指针中减去一个指针时 差值不等于它们相距多少字节 而是等于它们相距多少个整数 如果指向整数 为什么这样 这个想法是你指向内存块 06 07 08 09 10 11 mem 18 24 17 53 7 14 data 如果你有i
  • 如何返回 json 结果并将 unicode 字符转义为 \u1234

    我正在实现一个返回 json 结果的方法 例如 public JsonResult MethodName Guid key var result ApiHelper GetData key Data is stored in db as v
  • vector 超出范围后不清除内存

    我遇到了以下问题 我不确定我是否错了或者它是一个非常奇怪的错误 我填充了一个巨大的字符串数组 并希望在某个点将其清除 这是一个最小的例子 include
  • C# 中的递归自定义配置

    我正在尝试创建一个遵循以下递归结构的自定义配置部分
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • Discord.net 无法在 Linux 上运行

    我正在尝试让在 Linux VPS 上运行的 Discord net 中编码的不和谐机器人 我通过单声道运行 但我不断收到此错误 Unhandled Exception System Exception Connection lost at
  • WCF:将随机数添加到 UsernameToken

    我正在尝试连接到用 Java 编写的 Web 服务 但有些东西我无法弄清楚 使用 WCF 和 customBinding 几乎一切似乎都很好 除了 SOAP 消息的一部分 因为它缺少 Nonce 和 Created 部分节点 显然我错过了一

随机推荐

  • 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