Es ist völlig möglich und es funktioniert gut einmal eingerichtet. Leider ist die Dokumentation über den reinen C++ Flex/Bison Lexer-Parser nicht so einfach zu finden und zu folgen.
Ich kann Ihnen ein Barebone eines Parsers aussetzen, den ich geschrieben habe, aber es ist nur ein Beispiel dafür, wie Sie es tun könnten.
Beachten Sie, dass ein Teil dieses Codes durch Versuch und Irrtum eingerichtet wurde, da Dokumentation selten ist, so dass es überflüssige Operationen oder Dinge, die nicht genau richtig sind, aber es funktioniert.
YPP Datei
%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);
}
Hier können Sie C++ verwenden, überall, zum Beispiel
%type<std::list<Statement*>> statement_list for_statement
...
statement_list:
{ $$ = std::list<Statement*>(); }
| statement_list statement { $1.push_back($2); $$ = $1; }
;
l Datei
%{
#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();
%}
Dann Sie eine Header-Datei benötigen, die definiert, Ihre Lexer
Klasse, die von erben wird, dass ich s, wie C++ Flex arbeitet, die so etwas wie
#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;
};
}
Der letzte Schritt Ihre Compiler-Klasse ist die Definition, die von den Bison Grammatikregeln genannt wird erhalten (das ist, was parse-param
Attribute in YPP-Datei sind für). Etwas wie:
#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(); }
};
}
Jetzt können Sie execute Parsen leicht und vollständig vorbei C++ Code, zB:
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;
}
Das einzige, was man darauf achten muss, ist flex
auf der .l
Datei mit -c++
Argument aufzurufen damit es einen C++ - Lexer erzeugt.
Eigentlich mit einigen sorgfältigen Operationen konnte ich auch mehrere unabhängige und selbstregulierende Lexer/Parser im selben Projekt haben.
Vollständig erklärt hier: https: // bitbucket.org/emmetac/miscellany/src/master/flex/bison-cxx-beispiel/ – Emmet
Ich benutzte es genau vor 25 Jahren für genau diesen Zweck. Natürlich funktioniert es. – EJP