<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Parser on kenji.blog</title><link>http://kenji.blog/de/tags/parser/</link><description>Recent content in Parser on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>de</language><copyright>kenjinote</copyright><lastBuildDate>Sat, 12 Sep 2026 11:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/de/tags/parser/index.xml" rel="self" type="application/rss+xml"/><item><title>Einen schnellen JSON-Parser in C++ selbst schreiben, um die Funktionsweise zu verstehen</title><link>http://kenji.blog/de/p/cpp-custom-fast-json-parser-tutorial/</link><pubDate>Sat, 12 Sep 2026 11:00:00 +0900</pubDate><guid>http://kenji.blog/de/p/cpp-custom-fast-json-parser-tutorial/</guid><description>&lt;img src="http://kenji.blog/p/cpp-custom-fast-json-parser-tutorial/img/eyecatch.jpg" alt="Featured image of post Einen schnellen JSON-Parser in C++ selbst schreiben, um die Funktionsweise zu verstehen" />&lt;p>In der Webentwicklung und bei der Kommunikation zwischen Systemen ist die derzeit am weitesten verbreitete Datenbeschreibungssprache zweifellos &lt;strong>JSON (JavaScript Object Notation)&lt;/strong>. In der Welt existieren bereits sehr hervorragende und schnelle JSON-Parser wie &lt;code>RapidJSON&lt;/code> oder &lt;code>simdjson&lt;/code>. In der Praxis mag es selten vorkommen, dass man einen selbst geschriebenen Parser in den Produktionscode integriert, aber &lt;strong>&amp;ldquo;das eigene Schreiben eines JSON-Parsers&amp;rdquo;&lt;/strong> ist ein hervorragendes Thema, um Parsing, Speicherverwaltung, Zeichenkettenverarbeitung und Performance-Tuning zu erlernen.&lt;/p>
&lt;p>In diesem Artikel erklären wir detailliert den Prozess, einen schnellen und speichereffizienten JSON-Parser von Grund auf neu zu erstellen, indem wir moderne Features von C++17/C++20 (wie &lt;code>std::string_view&lt;/code>, &lt;code>std::variant&lt;/code>, &lt;code>std::from_chars&lt;/code> usw.) voll ausschöpfen.&lt;/p>
&lt;hr>
&lt;h2 id="1-wiederholung-der-json-spezifikation-rfc-8259">1. Wiederholung der JSON-Spezifikation (RFC 8259)
&lt;/h2>&lt;p>Die JSON-Spezifikation ist in &lt;a class="link" href="https://tools.ietf.org/html/rfc8259" target="_blank" rel="noopener"
>RFC 8259&lt;/a> streng definiert. Um einen Parser zu schreiben, müssen wir zunächst die Spezifikation richtig verstehen.&lt;/p>
&lt;p>Die JSON-Datentypen sind auf die folgenden 6 Arten beschränkt.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Object (Objekt)&lt;/strong>: Eine ungeordnete Sammlung von Schlüssel-Wert-Paaren, wobei die Schlüssel Zeichenketten sind. Eingeschlossen in &lt;code>{}&lt;/code> und jedes Paar ist durch &lt;code>,&lt;/code> getrennt.&lt;/li>
&lt;li>&lt;strong>Array&lt;/strong>: Eine geordnete Liste von Werten. Eingeschlossen in &lt;code>[]&lt;/code> und die Werte sind durch &lt;code>,&lt;/code> getrennt.&lt;/li>
&lt;li>&lt;strong>String (Zeichenkette)&lt;/strong>: Eine Sequenz von Unicode-Zeichen, eingeschlossen in doppelte Anführungszeichen &lt;code>&amp;quot;&amp;quot;&lt;/code>. Enthält Escaping mit dem Backslash &lt;code>\&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Number (Zahl)&lt;/strong>: Ganzzahl oder Gleitkommazahl. Unendlich (&lt;code>Infinity&lt;/code>) oder keine Zahl (&lt;code>NaN&lt;/code>) sind nicht zulässig.&lt;/li>
&lt;li>&lt;strong>Boolean (Wahrheitswert)&lt;/strong>: &lt;code>true&lt;/code> oder &lt;code>false&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Null&lt;/strong>: &lt;code>null&lt;/code>.&lt;/li>
&lt;/ol>
&lt;p>Laut Spezifikation können Leerzeichen (Space, Horizontal Tab, Line Feed, Carriage Return) an beliebiger Stelle zwischen Token eingefügt werden, und das Parsing muss erfolgen, während diese ignoriert werden.&lt;/p>
&lt;hr>
&lt;h2 id="2-architektur-des-parsers">2. Architektur des Parsers
&lt;/h2>&lt;p>Der Parsing-Prozess (syntaktische Analyse) wird im Allgemeinen in zwei Phasen unterteilt: &lt;strong>lexikalische Analyse (Lexical Analysis)&lt;/strong> und &lt;strong>syntaktische Analyse (Syntactic Analysis)&lt;/strong>.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Eingabe-JSON-String&amp;#34;] --&amp;gt; B[&amp;#34;Lexer (Tokenizer)&amp;#34;]
B --&amp;gt; C[&amp;#34;Token-Stream&amp;#34;]
C --&amp;gt; D[&amp;#34;Parser (Recursive Descent)&amp;#34;]
D --&amp;gt; E[&amp;#34;AST / DOM-Baum (JsonValue)&amp;#34;]
style A fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#bbf,stroke:#333,stroke-width:2px
&lt;/pre>
&lt;ol>
&lt;li>&lt;strong>Lexer (Tokenizer)&lt;/strong>: Liest den rohen Eingabe-String (Zeichen-Array) von Anfang an und teilt ihn in &amp;ldquo;sinnvolle kleinste Einheiten (Token)&amp;rdquo;.&lt;/li>
&lt;li>&lt;strong>Parser&lt;/strong>: Liest die vom Lexer erhaltene Token-Sequenz und baut gemäß den Grammatikregeln eine Baumstruktur (DOM-Baum: Document Object Model) auf.&lt;/li>
&lt;/ol>
&lt;p>In dieser Implementierung wird der Lexer so konzipiert, dass er keine Kopien von Zeichenketten erstellt, sondern Zeiger und Länge auf den ursprünglichen Eingabe-String (&lt;code>std::string_view&lt;/code>) speichert, um die Speichereffizienz zu erhöhen.&lt;/p>
&lt;hr>
&lt;h2 id="3-entwurf-des-ast--dom--modells-und-modernes-c">3. Entwurf des AST- (DOM-) Modells und modernes C++
&lt;/h2>&lt;p>Um die verschiedenen Datentypen von JSON in C++ darzustellen, nutzen wir das in C++17 eingeführte &lt;code>std::variant&lt;/code>. &lt;code>std::variant&lt;/code> ist eine typsichere Union und eignet sich ideal für die Darstellung von JSON-Daten mit dynamischer Typisierung.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;vector&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;map&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;variant&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;memory&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;string_view&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Vorwärtsdeklaration
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">class&lt;/span> &lt;span class="nc">JsonValue&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Datentypen für JSON definieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">using&lt;/span> &lt;span class="n">JsonNull&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">nullptr_t&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">JsonBool&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">bool&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">JsonNumber&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="kt">double&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">JsonString&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">JsonArray&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonValue&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="n">JsonObject&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">map&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// std::variant verwenden, um genau einen der Typen zu speichern
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">using&lt;/span> &lt;span class="n">JsonVariant&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">variant&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonNull&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonBool&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonNumber&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonString&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonArray&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonObject&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">JsonValue&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Standardkonstruktor initialisiert mit Null
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">m_value&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">nullptr&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Konstruktor, der implizite Konvertierungen aus jedem Typ erlaubt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="k">typename&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">val&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">m_value&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">forward&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">val&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Hilfsmethoden zur Typprüfung
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isNull&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonNull&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isBool&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonBool&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isNumber&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonNumber&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isString&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonString&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isArray&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonArray&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isObject&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">holds_alternative&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">JsonObject&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Hilfsmethode zum Abrufen von Werten
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">template&lt;/span> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="k">typename&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">const&lt;/span> &lt;span class="n">T&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">get&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">get&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">T&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonVariant&lt;/span> &lt;span class="n">m_value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Durch dieses Design können rekursive Datenstrukturen wie &lt;code>JsonArray&lt;/code> und &lt;code>JsonObject&lt;/code> prägnant und sicher dargestellt werden (in einigen Implementierungen der C++-Standardbibliothek ist die Verwendung unvollständiger Typen innerhalb von &lt;code>std::variant&lt;/code> eingeschränkt, weshalb eine Heap-Zuweisung mit Smart Pointern erforderlich sein kann, aber in den neuesten Compilern funktioniert der obige Code oft reibungslos).&lt;/p>
&lt;hr>
&lt;h2 id="4-implementierung-des-lexers-lexikalische-analyse">4. Implementierung des Lexers (Lexikalische Analyse)
&lt;/h2>&lt;p>Die Aufgabe des Lexers ist es, Zeichenketten zu lesen und in Token zu zerlegen. Zunächst definieren wir die Arten von Token.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">enum&lt;/span> &lt;span class="k">class&lt;/span> &lt;span class="nc">TokenType&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Null&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">True&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">False&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Number&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">LBrace&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// {
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">RBrace&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// }
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">LBracket&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// [
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">RBracket&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// ]
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Colon&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// :
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">Comma&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="c1">// ,
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">EndOfFile&lt;/span> &lt;span class="c1">// EOF
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">struct&lt;/span> &lt;span class="nc">Token&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TokenType&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wenn wir die internen Zustandsübergänge des Lexers mit Mermaid visualisieren, sieht das wie folgt aus.&lt;/p>
&lt;pre class="mermaid">
stateDiagram-v2
[*] --&amp;gt; Start : &amp;#34;Leerzeichen überspringen&amp;#34;
Start --&amp;gt; ParseString : &amp;#34;Doppeltes Anführungszeichen (&amp;#39;\&amp;#34;&amp;#39;)&amp;#34;
Start --&amp;gt; ParseNumber : &amp;#34;Ziffer oder Minus (&amp;#39;-&amp;#39;)&amp;#34;
Start --&amp;gt; ParseKeyword : &amp;#34;Zeichen (&amp;#39;t&amp;#39;, &amp;#39;f&amp;#39;, &amp;#39;n&amp;#39;)&amp;#34;
Start --&amp;gt; ParseSymbol : &amp;#34;Satzzeichen (&amp;#39;{&amp;#39;, &amp;#39;[&amp;#39;, usw.)&amp;#34;
ParseString --&amp;gt; Start : &amp;#34;Endanführungszeichen (&amp;#39;\&amp;#34;&amp;#39;)&amp;#34;
ParseNumber --&amp;gt; Start : &amp;#34;Nicht-Ziffer&amp;#34;
ParseKeyword --&amp;gt; Start : &amp;#34;Schlüsselwort-Treffer&amp;#34;
ParseSymbol --&amp;gt; Start : &amp;#34;Einzelnes Zeichen&amp;#34;
&lt;/pre>
&lt;p>Die Hauptimplementierung des Lexers sieht folgendermaßen aus. Während Leerzeichen übersprungen werden, wird abhängig vom aktuellen Zeichen verzweigt (mit einer switch- oder if-Anweisung).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;span class="lnt">78
&lt;/span>&lt;span class="lnt">79
&lt;/span>&lt;span class="lnt">80
&lt;/span>&lt;span class="lnt">81
&lt;/span>&lt;span class="lnt">82
&lt;/span>&lt;span class="lnt">83
&lt;/span>&lt;span class="lnt">84
&lt;/span>&lt;span class="lnt">85
&lt;/span>&lt;span class="lnt">86
&lt;/span>&lt;span class="lnt">87
&lt;/span>&lt;span class="lnt">88
&lt;/span>&lt;span class="lnt">89
&lt;/span>&lt;span class="lnt">90
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Lexer&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">explicit&lt;/span> &lt;span class="n">Lexer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">source&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">source&lt;/span>&lt;span class="p">),&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="nf">nextToken&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">skipWhitespace&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">EndOfFile&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">switch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;{&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">LBrace&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;{&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;}&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBrace&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;}&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;[&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">LBracket&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;[&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;]&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBracket&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;]&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;:&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Colon&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;:&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;,&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Comma&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;,&amp;#34;&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="sc">&amp;#39;&amp;#34;&amp;#39;&lt;/span>&lt;span class="o">:&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">lexString&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">default&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;-&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">isdigit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">lexNumber&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">isalpha&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">lexKeyword&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Unexpected character&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Unerwartetes Zeichen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">bool&lt;/span> &lt;span class="nf">isAtEnd&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">m_position&lt;/span> &lt;span class="o">&amp;gt;=&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">length&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="nf">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="k">const&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">m_position&lt;/span>&lt;span class="p">];&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">advance&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="o">++&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">skipWhitespace&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">char&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39; &amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;\t&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;\n&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">c&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;\r&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="nf">lexString&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Anfängliches Anführungszeichen überspringen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">size_t&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="sc">&amp;#39;&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Die Verarbeitung von Escape-Zeichen (wie \&amp;#34; oder \\) sollte hier strikt erfolgen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;\\&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Den Backslash des Escapes überspringen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Unterminated string&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Nicht beendeter String
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">strVal&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">substr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m_position&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Abschließendes Anführungszeichen überspringen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">strVal&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="nf">lexNumber&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">isdigit&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">peek&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;e&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;E&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;+&amp;#39;&lt;/span> &lt;span class="o">||&lt;/span> &lt;span class="n">peek&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="sc">&amp;#39;-&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Number&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">substr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m_position&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="nf">lexKeyword&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">size_t&lt;/span> &lt;span class="n">start&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_position&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="o">!&lt;/span>&lt;span class="n">isAtEnd&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">isalpha&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">peek&lt;/span>&lt;span class="p">()))&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">advance&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">word&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_source&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">substr&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">start&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">m_position&lt;/span> &lt;span class="o">-&lt;/span> &lt;span class="n">start&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s">&amp;#34;true&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">True&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">word&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s">&amp;#34;false&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">False&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">word&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">word&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s">&amp;#34;null&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="p">{&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Null&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">word&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Unknown keyword&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Unbekanntes Schlüsselwort
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Der entscheidende Punkt hier ist, dass die Werte von Zeichenketten (String) und Zahlen (Number) als &lt;code>std::string_view&lt;/code> extrahiert werden. Dadurch &lt;strong>treten auf der Lexer-Stufe keinerlei dynamische Speicherzuweisungen (Heap-Allocation) oder Kopien auf&lt;/strong>. Dies ist ein wichtiges Design, das sich direkt auf die Performance auswirkt.&lt;/p>
&lt;hr>
&lt;h2 id="5-implementierung-des-parsers-syntaktische-analyse-recursive-descent-parsing">5. Implementierung des Parsers (Syntaktische Analyse): Recursive Descent Parsing
&lt;/h2>&lt;p>Sobald der Lexer fertig ist, ist der Parser an der Reihe. Da die JSON-Grammatik eine LL(1)-Grammatik ist, passt sie sehr gut zum &lt;strong>Recursive Descent Parsing (rekursiver absteigender Parser)&lt;/strong>, bei dem &amp;ldquo;nur durch Betrachtung eines aktuellen Tokens&amp;rdquo; entschieden werden kann, welche Funktion als Nächstes aufgerufen werden soll.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt"> 10
&lt;/span>&lt;span class="lnt"> 11
&lt;/span>&lt;span class="lnt"> 12
&lt;/span>&lt;span class="lnt"> 13
&lt;/span>&lt;span class="lnt"> 14
&lt;/span>&lt;span class="lnt"> 15
&lt;/span>&lt;span class="lnt"> 16
&lt;/span>&lt;span class="lnt"> 17
&lt;/span>&lt;span class="lnt"> 18
&lt;/span>&lt;span class="lnt"> 19
&lt;/span>&lt;span class="lnt"> 20
&lt;/span>&lt;span class="lnt"> 21
&lt;/span>&lt;span class="lnt"> 22
&lt;/span>&lt;span class="lnt"> 23
&lt;/span>&lt;span class="lnt"> 24
&lt;/span>&lt;span class="lnt"> 25
&lt;/span>&lt;span class="lnt"> 26
&lt;/span>&lt;span class="lnt"> 27
&lt;/span>&lt;span class="lnt"> 28
&lt;/span>&lt;span class="lnt"> 29
&lt;/span>&lt;span class="lnt"> 30
&lt;/span>&lt;span class="lnt"> 31
&lt;/span>&lt;span class="lnt"> 32
&lt;/span>&lt;span class="lnt"> 33
&lt;/span>&lt;span class="lnt"> 34
&lt;/span>&lt;span class="lnt"> 35
&lt;/span>&lt;span class="lnt"> 36
&lt;/span>&lt;span class="lnt"> 37
&lt;/span>&lt;span class="lnt"> 38
&lt;/span>&lt;span class="lnt"> 39
&lt;/span>&lt;span class="lnt"> 40
&lt;/span>&lt;span class="lnt"> 41
&lt;/span>&lt;span class="lnt"> 42
&lt;/span>&lt;span class="lnt"> 43
&lt;/span>&lt;span class="lnt"> 44
&lt;/span>&lt;span class="lnt"> 45
&lt;/span>&lt;span class="lnt"> 46
&lt;/span>&lt;span class="lnt"> 47
&lt;/span>&lt;span class="lnt"> 48
&lt;/span>&lt;span class="lnt"> 49
&lt;/span>&lt;span class="lnt"> 50
&lt;/span>&lt;span class="lnt"> 51
&lt;/span>&lt;span class="lnt"> 52
&lt;/span>&lt;span class="lnt"> 53
&lt;/span>&lt;span class="lnt"> 54
&lt;/span>&lt;span class="lnt"> 55
&lt;/span>&lt;span class="lnt"> 56
&lt;/span>&lt;span class="lnt"> 57
&lt;/span>&lt;span class="lnt"> 58
&lt;/span>&lt;span class="lnt"> 59
&lt;/span>&lt;span class="lnt"> 60
&lt;/span>&lt;span class="lnt"> 61
&lt;/span>&lt;span class="lnt"> 62
&lt;/span>&lt;span class="lnt"> 63
&lt;/span>&lt;span class="lnt"> 64
&lt;/span>&lt;span class="lnt"> 65
&lt;/span>&lt;span class="lnt"> 66
&lt;/span>&lt;span class="lnt"> 67
&lt;/span>&lt;span class="lnt"> 68
&lt;/span>&lt;span class="lnt"> 69
&lt;/span>&lt;span class="lnt"> 70
&lt;/span>&lt;span class="lnt"> 71
&lt;/span>&lt;span class="lnt"> 72
&lt;/span>&lt;span class="lnt"> 73
&lt;/span>&lt;span class="lnt"> 74
&lt;/span>&lt;span class="lnt"> 75
&lt;/span>&lt;span class="lnt"> 76
&lt;/span>&lt;span class="lnt"> 77
&lt;/span>&lt;span class="lnt"> 78
&lt;/span>&lt;span class="lnt"> 79
&lt;/span>&lt;span class="lnt"> 80
&lt;/span>&lt;span class="lnt"> 81
&lt;/span>&lt;span class="lnt"> 82
&lt;/span>&lt;span class="lnt"> 83
&lt;/span>&lt;span class="lnt"> 84
&lt;/span>&lt;span class="lnt"> 85
&lt;/span>&lt;span class="lnt"> 86
&lt;/span>&lt;span class="lnt"> 87
&lt;/span>&lt;span class="lnt"> 88
&lt;/span>&lt;span class="lnt"> 89
&lt;/span>&lt;span class="lnt"> 90
&lt;/span>&lt;span class="lnt"> 91
&lt;/span>&lt;span class="lnt"> 92
&lt;/span>&lt;span class="lnt"> 93
&lt;/span>&lt;span class="lnt"> 94
&lt;/span>&lt;span class="lnt"> 95
&lt;/span>&lt;span class="lnt"> 96
&lt;/span>&lt;span class="lnt"> 97
&lt;/span>&lt;span class="lnt"> 98
&lt;/span>&lt;span class="lnt"> 99
&lt;/span>&lt;span class="lnt">100
&lt;/span>&lt;span class="lnt">101
&lt;/span>&lt;span class="lnt">102
&lt;/span>&lt;span class="lnt">103
&lt;/span>&lt;span class="lnt">104
&lt;/span>&lt;span class="lnt">105
&lt;/span>&lt;span class="lnt">106
&lt;/span>&lt;span class="lnt">107
&lt;/span>&lt;span class="lnt">108
&lt;/span>&lt;span class="lnt">109
&lt;/span>&lt;span class="lnt">110
&lt;/span>&lt;span class="lnt">111
&lt;/span>&lt;span class="lnt">112
&lt;/span>&lt;span class="lnt">113
&lt;/span>&lt;span class="lnt">114
&lt;/span>&lt;span class="lnt">115
&lt;/span>&lt;span class="lnt">116
&lt;/span>&lt;span class="lnt">117
&lt;/span>&lt;span class="lnt">118
&lt;/span>&lt;span class="lnt">119
&lt;/span>&lt;span class="lnt">120
&lt;/span>&lt;span class="lnt">121
&lt;/span>&lt;span class="lnt">122
&lt;/span>&lt;span class="lnt">123
&lt;/span>&lt;span class="lnt">124
&lt;/span>&lt;span class="lnt">125
&lt;/span>&lt;span class="lnt">126
&lt;/span>&lt;span class="lnt">127
&lt;/span>&lt;span class="lnt">128
&lt;/span>&lt;span class="lnt">129
&lt;/span>&lt;span class="lnt">130
&lt;/span>&lt;span class="lnt">131
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">class&lt;/span> &lt;span class="nc">Parser&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">public&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">explicit&lt;/span> &lt;span class="n">Parser&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">source&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="o">:&lt;/span> &lt;span class="n">m_lexer&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">source&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">m_currentToken&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_lexer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nextToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parse&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="n">result&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">parseValue&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">EndOfFile&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Extra tokens after root element&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Zusätzliche Token nach dem Wurzelelement
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">result&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">private&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Lexer&lt;/span> &lt;span class="n">m_lexer&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Token&lt;/span> &lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">consumeToken&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">m_currentToken&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_lexer&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">nextToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">void&lt;/span> &lt;span class="nf">expectAndConsume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TokenType&lt;/span> &lt;span class="n">expectedType&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">expectedType&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Unexpected token&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Unerwartetes Token
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parseValue&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">switch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">Null&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">nullptr&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">True&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">False&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">Number&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">parseNumber&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">String&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">parseString&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">LBrace&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">parseObject&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">case&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="nl">LBracket&lt;/span>&lt;span class="p">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">parseArray&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">default&lt;/span>&lt;span class="o">:&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Invalid value&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Ungültiger Wert
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parseNumber&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string_view&lt;/span> &lt;span class="n">numStr&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">double&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="mf">0.0&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// std::from_chars von C++17 verwenden für schnelles Parsen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">auto&lt;/span> &lt;span class="p">[&lt;/span>&lt;span class="n">ptr&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">ec&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">from_chars&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">numStr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">numStr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">data&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">numStr&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">size&lt;/span>&lt;span class="p">(),&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">ec&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">errc&lt;/span>&lt;span class="p">())&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Invalid number format&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Ungültiges Zahlenformat
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parseString&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Eigentlich sollte hier die Dekodierung von Escape-Sequenzen (\n, \uXXXX usw.) erfolgen
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// und der tatsächliche std::string aufgebaut werden.
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">str&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">str&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parseArray&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// &amp;#39;[&amp;#39; konsumieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">JsonArray&lt;/span> &lt;span class="n">array&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBracket&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Leeres Array
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">array&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">array&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">push_back&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">parseValue&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Comma&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBracket&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Expected &amp;#39;,&amp;#39; or &amp;#39;]&amp;#39; in array&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Erwartet &amp;#39;,&amp;#39; oder &amp;#39;]&amp;#39; im Array
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">array&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="nf">parseObject&lt;/span>&lt;span class="p">()&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// &amp;#39;{&amp;#39; konsumieren
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">JsonObject&lt;/span> &lt;span class="n">object&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBrace&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span> &lt;span class="c1">// Leeres Objekt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">object&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">while&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">!=&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">String&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Expected string key in object&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Erwartet String-Schlüssel im Objekt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">string&lt;/span> &lt;span class="n">key&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">value&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">expectAndConsume&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Colon&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">JsonValue&lt;/span> &lt;span class="n">value&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">parseValue&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">object&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="n">key&lt;/span>&lt;span class="p">]&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Comma&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">m_currentToken&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">type&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="n">TokenType&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RBrace&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">consumeToken&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">break&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span> &lt;span class="k">else&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">throw&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">runtime_error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;Expected &amp;#39;,&amp;#39; or &amp;#39;}&amp;#39; in object&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span> &lt;span class="c1">// Erwartet &amp;#39;,&amp;#39; oder &amp;#39;}&amp;#39; im Objekt
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="n">JsonValue&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">object&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Da bei einem Recursive Descent Parser die Codestruktur und die JSON-Grammatik (BNF) eins zu eins übereinstimmen, wird der Code intuitiv und leicht lesbar. Bei &lt;code>parseObject&lt;/code> wird beispielsweise die Syntax in der Reihenfolge Schlüssel (String) -&amp;gt; Doppelpunkt (Colon) -&amp;gt; Wert (Value) analysiert.&lt;/p>
&lt;hr>
&lt;h2 id="6-techniken-zur-performance-optimierung">6. Techniken zur Performance-Optimierung
&lt;/h2>&lt;p>Allein durch die Implementierung eines einfachen Parsers kann man keine praktischen Bibliotheken schlagen. Wir stellen einige Optimierungstechniken vor, die spezifisch für C++ sind.&lt;/p>
&lt;h3 id="61-zero-copy-architektur-und-stdstring_view">6.1. Zero-Copy-Architektur und &lt;code>std::string_view&lt;/code>
&lt;/h3>&lt;p>Der Großteil der Performance-Engpässe eines Parsers liegt in der &amp;ldquo;Kopie von Zeichenketten&amp;rdquo; und der &amp;ldquo;dynamischen Allokation von Heap-Speicher&amp;rdquo;.
Wenn &lt;code>std::string&lt;/code> häufig verwendet wird, tritt bei jeder Erstellung von Teilstrings eine Speicherzuweisung auf. Um dies zu verhindern, haben wir im Lexer konsequent &lt;code>std::string_view&lt;/code> verwendet.
Die Erstellungszeit von &lt;code>std::string_view&lt;/code> hängt nicht von der Stringlänge $L$ ab und wird in $O(1)$ abgeschlossen.&lt;/p>
&lt;h3 id="62-optimierung-des-zahlen-parsings-stdfrom_chars">6.2. Optimierung des Zahlen-Parsings (&lt;code>std::from_chars&lt;/code>)
&lt;/h3>&lt;p>Standardfunktionen wie &lt;code>std::stod&lt;/code> oder &lt;code>sscanf&lt;/code> arbeiten abhängig von den aktuellen Locale-Einstellungen. Dadurch erhalten sie intern Sperren für gegenseitigen Ausschluss und erzeugen Lokalisierungs-Overheads.
Das in C++17 eingeführte &lt;code>std::from_chars&lt;/code> ist locale-unabhängig und erfordert keine Speicherkopien. Daher bietet es eine überwältigende Performance beim Parsen von Zahlen. Die Zeitkomplexität beträgt $O(M)$, wobei $M$ die Anzahl der Ziffern ist.&lt;/p>
&lt;h3 id="63-speicherzuweisung-und-stdpmr-polymorphic-memory-resources">6.3. Speicherzuweisung und &lt;code>std::pmr&lt;/code> (Polymorphic Memory Resources)
&lt;/h3>&lt;p>Während der Erstellung des AST entstehen durch die Knotengenerierung von &lt;code>std::vector&lt;/code> oder &lt;code>std::map&lt;/code> zahlreiche kleine Allokationen (Fragmentierungen).
Um dies zu vermeiden, ist es effektiv, in C++17 &lt;code>std::pmr::monotonic_buffer_resource&lt;/code> als benutzerdefinierten Allokator zu verwenden. Indem ein großer Speicherblock im Voraus nur einmal reserviert wird und Speicher durch einfaches Weiterrücken eines Zeigers ausgeschnitten wird, sinken die Allokationskosten auf fast null.&lt;/p>
&lt;h3 id="64-nutzung-von-simd-fortgeschritten">6.4. Nutzung von SIMD (Fortgeschritten)
&lt;/h3>&lt;p>Fortschrittliche Parser wie &lt;code>simdjson&lt;/code> verwenden SIMD-Anweisungen wie AVX2 oder NEON, um Zeichenketten von 32 oder 64 Byte auf einmal zu scannen. Dadurch wird das Überspringen von Leerzeichen und die Suche nach Anführungszeichen drastisch beschleunigt. Die Implementierung in diesem Artikel verwendet zeichenweises Scannen, aber wenn man nach dem ultimativen Ziel strebt, sind branchless (verzweigungsfreie) Programmierung und SIMD unerlässlich.&lt;/p>
&lt;hr>
&lt;h2 id="7-bewertung-von-komplexität-und-algorithmus">7. Bewertung von Komplexität und Algorithmus
&lt;/h2>&lt;p>Wir bewerten die algorithmische Komplexität dieses Parsers.
Angenommen, die Gesamtlänge der eingegebenen JSON-Zeichenkette beträgt $N$ Bytes.&lt;/p>
&lt;p>&lt;strong>Zeitkomplexität (Time Complexity):&lt;/strong>
Der Lexer referenziert jedes Zeichen nur eine konstante Anzahl von Malen (normalerweise einmal), und der Parser führt eine konstante Anzahl von Operationen pro Token durch. Es gibt absolut kein Backtracking (Neu-Lesen). Daher ist die allgemeine Zeitkomplexität linear.&lt;/p>
$$
T(N) = O(N)
$$&lt;p>&lt;strong>Speicherkomplexität (Space Complexity):&lt;/strong>
Der zugewiesene Speicher für den Aufbau des AST (DOM-Baum) ist proportional zur Anzahl der Elemente im JSON-String. Selbst im schlimmsten Fall (z.B. stark verschachteltes Array &lt;code>[[[[...]]]]&lt;/code>) liegt die erforderliche Speichermenge innerhalb eines konstanten Vielfachen, das die Eingabegröße $N$ nicht überschreitet.&lt;/p>
$$
Space(N) \le C \times N \implies O(N)
$$&lt;p>Beim Recursive Descent Parsing wird der Aufrufstapel (Call Stack) jedoch proportional zur Verschachtelungstiefe (Depth) von JSON verbraucht. Für die Tiefe $D$ wird ein Stapelspeicher von $O(D)$ benötigt. Wenn böswillig endlos verschachteltes JSON eingegeben wird, besteht die Gefahr eines Stack Overflow. Daher müssen praktische Parser eine Grenze für die Rekursionstiefe festlegen (z. B. 256 oder 512) oder die Rekursion in Schleifen auflösen.&lt;/p>
&lt;hr>
&lt;h2 id="8-zusammenfassung">8. Zusammenfassung
&lt;/h2>&lt;p>In diesem Artikel haben wir die Schritte erläutert, um mit C++ einen JSON-Parser von Grund auf neu zu erstellen.&lt;/p>
&lt;ul>
&lt;li>Trennen des Strings in Token mithilfe eines &lt;strong>Lexers&lt;/strong> und Reduzieren unnötiger Kopien durch &lt;code>std::string_view&lt;/code>.&lt;/li>
&lt;li>Konvertieren der Token in einen AST (&lt;code>std::variant&lt;/code>) mithilfe eines Recursive Descent &lt;strong>Parsers&lt;/strong>.&lt;/li>
&lt;li>Anwenden von &lt;code>std::from_chars&lt;/code> und Speicherverwaltungsstrategien unter Berücksichtigung der &lt;strong>Performance&lt;/strong>.&lt;/li>
&lt;/ul>
&lt;p>Die Erfahrung, die Spezifikationen einer Sprache zu verstehen und in Code umzusetzen, hebt die Fähigkeiten als Programmierer auf die nächste Stufe. Nutzen Sie diesen Artikel als Sprungbrett, um Ihre eigenen Parser und Serialisierer (Generierung von JSON-Strings) zu erweitern und fordern Sie sich selbst zu weiteren Optimierungen (wie die Einführung von benutzerdefinierten Allokatoren oder SIMD-Nutzung) heraus.&lt;/p></description></item></channel></rss>