Parsing einer Grammatik mit Boost Spirit
Ich versuche zu analysieren, eine C-Funktion wie Baum Ausdrücke wie den folgenden (mit Hilfe der Spirit-Parser-Framework):
F( A() , B( GREAT( SOME , NOT ) ) , C( YES ) )
Dafür bin ich zu versuchen, die drei Regeln auf der folgenden Grammatik:
template< typename Iterator , typename ExpressionAST >
struct InputGrammar : qi::grammar<Iterator, ExpressionAST(), space_type> {
InputGrammar() : InputGrammar::base_type( ) {
tag = ( qi::char_("a-zA-Z_") >> *qi::char_("a-zA-Z_0-9") )[ push_back( at_c<0>(qi::_val) , qi::_1 ) ];
command = tag [ at_c<0>(qi::_val) = at_c<0>(qi::_1) ] >> "(" >> (*instruction >> ",")
[ push_back( at_c<1>(qi::_val) , qi::_1 ) ] >> ")";
instruction = ( command | tag ) [qi::_val = qi::_1];
}
qi::rule< Iterator , ExpressionAST() , space_type > tag;
qi::rule< Iterator , ExpressionAST() , space_type > command;
qi::rule< Iterator , ExpressionAST() , space_type > instruction;
};
Feststellen, dass mein-tag-Regel nur zu erfassen versucht die Bezeichner verwendet, die in die Ausdrücke (die 'Funktion' Namen). Beachten Sie auch, dass die Unterschrift von der tag-Regel gibt einen ExpressionAST
statt einer std::string
, wie in den meisten Beispielen. Der Grund ich will es so machen ist eigentlich ziemlich einfach: ich hasse es mit Varianten, und ich werde Sie vermeiden, wenn möglich. Es wäre toll, halten den Kuchen und ihn auch Essen, denke ich.
Ein-Befehl sollte mit einem start-tag (der name des aktuellen Knotens, erste string-Feld der AST-Knoten) und eine variable Anzahl von Argumenten in Klammern eingeschlossen, und jedes der Argumente kann ein tag sein, sich selbst oder einen anderen Befehl.
In diesem Beispiel jedoch überhaupt nicht funktioniert. Es kompiliert und alles, aber zur Laufzeit scheitert es zu analysieren, alle meine test-strings. Und die Sache, die wirklich mich ärgert ist, dass ich kann nicht herausfinden, wie es zu beheben, da kann ich nicht wirklich Debuggen der oben genannten code, zumindest in der traditionellen Bedeutung des Wortes. Im Grunde die einzige Möglichkeit, die ich sehe, kann ich beheben, der obige code ist von dem wissen, was ich falsch mache.
So, die Frage ist, dass ich nicht weiß, was falsch ist mit dem obigen code. Wie definieren Sie die obige Grammatik?
Den ExpressionAST
Typ, den ich verwende, ist:
struct MockExpressionNode {
std::string name;
std::vector< MockExpressionNode > operands;
typedef std::vector< MockExpressionNode >::iterator iterator;
typedef std::vector< MockExpressionNode >::const_iterator const_iterator;
iterator begin() { return operands.begin(); }
const_iterator begin() const { return operands.begin(); }
iterator end() { return operands.end(); }
const_iterator end() const { return operands.end(); }
bool is_leaf() const {
return ( operands.begin() == operands.end() );
}
};
BOOST_FUSION_ADAPT_STRUCT(
MockExpressionNode,
(std::string, name)
(std::vector<MockExpressionNode>, operands)
)
- Etwas, das ich herausgefunden vor kurzem, dass C-und C++ - Bezeichner kann '$' Zeichen im Namen. So dass a-z, A-Z, 0-9 (außer für das erste Zeichen), _ und $ gültig sind, in ein C/C++ - Bezeichner.
- MSVC erlaubt Sonderzeichen in Bezeichnern. Bedeutet nicht, es ist standard-konform.
- Noch wichtiger ist, was ist der Punkt, den Sie versuchen zu machen @Cthutu? Ist es ein Mangel in IDS? Hat dein compiler keine Unterstützung für namespaces, richtig?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Soweit Debuggen, ist es möglich, um eine normale Pause und sehen Ansatz. Erschwerend ist, wie Sie formatiert habe die Regeln aber. Wenn Sie format pro den Geist Beispielen (~ein parser pro line, einer phoenix-Anweisung pro Zeile), break werden die Punkte viel mehr informativ.
Ihre Daten-Struktur nicht zu unterscheiden
A()
ausSOME
sind, als Sie die beiden Blätter (lassen Sie mich wissen, wenn ich etwas fehlt). Von deiner Variante Kommentar, ich glaube nicht, dass dies Ihre Absicht war, so eine Unterscheidung zwischen diesen beiden Fällen, habe ich einbool commandFlag
member-variable MockExpressionNode (gilt fürA()
und false fürSOME
), mit einer entsprechenden fusion-adapter line.Für den speziellen code, den Sie brauchen, um passieren der start-Regel zu den Basis-Konstruktor, D. H.:
Dies ist der Einstiegspunkt in die Grammatik, und die ist, warum Sie wurden nicht immer alle Daten analysiert. Ich bin überrascht, dass es kompiliert, ohne es, dachte ich, dass die Grammatik Typ war erforderlich, um den Typ der die erste Regel. Sogar so, dies ist eine bequeme Konvention zu Folgen.
Für die
tag
Regel, es gibt tatsächlich zwei Parserqi::char_("a-zA-Z_")
, das _1 mit Typ -char
und*qi::char_("a-zA-Z_0-9")
was _2 mit Typ (im Grunde)vector<char>
. Ist nicht möglich, jemanden zu nötigen, diese in einen string, ohne autorules, Aber es kann getan werden durch das anbringen einer Regel, die auf jedes Analysierte char:Allerdings, die viel sauberer zu lassen Geist diese Konvertierung. So definieren Sie eine neue Regel:
Und Mach dir keine sorgen ;). Dann tag wird
For-Befehl, der erste Teil ist in Ordnung, aber es gibt ein paar Probleme mit
(*instruction >> ",")[ push_back( at_c<1>(qi::_val) , qi::_1 ) ]
. Diese analysieren die null oder multiple instruction Regeln, gefolgt von einem ",". Es wird auch versucht, push_back einvector<MockExpressionNode>
(nicht sicher, warum dieser kompiliert entweder, vielleicht nicht instanziiert werden, da der fehlende start-Regel?). Ich denke, Sie wollen das folgende (mit der id änderung):Diese nutzt die optional Bediener
-
und den Betreiber der Liste%
letzteres ist äquivalent zuinstruction >> *("," >> instruction)
. Die phoenix-Ausdruck dann nur weist der Vektor direkt in die Struktur Mitglied, aber Sie können auch befestigen Sie die action direkt zu der Anleitung passen und benutzen Sie push_back.Die Anweisung-Regel ist gut, werde ich nur erwähnen, dass es äquivalent zu
instruction %= (command|tag)
.Eine Letzte Sache, wenn es tatsächlich keine Unterscheidung zwischen
A()
undSOME
(d.h. Ihre ursprüngliche Struktur mit keinecommandFlag
), schreiben Sie diese parser mit nur autorules:Dies ist der große Vorteil der Verwendung einer fusion gewickelt, Struktur, Modelle der Eingang eng.
void setAsFlag(bool flag)
):phoenix::bind(&ExpressionAST::setAsFlag, qi::_val, true)
.