【问题标题】:How do I use C++ in flex and bison?如何在 flex 和 bison 中使用 C++?
【发布时间】:2009-04-22 17:55:28
【问题描述】:

我有一个学校项目,我们需要使用 flex 和 bison。我想使用 C++,以便可以访问 STL 和我自己编写的类。我们获得了以下 Makefile:

CC = gcc 
CFLAGS = -g 

OBJs = parse.tab.o symtab.o attr.o lex.yy.o 

default: parser

parser: ${OBJs}
    ${CC} ${CFLAGS} ${OBJs} -o parser -lfl

lex.yy.c: scan.l parse.tab.h attr.h
    flex -i scan.l

parse.tab.c: parse.y attr.h symtab.h
    bison -dv parse.y

parse.tab.h: parse.tab.c

clean:
    rm -f parser lex.yy.c *.o parse.tab.[ch] parse.output

depend:
    makedepend -I. *.c

scan.l 和 parse.y 有一些初始的 flex/bison 东西来生成扫描器和解析器。我需要将我自己的东西添加到这些文件中。 symtab.{h, c} 应该是符号表的实现。 attr.{h, c} 用于某些属性魔法。我想让 symtab.c 成为 .cc 文件,这样我就可以使用 STL。我还有其他想使用 C++ 的原因。

我尝试使用 parse.ypp 文件,以便生成 .cpp 文件。但问题是我没有得到正确的 .h 文件。我将 Makefile 更改为如下所示:

CC = g++          # Change gcc to g++
CFLAGS = -g 

OBJs = lex.yy.o parse.tab.o symtab.o attr.o

default: lex.yy.c parser    # added lex.yy.c so I could just keep lex stuff in C since I don't really need C++ there

parser: ${OBJs}
    ${CC} ${CFLAGS} ${OBJs} -o parser -lfl

lex.yy.o: scan.l parse.tab.h attr.h      # added this rule to use gcc instead of g++
    gcc -c -o lex.yy.o lex.yy.c

lex.yy.c: scan.l parse.tab.h attr.h
    flex -i scan.l

parse.tab.cpp: parse.ypp attr.h symtab.h
    bison -dv parse.ypp

parse.tab.h: parse.tab.cpp      # I want a parse.tab.h but I get parse.tab.hpp

clean:
    rm -f parser lex.yy.c *.o parse.tab.cpp parse.tab.h parse.output

depend:
    makedepend -I. *.c

谁能告诉我我需要添加什么或做什么才能让 C++ 工作?应该注意的是,我在 .y(或 .ypp)文件中添加了一些东西来处理从 C 到 C++ 的迁移。特别是,我不得不将一些东西声明为 extern。我的主要问题是,当我运行 make 时,scan.l 有一堆语法错误,它们似乎是因为它不能包含 parse.tab.h(因为它从未生成)。

【问题讨论】:

  • 作为记录,flex 具有 -+ 或 --c++ 命令行标志来生成 C++ 词法分析器而不是 C 词法分析器。考虑调查一下,尽管我认为在这种情况下这不是你的问题。

标签: c++ c bison flex-lexer


【解决方案1】:

你不需要对 flex 或 bison 做任何事情来使用 C++,我已经做过很多次了。你只需要确保你使用的是 g++,而不是 gcc。

您的问题在于 Makefile,而不是代码。

【讨论】:

  • 很晚才接受这个:-)...但我记得这是对的,我只需要玩弄我的makefile。谢谢。
【解决方案2】:
For using flex with C++:
 1: read the flex docs:
 2: use flex -+ -o file.cc parser.ll
 3: In the .ll file:

%option c++
%option yyclass="Your_class_name"
%option batch

 4: In your .hh file, derive Your_class_name from  public yyFlexLexer
 5: you can then use your_class_instance.yylex()

【讨论】:

  • 例如,对于我用 scons 构建的 robots.txt flex 解析器,它很简单:thisenv.CXXFile(target='Robots_flex.cc',source='robots.ll') And Robots .cc 构造函数有: Robots::Robots(std::istream* in) : yyFlexLexer(in,0), [...]
【解决方案3】:

有一些差异,您可以详细查看 here.

【讨论】:

    【解决方案4】:

    使用 C 编译器或 C++ 编译器,但不能同时使用两者(直到您知道自己在做什么)。否则,您肯定会用双脚多次射击自己。混合 gcc 和 g++ 不好。

    这条线是可疑的:

    lex.yy.o: scan.l parse.tab.h attr.h      # added this ...
    gcc -c -o lex.yy.o lex.yy.c
    

    另外,您似乎没有在任何地方使用CC,使用它会让生活更轻松。

    假设您不更改 C 代码的任何一行,您可能会遇到一些错误和相当多的警告(如已弃用的标头等)。您还必须修复它们。

    【讨论】:

      【解决方案5】:

      如果您使用 C++ 进行解析器,我建议您查看 Boost Spirit。它比 bison/yacc 好用得多。

      来自here:

      Spirit 是一个使用模板元编程技术实现的面向对象的递归下降解析器生成器框架。表达式模板允许我们在 C++ 中完全近似扩展巴科斯范式 (EBNF) 的语法。

      【讨论】:

      • 我不同意。我都试过了,而且我更喜欢野牛(尽管我更喜欢 ANTLR 而不是两者)。将 EBNF 融入 C++ 所需的怪异语法使得语法难以阅读。
      • 在这种情况下不是一个选项,因为他的项目需要使用 bison/flex。此外,并非 C++ 中的所有内容都需要使用 Boost 来完成。
      • Spirit 是目前最糟糕且过于复杂的 C++ 库之一。如果有的话,这只不过是一次异想天开的尝试,看看在 C++ 中可以重载什么样的运算符。
      • 此外,Spirit 非常不稳定。即使是最简单的示例也无法从一个版本编译到下一个版本,通常只是出现非解释性编译器错误。
      • 其他评论者不喜欢 Spirit。其实我挺喜欢Spirit的。它相当合理地使用运算符重载,并且像宣传的那样工作。它非常适合替换对 JSON、CSV 等小东西的临时解析。但是,在几个不平凡的项目中认真尝试使用它后,我发现它功能强大且性能卓越,但使用起来有些乏味不仅仅是小语法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-08-17
      • 2019-10-26
      • 2021-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      相关资源
      最近更新 更多