2016-06-19 6 views
3

Ich versuche, einen Parser zu schreiben, der entweder eine int32_t oder eine double analysiert. Als erster Versuch schrieb ich diesen Parser:boost spirit x3 int32 | double_ kann nicht doppelt parsen

const auto int_or_double = boost::spirit::x3::int32 | boost::spirit::x3::double_; 

, die ich erwarte einen boost::variant<int32_t, double> die Parser gelingen, um wieder zu ints wie 12, 100, -42, 7 zu analysieren aber es funktioniert nicht verdoppelt, wie 13.243, 42.7, 12.0 -10000.3

hier ein Live ist zu analysieren, demo

Warum scheitert dieser Parser im Doppel?

Antwort

5

Ihr Problem ist sehr ähnlich zu this question.

Wenn der Integer-Parser in Ihrer Grammatik zuerst auftritt, wird er bevorzugt. Bei der Eingabe "12.9" parst der Parser den ganzzahligen Teil von "12.9, der 12 ist, und stoppt bei .. live example

Sie haben die Reihenfolge umzukehren, so dass die Doppel-Parser über die ganze Zahl ist bevorzugt ein:

const auto double_or_int = boost::spirit::x3::double_ | boost::spirit::x3::int32; 

Dies wird nun arbeiten für "12.9": live example

Da jedoch ein Doppel Parser analysiert auch eine Ganzzahl, Sie erhalten immer eine doppelte, auch wenn die Eingabe "12" ist: live example

Um dies zu verhindern, müssen Sie eine strenge Doppel Parser:

boost::spirit::x3::real_parser<double, boost::spirit::x3::strict_real_policies<double> > const double_ = {}; 

live example

+0

wow danke ich wusste nicht über die 'strict_real_policies' Vorlage – Exagon

1

ich nicht strict_real_policies wusste über entweder, dass praktisch klingt.

ich um dieses arbeitete in einer direkteren Art und Weise einmal in etwa so:

(qi::int_ >> !lit('.') >> !lit('e') >> !lit('E')) | qi::float_ 

Wenn Sie einen Blick auf das Flussdiagramm auf http://www.json.org/ haben, können Sie sehen, dass diese drei Zeichen, die rechtlichen Möglichkeiten, um alle abdecken, dass ein Die Nummer könnte als Float analysiert werden. (In meinem speziellen Problem.)

+3

Dieser Ansatz wird normalerweise funktionieren, aber in einem Fall wie [dieser] (http: //coliru.stacked-crooked .com/a/07be3ea0e2824259) es würde scheitern. Wenn Sie wissen, dass der ganzzahlige Teil niemals fehlen wird, denke ich, dass '(int_ >>! Char _ (". EE ")) | float_' sollte äquivalent und (etwas) weniger laut sein. – llonesmiz

+3

Das ist Skipper vergessen, also sollte es wahrscheinlich 'lexeme [int_ >>! Char _ (". EE ")] | double_' – sehe

+0

@sehe: In der Grammatik, in der ich gearbeitet habe, habe ich alle Skipper deaktiviert. Die vollständige Regel war eigentlich 'non_nil_value = true_ | false_ | (qi :: int_ >>! lit ('.') >>! lit ('e') >>! lit ('E')) | qi :: float_ | tstring_ | lua_string_ | Tisch; '. Aber im Allgemeinen denke ich, dass "Lexem" beteiligt sein sollte. –

Verwandte Themen