2

这是一个多部分的问题。首先,我的输入文件将如下所示:

category Shoes brand:char[50],cost:int
category Shirts brand:char[20],cost:int

我的问题是:

a.) 如何:仅在类别名称之后拆分行?ShoesShirts在这些情况下。

b.) 我将如何编写我的 Bison 解析器,以便确定char[30]保存每一行信息的结构的变量(例如 )?

如果这些问题看起来过于本地化,如果我能被引导到一些可以帮助我做同样事情的资源,我将不胜感激

4

3 回答 3

5

遗漏的细节太多了。例如,“int”可以用作类别名称吗?你打算如何存储你解析的数据?

尽管如此,解析器的初始草图将是这样的:

%token CATEGORY "category"
       EQ       "="
       COLON    ":"
       COMMA    ","
       LBRA     "["
       RBRA     "]"
       INT      "int"
       CHAR     "char"
       ID
       NATURAL
;
%%    
categories:
  category
| categories category
;

category:
  "category" ID fields
;

fields:
  field
| fields "," field
;

field:
  ID ":" type
;

type:
  "char"
| "int"
| type "[" NATURAL "]"
;

这对于扫描仪:

%%
"category"   return CATEGORY;
"="          return EQ;
":"          return COLON;
","          return COMMA;
"["          return LBRA;
"]"          return RBRA;
"int"        return INT;
"char"       return CHAR;
[a-zA-Z]+    return ID;
[0-9]+       return NATURAL;
[ \n\t]+     continue;
于 2013-03-18T12:56:30.857 回答
2

(b.) 我不确定我是否正确理解了你的问题。我假设您要解析输入文件中的每个条目并将信息存储在结构中。Category 和 Brand 是字符串,cost 是 int。您想事先知道字符串的长度,因此您可以分配一个变量来保存解析后的值(例如 char[20])。

为什么不使用 C++ 字符串?那么你不必声明长度。这里的例子。如果必须使用 C,则可以只使用 char * 并使用 malloc 在堆上分配字符串。

于 2013-03-18T08:36:30.663 回答
0

此页面有一个合理、简单的示例,可以作为您尝试做什么的指南。编写 flex/bison 解析器的完整一般过程是:

  1. 确定标记是什么,编写一个正则表达式并为每个标记选择一个标识符(就像@akim 在他的 flex/bison 代码中所做的那样)。
  2. 为您尝试解析的“合法”输入编写 LALR(1) 上下文无关语法。@akim 在这方面为您提供了帮助。
  3. 设计一个目标数据结构来保存解析器结果。这是您帖子中缺少的关键内容。如果你只是想计算一个整数大小,那么你就完成了。如果您需要传递更多细节以进行进一步处理,您将需要某种记录/枚举/列表结构,通常称为抽象语法树或 AST,即使它通常不是真正的树。
  4. 实现 AST(如有必要)数据结构,包括构造函数,如CATEGORY_NODE make_category(enum category_e cat);. 这些构造函数将被解析器调用。
  5. 在没有操作代码的 flex 扫描程序文件中实现令牌。
  6. 在野牛解析器程序文件中实现 CFG,无需操作代码。
  7. 构建一个测试框架和一个测试套件,并测试扫描器和解析器是否读取合法输入并拒绝错误输入。到目前为止,该程序什么也没做。这就是@akim 的代码现在所在的位置。
  8. 决定哪些数据必须与每个令牌相关联(如果有)。例如,无符号数的值是从扫描仪返回的大小为unsigned int. 标识符的值将是一个字符串。但是括号[根本没有任何价值。使用这些类型来创建 bison%union指令以接受来自扫描仪的值。将这些作为<union_field>标签添加到相应的%token指令中。请参阅@union此处使用的示例,它有两种标记值类型。
  9. 通过在顶部添加一个并添加操作代码来修复flex扫描仪,以返回相应令牌的正确令牌值。#include "foo.tab.h"此时一切都应该再次编译并运行,但仍然什么都不做。再次参考示例。
  10. 现在在解析器中实现数据处理。您将使用美元$n$$指令并将<union_field>类型标签添加到语法非终结符以在语法规则之间移动数据,最后调用 AST 结构的构造函数以在读取输入时构建结构(或增加整数,如果这是就是这样)。这就是 LALR 解析器的经验和更深入的知识很有帮助的地方。文档中后面的示例Bison是这部分的另一个参考。如果遇到障碍,请返回具体问题。
  11. 再次运行测试并以您可以验证的形式打印生成的 AST。XML 可以很好地解决这个问题。

现在我敢肯定,有人会注意到这种完全通用的方法对于您迄今为止所要求的内容来说太过分了。这取决于。您当前的输入非常简单,您可能可以更快地手写一个小的临时解析器,根本不使用 flex 或 bison。

但是,如果您正在编写的程序可能会使用一段时间并随着时间的推移而改变,那么在一开始就准备好通用解析器的所有机制可以让生活变得更轻松。将程序输入视为一种真实的语言而不仅仅是原始数据,可以引导您创建您永远不会想到的功能。

于 2013-03-24T17:21:38.023 回答