GNU / Flex C是否可以工作?
引用本书flex& amp;野牛(O’Reilly,John Levine,2009):
在我努力编写一个相当复杂的Flex扫描程序之前,我(我想我们很多人)想知道自2009年以来是否有任何关于这方面的变化.是否有人成功编写Flex / C解析器?如果是这样,是否值得努力,或者C扫描仪是否仍然是最安全的C解析器? 解决方法
这是完全可能的,一旦设置它就会很好用.不幸的是,关于纯C Flex / Bison词法分析器的文档并不那么容易找到和遵循.
我可以向你揭示我编写的解析器的准确性,但这只是你如何做到这一点的一个例子. 请注意,这些代码中的一些是通过反复试验设置的,因为文档很少,所以可能是多余的操作或不完全正确但可行的事情. ypp文件 %skeleton "lalr1.cc" %require "3.0.2" %defines %define api.namespace {script} %define parser_class_name {Parser} %define api.token.constructor %define api.value.type variant %define parse.assert true %code requires { namespace script { class Compiler; class Lexer; } } %lex-param { script::Lexer &lexer } %lex-param { script::Compiler &compiler } %parse-param { script::Lexer &lexer } %parse-param { script::Compiler &compiler } %locations %initial-action { @$.begin.filename = @$.end.filename = &compiler.file; }; %define parse.trace %define parse.error verbose %code top { #include "Compiler.h" #include "MyLexer.h" #include "MyParser.hpp" static script::Parser::symbol_type yylex(script::Lexer &scanner,script::Compiler &compiler) { return scanner.get_next_token(); } using namespace script; } // tokens and grammar void script::Parser::error(const location_type& l,const std::string& m) { compiler.error(l,m); } 例如,您可以在这里使用C. %type<std::list<Statement*>> statement_list for_statement ... statement_list: { $$= std::list<Statement*>(); } | statement_list statement { $1.push_back($2); $$= $1; } ; 我的文件 %{ #include "MyParser.hpp" #include "MyLexer.h" #include "Compiler.h" #include <string> typedef script::Parser::token token; #define yyterminate() script::Parser::make_END(loc); static script::location loc; using namespace script; %} %x sstring %x scomment %option nodefault %option noyywrap %option c++ %option yyclass="Lexer" %option prefix="My" %{ # define YY_USER_ACTION loc.columns((int)yyleng); %} %% %{ loc.step(); %} 然后你需要一个头文件来定义你的Lexer类,它将继承yyFlexLexer,这就是C Flex的工作方式,就像这样 #if ! defined(yyFlexLexerOnce) #undef yyFlexLexer #define yyFlexLexer NanoFlexLexer #include <FlexLexer.h> #endif #undef YY_DECL #define YY_DECL script::Parser::symbol_type script::Lexer::get_next_token() #include "MyParser.hpp" namespace script { class Compiler; class Lexer : public yyFlexLexer { public: Lexer(Compiler &compiler,std::istream *in) : yyFlexLexer(in),compiler(compiler) {} virtual script::Parser::symbol_type get_next_token(); virtual ~Lexer() { } private: Compiler &compiler; }; } 最后一步是定义你的Compiler类,它将从Bison语法规则中调用(这就是ypp文件中parse-param属性的用途).就像是: #include "parser/MyParser.hpp" #include "parser/MyLexer.h" #include "parser/location.hh" #include "Symbols.h" namespace script { class Compiler { public: Compiler(); std::string file; void error(const location& l,const std::string& m); void error(const std::string& m); vm::Script* compile(const std::string& text); bool parseString(const std::string& text); void setRoot(ASTRoot* root); Node* getRoot() { return root.get(); } }; } 现在您可以轻松地执行解析并完全通过C代码,例如: bool Compiler::parseString(const std::string &text) { constexpr bool shouldGenerateTrace = false; istringstream ss(text); script::Lexer lexer = script::Lexer(*this,&ss); script::Parser parser(lexer,*this); parser.set_debug_level(shouldGenerateTrace); return parser.parse() == 0; } 您必须注意的唯一事情是使用-c参数调用.l文件上的flex,以使其生成C词法分析器. 实际上,通过一些谨慎的操作,我也可以在同一个项目中拥有多个独立且可自我重入的词法分析器/解析器. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |