<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mathieu Ledru</title>
    <description>The latest articles on DEV Community by Mathieu Ledru (@matyo91).</description>
    <link>https://dev.to/matyo91</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F182978%2F61c41098-10ce-4833-acf3-b00cc42f852c.jpeg</url>
      <title>DEV Community: Mathieu Ledru</title>
      <link>https://dev.to/matyo91</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matyo91"/>
    <language>en</language>
    <item>
      <title>🚀 Darkwood v8.1.6 disponible</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 15:42:57 +0000</pubDate>
      <link>https://dev.to/matyo91/darkwood-v816-disponible-1d4p</link>
      <guid>https://dev.to/matyo91/darkwood-v816-disponible-1d4p</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/darkwood-com/darkwood/releases/tag/v8.1.6" rel="noopener noreferrer"&gt;Darkwood v8.1.6&lt;/a&gt; vient d'être publié.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⬆️ Mise à jour vers Symfony v8.1.6&lt;/li&gt;
&lt;li&gt;🔨 Ajout de symfony lsp:check&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🏷️ Journal des modifications complet &lt;a href="https://github.com/darkwood-com/darkwood/compare/v8.1.5...v8.1.6" rel="noopener noreferrer"&gt;v8.1.5...v8.1.6&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Bluesky Creator - @aurelievache : Deux postes d'ingénieur en accessibilité chez Apple</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 15:03:39 +0000</pubDate>
      <link>https://dev.to/matyo91/bluesky-creator-aurelievache-deux-postes-dingenieur-en-accessibilite-chez-apple-pmk</link>
      <guid>https://dev.to/matyo91/bluesky-creator-aurelievache-deux-postes-dingenieur-en-accessibilite-chez-apple-pmk</guid>
      <description>&lt;p&gt;Découvrez deux postes passionnants dans le domaine de l'ingénierie de l'accessibilité chez Apple à Londres. L'un d'entre eux est idéal pour les candidats en début de carrière ! Ces postes jouent un rôle essentiel à l'heure où la technologie devient de plus en plus inclusive. Vous trouverez ci-dessous tous les détails et des informations complémentaires.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à un abonnement supérieur pour accéder à l'analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Créateur Reddit - r/opensource : mloda 0.11 : a transformé une simple erreur de résolution « introuvable » en une piste d'élimination complète</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 13:03:00 +0000</pubDate>
      <link>https://dev.to/matyo91/createur-reddit-ropensource-mloda-011-a-transforme-une-simple-erreur-de-resolution--3f4l</link>
      <guid>https://dev.to/matyo91/createur-reddit-ropensource-mloda-011-a-transforme-une-simple-erreur-de-resolution--3f4l</guid>
      <description>&lt;p&gt;Dans la récente mise à jour de mloda vers la version 0.11, la fonctionnalité de débogage des erreurs de résolution des caractéristiques a été considérablement améliorée. Auparavant, une simple erreur « introuvable » laissait les développeurs dans l'incertitude quant à la cause de leurs problèmes. Désormais, le système fournit une piste d’élimination détaillée qui précise quelles caractéristiques ont été prises en compte et pourquoi elles ont été rejetées. Il s’agit d’un véritable tournant pour les développeurs qui exploitent les capacités de mloda en matière d’ingénierie des caractéristiques.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à la version supérieure pour accéder à l'analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Auteur sur arXiv - cs.LG : Regret individuel constant dans les jeux généraux</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 11:04:04 +0000</pubDate>
      <link>https://dev.to/matyo91/auteur-sur-arxiv-cslg-regret-individuel-constant-dans-les-jeux-generaux-5abc</link>
      <guid>https://dev.to/matyo91/auteur-sur-arxiv-cslg-regret-individuel-constant-dans-les-jeux-generaux-5abc</guid>
      <description>&lt;p&gt;Cette recherche aborde les défis complexes liés au regret individuel dans les contextes multijoueurs. Les auteurs présentent ECHO-OFTRL, un algorithme innovant qui garantit aux joueurs un regret borné dans les jeux à horizon fini, ce qui constitue une avancée significative dans le domaine de la théorie des jeux.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à un abonnement supérieur pour accéder à l’analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 GitHub Creator - helm: Helm v3.22.0-rc.1</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 10:03:37 +0000</pubDate>
      <link>https://dev.to/matyo91/github-creator-helm-helm-v3220-rc1-n5f</link>
      <guid>https://dev.to/matyo91/github-creator-helm-helm-v3220-rc1-n5f</guid>
      <description>&lt;h2&gt;
  
  
  À propos de ce créateur
&lt;/h2&gt;

&lt;p&gt;Helm v3.22.0-rc.1, une pré-version, est là pour recueillir des retours de la communauté et permettre des tests en environnement de staging avant la sortie officielle. La communauté continue de croître, et nous vous encourageons à vous y engager.&lt;/p&gt;

&lt;h2&gt;
  
  
  En savoir plus sur les changements et les tests disponibles.
&lt;/h2&gt;

&lt;p&gt;🚨 &lt;b&gt;Premium content.&lt;/b&gt;&lt;br&gt;⬆️ Upgrade to access full analysis.&lt;br&gt;👉 Subscribe here : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🤖 Veille Darkwood - 2026-09-01</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Tue, 01 Sep 2026 05:03:09 +0000</pubDate>
      <link>https://dev.to/matyo91/veille-darkwood-2026-09-01-4959</link>
      <guid>https://dev.to/matyo91/veille-darkwood-2026-09-01-4959</guid>
      <description>&lt;h2&gt;
  
  
  Points saillants
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Développer un scanner de rendement DeFi avec Python et IA&lt;/strong&gt; : Un aperçu des architectures nécessaires pour extraire des données sur la blockchain efficacement. &lt;a href="https://dev.to/rogt7/building-a-defi-yield-scanner-with-python-and-ai-445f"&gt;Lire plus ici&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;L'avenir de l'infrastructure de données financières connectées&lt;/strong&gt; : L'importance grandissante d'un infrastructure fiable dans le secteur financier. &lt;a href="https://dev.to/bmupmultiassetinstit/bmup-multi-asset-institute-examines-the-future-of-connected-financial-data-infrastructure-3i2b"&gt;Lire plus ici&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Les mithes sur les serveurs AI gratuits&lt;/strong&gt; : Briser les mythes autour de l'hébergement AI gratuit. &lt;a href="https://dev.to/gitlab_3188/free-ai-servers-are-not-a-slot-machine-five-myths-worth-breaking-4mb8"&gt;Lire plus ici&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 &lt;b&gt;Premium content.&lt;/b&gt;&lt;br&gt;⬆️ Upgrade to access full analysis.&lt;br&gt;👉 Subscribe here : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Créateur de Hacker News - Décryptage du code de Claude, opus 5, mode automatique</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Mon, 31 Aug 2026 14:03:07 +0000</pubDate>
      <link>https://dev.to/matyo91/createur-de-hacker-news-decryptage-du-code-de-claude-opus-5-mode-automatique-5fad</link>
      <guid>https://dev.to/matyo91/createur-de-hacker-news-decryptage-du-code-de-claude-opus-5-mode-automatique-5fad</guid>
      <description>&lt;p&gt;Découvrez comment la nouvelle fonctionnalité « Mode Auto » de Claude Code Opus 5 va révolutionner le monde de l'automatisation, tant pour les développeurs que pour les entreprises.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à la version supérieure pour accéder à l'analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Créateur Reddit - r/opensource : Je développe un éditeur de documents docx open source doté de son propre moteur de rendu Canvas</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Mon, 31 Aug 2026 13:03:10 +0000</pubDate>
      <link>https://dev.to/matyo91/createur-reddit-ropensource-je-developpe-un-editeur-de-documents-docx-open-source-dote-de-5f0j</link>
      <guid>https://dev.to/matyo91/createur-reddit-ropensource-je-developpe-un-editeur-de-documents-docx-open-source-dote-de-5f0j</guid>
      <description>&lt;h2&gt;
  
  
  À propos de cet article
&lt;/h2&gt;

&lt;p&gt;Bonjour à toute la communauté ! Découvrez Oasis Editor, un nouvel éditeur de fichiers docx open source qui utilise un moteur de rendu Canvas personnalisé pour offrir une expérience plus riche lors de la consultation des documents. Ce projet, développé en TypeScript, est ouvert aux commentaires et à la collaboration, notamment en ce qui concerne le rendu et la mise en page.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à la version supérieure pour accéder à l’analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Auteur sur arXiv - stat.ML : Apprentissage d'une frontière taille-poids pour l'inférence augmentée par synthèse</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Mon, 31 Aug 2026 11:04:00 +0000</pubDate>
      <link>https://dev.to/matyo91/auteur-sur-arxiv-statml-apprentissage-dune-frontiere-taille-poids-pour-linference-3glg</link>
      <guid>https://dev.to/matyo91/auteur-sur-arxiv-statml-apprentissage-dune-frontiere-taille-poids-pour-linference-3glg</guid>
      <description>&lt;p&gt;Découvrez un nouveau cadre qui exploite les données synthétiques pour affiner les processus d’inférence statistique. Cette approche garantit une couverture améliorée et réduit les biais grâce à une relation taille-poids bien définie.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à un abonnement supérieur pour accéder à l'analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🤖 Veille Darkwood - 2026-08-31</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Mon, 31 Aug 2026 05:03:24 +0000</pubDate>
      <link>https://dev.to/matyo91/veille-darkwood-2026-08-31-3ejp</link>
      <guid>https://dev.to/matyo91/veille-darkwood-2026-08-31-3ejp</guid>
      <description>&lt;h2&gt;
  
  
  Points saillants
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Surveillance des airdrops&lt;/strong&gt; : Construire un moniteur airdrop avec l'IA pour identifier les meilleures opportunités. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outil de sécurité WiFi&lt;/strong&gt; : Evaluation pratique de &lt;code&gt;martin-olivier/airgorah&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IA en ventes&lt;/strong&gt; : Optimisation des efforts de vente grâce à l'IA.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🚨 &lt;b&gt;Premium content.&lt;/b&gt;&lt;br&gt;⬆️ Upgrade to access full analysis.&lt;br&gt;👉 Subscribe here : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>💫 Hacker News Creator - Aperçu de Hy4</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Sun, 30 Aug 2026 14:03:10 +0000</pubDate>
      <link>https://dev.to/matyo91/hacker-news-creator-apercu-de-hy4-4cee</link>
      <guid>https://dev.to/matyo91/hacker-news-creator-apercu-de-hy4-4cee</guid>
      <description>&lt;h2&gt;
  
  
  À propos de cet article
&lt;/h2&gt;

&lt;p&gt;Tencent a dévoilé un aperçu de sa technologie Hy4, promettant des répercussions transformatrices sur divers secteurs technologiques. Les premières réactions témoignent à la fois d’enthousiasme et de scepticisme quant à ses applications potentielles dans des situations concrètes.&lt;/p&gt;

&lt;p&gt;🚨 &lt;b&gt;Contenu premium.&lt;/b&gt;&lt;br&gt;⬆️ Passez à un abonnement supérieur pour accéder à l'analyse complète.&lt;br&gt;👉 Abonnez-vous ici : &lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php" rel="noopener noreferrer"&gt;https://www.bonzai.pro/matyo91/shop/48ov_2168/automation-avec-flow-en-php&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>🔨 J'ai créé un compilateur C en PHP capable de compiler du SQLite</title>
      <dc:creator>Mathieu Ledru</dc:creator>
      <pubDate>Sun, 30 Aug 2026 13:53:32 +0000</pubDate>
      <link>https://dev.to/matyo91/jai-cree-un-compilateur-c-en-php-capable-de-compiler-du-sqlite-2io6</link>
      <guid>https://dev.to/matyo91/jai-cree-un-compilateur-c-en-php-capable-de-compiler-du-sqlite-2io6</guid>
      <description>&lt;p&gt;Je voulais savoir quelle part du compilateur C je pouvais implémenter en PHP avant qu'il ne soit capable de compiler SQLite.&lt;/p&gt;

&lt;p&gt;À l'heure actuelle, la réponse est&amp;nbsp;: suffisant. Sur macOS ARM64, une interface C hébergée par PHP et un générateur de code ARM64 transforment le code SQLite 3.46.0 en assembleur textuel. L'assembleur et l'éditeur de liens d'Apple génèrent ensuite un exécutable natif. Un petit programme ouvre une base de données en mémoire, y insère une ligne, la sélectionne et l'affiche.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;darkwood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ce test d'acceptation est complété par une suite de tests de régression qui réussit &lt;strong&gt;46/46&lt;/strong&gt; tests. Le pipeline de compilation/validation externe est orchestré avec &lt;strong&gt;darkwood/flow v8.1.5&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Cet article propose une visite guidée de cette implémentation&amp;nbsp;: comment le code source devient des jetons, comment les macros s’étendent, comment les déclarateurs deviennent des types, comment l’analyse sémantique alimente la génération de code, comment l’architecture ARM64 est générée et quels bogues ont contraint les abstractions à adopter une approche pragmatique. Le plus intéressant n’est pas un tableau de bord de performances, mais le PHP qui implémente le C.&lt;/p&gt;

&lt;h2&gt;
  
  
  Que signifie concrètement « compiler SQLite en PHP » ?
&lt;/h2&gt;

&lt;p&gt;La précision est importante, car il est facile de survendre cette expression.&lt;/p&gt;

&lt;p&gt;Le compilateur PHP implémente&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C source
  → lexer / preprocessor
  → parser
  → AST
  → semantic analysis
  → ARM64 code generation
  → .s assembly text
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les outils natifs d'Apple effectuent ensuite les opérations suivantes&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ARM64 .s
  → Apple assembler (as)
  → Mach-O object

objects
  → system linker via the clang driver
  → native executable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Clang n'est pas utilisé pour compiler &lt;code&gt;sqlite3.c&lt;/code&gt; dans le chemin d'acceptation.&lt;/strong&gt; Il est utilisé comme pilote de liaison et parfois comme oracle différentiel pour les petites requêtes. PHP n'écrit pas de code Mach-O. La limite intéressante est&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;PHP implémente l'interface C et le générateur de code ARM64&amp;nbsp;; l'assembleur et l'éditeur de liens de la plateforme finalisent l'exécutable natif.&lt;/p&gt;

&lt;h2&gt;
  
  
  L'architecture délibérément réduite
&lt;/h2&gt;

&lt;p&gt;Il n'y a ni CIR, ni formulaire SSA, ni pipeline d'optimisation. Le pilote dans &lt;code&gt;src/Compiler/Driver/Compiler.php&lt;/code&gt; est presque linéaire&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$preprocessor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Preprocessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sourceManager&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;includePaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;defines&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$preprocessor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;preprocess&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fileId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;diagnostics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$decls&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$parser&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$sema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Sema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;diagnostics&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$tast&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sema&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$decls&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$enumConstants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sema&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;enumConstants&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sema&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nv"&gt;$codegen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Codegen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$enumConstants&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$assembly&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$codegen&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tast&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Symfony prend en charge les commandes de la console (&lt;code&gt;app:compiler-check&lt;/code&gt;, &lt;code&gt;app:compiler-fixtures&lt;/code&gt;, &lt;code&gt;app:compiler-sqlite&lt;/code&gt;, etc.). Elles ne font pas partie de l'algorithme de compilation. Le code pertinent se trouve dans &lt;code&gt;src/Compiler/&lt;/code&gt;, sous forme de classes PHP classiques. Les fichiers d'en-tête sous &lt;code&gt;include/&lt;/code&gt; fournissent une interface minimale Darwin/libc pour le frontend&amp;nbsp;— suffisante pour &lt;code&gt;stdio&lt;/code&gt;, &lt;code&gt;stdlib&lt;/code&gt;, les threads et les déclarations associées&amp;nbsp;— sans nécessiter une réécriture complète du SDK.&lt;/p&gt;

&lt;p&gt;L'utilisation de l'assembleur textuel était un choix de portée. Générer un fichier &lt;code&gt;.s&lt;/code&gt; permet d'hériter des diagnostics de l'assembleur d'Apple et d'un chemin de débogage lisible, sans avoir à créer un générateur Mach-O en PHP.&lt;/p&gt;

&lt;p&gt;En image :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                     PHP

sqlite3.c
   │
   ▼
┌──────────────┐
│ Preprocessor │
└──────┬───────┘
       ▼
┌──────────────┐
│    Parser    │
└──────┬───────┘
       ▼
┌──────────────┐
│     AST      │
└──────┬───────┘
       ▼
┌──────────────┐
│     Sema     │
└──────┬───────┘
       ▼
┌──────────────┐
│ ARM64 Codegen│
└──────┬───────┘
       │
       ▼
    sqlite3.s

                  macOS toolchain

sqlite3.s → as → sqlite3.o
smoke.s  → as → smoke.o
                 │
                 ▼
              linker → executable → darkwood
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Fichiers sources et jetons
&lt;/h2&gt;

&lt;p&gt;La compilation commence par l'identification de la source, et non par la grammaire.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SourceLoc&lt;/code&gt; est volontairement très petit&amp;nbsp;: un identifiant de fichier et un décalage en octets.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Common/SourceLoc.php&lt;/span&gt;
&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SourceLoc&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$fileId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La ligne et la colonne sont calculées ultérieurement par &lt;code&gt;SourceManager::lineCol()&lt;/code&gt;. Le gestionnaire conserve le contenu du fichier et une table en cache des décalages de début de ligne, puis effectue une recherche dichotomique pour trouver le décalage de début le plus grand &lt;code&gt;&amp;lt;= offset&lt;/code&gt;&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Common/SourceManager.php (excerpt)&lt;/span&gt;
&lt;span class="nv"&gt;$starts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;lineStarts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;fileId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Binary search: largest line-start index with start &amp;lt;= offset.&lt;/span&gt;
&lt;span class="nv"&gt;$lo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$starts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lo&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$hi&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$mid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intdiv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$lo&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$hi&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$starts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$mid&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nv"&gt;$offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$lo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$mid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$hi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$mid&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;$lineIdx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$hi&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$lineStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$starts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$lineIdx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'line'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$lineIdx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'col'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$offset&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nv"&gt;$lineStart&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les jetons contiennent l'orthographe, le type, l'emplacement et — élément crucial pour le préprocesseur — un &lt;strong&gt;ensemble de masquage&lt;/strong&gt;&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Common/Token.php&lt;/span&gt;
&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Token&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cd"&gt;/**
   * @param list&amp;lt;string&amp;gt; $hideSet Names that should NOT be expanded for this token (blue-painting)
   */&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;TokenKind&lt;/span&gt; &lt;span class="nv"&gt;$kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$spelling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;SourceLoc&lt;/span&gt; &lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$hideSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;withHideSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$newHideSet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;self&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;spelling&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spelling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;hideSet&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$newHideSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TokenKind&lt;/code&gt; est une petite énumération&amp;nbsp;: identifiant, mot-clé, littéraux entiers/flottants/caractères/chaînes de caractères, ponctuation et EOF. La conservation de l’emplacement de chaque jeton permet d’établir des diagnostics de la forme &lt;code&gt;file.c:line:column: error: ...&lt;/code&gt; après l’échec des étapes ultérieures.&lt;/p&gt;

&lt;p&gt;Il s'agit également d'une structure typiquement PHP&amp;nbsp;: objets de valeur immuables, tableaux de jetons et répartition &lt;code&gt;instanceof&lt;/code&gt;/&lt;code&gt;match&lt;/code&gt; plus tard dans le pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Création d'un préprocesseur C en PHP
&lt;/h2&gt;

&lt;p&gt;Le préprocesseur n'effectue pas de substitution de chaînes de caractères. Il s'agit d'une machine à jetons avec compilation conditionnelle et expansion récursive de macros.&lt;/p&gt;

&lt;p&gt;La fonction &lt;code&gt;Preprocessor::processTokens()&lt;/code&gt; parcourt un flux de jetons indexé. Une pile de conditions suit les directives &lt;code&gt;#if&lt;/code&gt; / &lt;code&gt;#elif&lt;/code&gt; / &lt;code&gt;#else&lt;/code&gt; / &lt;code&gt;#endif&lt;/code&gt; avec des cadres de la forme &lt;code&gt;{parentActive, anyBranchTaken, currentActive, seenElse}&lt;/code&gt;. Les jetons ne sont intégrés au chemin d'expansion que lorsque tous les cadres sont actifs. Les régions inactives continuent d'analyser les directives, ce qui permet de maintenir l'équilibre de l'imbrication.&lt;/p&gt;

&lt;p&gt;Lorsque la région est active, les jetons non directifs sont regroupés jusqu'au prochain début de ligne &lt;code&gt;#&lt;/code&gt;, puis transmis à &lt;code&gt;MacroExpander::expand()&lt;/code&gt;&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Preproc/Preprocessor.php (excerpt)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$isActive&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nc"&gt;TokenKind&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;Punct&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spelling&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'#'&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isAtLineStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nv"&gt;$batch&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$batch&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;array_push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;expander&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$batch&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les expressions &lt;code&gt;#if&lt;/code&gt; sont développées par le même expandeur après la réécriture &lt;code&gt;defined(...)&lt;/code&gt;, puis évaluées comme des expressions constantes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ensembles d'expansion et de masquage de macros
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;MacroExpander&lt;/code&gt; (dans &lt;code&gt;MacroTable.php&lt;/code&gt;) utilise un &lt;strong&gt;curseur indexé&lt;/strong&gt; sur l'entrée d'origine, ainsi qu'une pile d'attente inversée pour la réanalyse. Les expansions sont effectuées en sens inverse, de sorte que le prochain jeton à traiter est le premier jeton de l'expansion&amp;nbsp;— une sémantique de réanalyse classique sans avoir à effectuer des appels répétés à &lt;code&gt;array_shift()&lt;/code&gt; sur une grande liste.&lt;/p&gt;

&lt;p&gt;Lorsqu'un identifiant désigne une macro et n'est pas désactivé par son ensemble de masquage, l'extenseur fusionne le nom de la macro avec l'ensemble de masquage des jetons de remplacement («&amp;nbsp;peinture bleue&amp;nbsp;»). Cela empêche une récursion infinie lorsqu'une macro se développe en son propre nom&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Preproc/MacroTable.php (excerpt)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hideSet&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;in_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spelling&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hideSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$output&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$macro&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;lookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;spelling&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nv"&gt;$newHideSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unionHideSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;hideSet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$macro&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nv"&gt;$expanded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expandObjectLike&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$macro&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$newHideSet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expanded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;$i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nv"&gt;$pendingReversed&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$expanded&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les macros de type fonction analysent les listes d'arguments, prennent en charge la conversion en chaîne de caractères avec &lt;code&gt;#&lt;/code&gt; et le collage avec &lt;code&gt;##&lt;/code&gt;, et appliquent des ensembles de masquage aux jetons du corps. Les macros de type objet sont une version simplifiée de ce même mécanisme.&lt;/p&gt;

&lt;p&gt;La substitution parcourt le corps de la macro jeton par jeton. Les noms des paramètres sont remplacés par les listes de jetons d'arguments correspondantes (elles-mêmes soumises aux règles d'expansion), &lt;code&gt;#&lt;/code&gt; convertit un argument en une chaîne littérale, et &lt;code&gt;##&lt;/code&gt; concatène les jetons adjacents pour former une nouvelle orthographe. &lt;code&gt;__VA_ARGS__&lt;/code&gt; intervient pour les macros de type fonction variadique. Chaque jeton produit possède un ensemble de masquage incluant la macro en cours d'expansion, de sorte qu'une analyse ultérieure n'entrera pas à nouveau le même nom via le même jeton coloré.&lt;/p&gt;

&lt;p&gt;Pour un lecteur technique&amp;nbsp;: il s’agit d’un véritable sous-système de préprocesseur. L’agrégation de SQLite repose fortement sur les macros&amp;nbsp;; sans les ensembles masqués, la collecte des arguments, la conversion en chaîne de caractères et la compilation conditionnelle, l’analyseur syntaxique ne pourrait jamais obtenir un flux de jetons cohérent.&lt;/p&gt;

&lt;p&gt;Un des premiers tests de régression, &lt;code&gt;011-macro-eof&lt;/code&gt;, encode un cas limite où l'interaction de la fin de fichier (EOF) avec le remplacement de macros et l'évaluation conditionnelle corrompt le prétraitement. Ce type de test est une pratique courante du projet&amp;nbsp;: réduire l'erreur de fusion à un minuscule programme qui plante toujours en cas de régression du préprocesseur. Un autre test, &lt;code&gt;012-octal-escape&lt;/code&gt;, intervient une étape plus tard dans l'analyseur lexical/décodeur de chaînes — &lt;code&gt;"\040"&lt;/code&gt; doit être converti en octet correct — mais il illustre le même principe&amp;nbsp;: les règles lexicales «&amp;nbsp;ennuyeuses&amp;nbsp;» du C deviennent essentielles dès l'apparition des véritables en-têtes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyse syntaxique du C sans générateur d'analyseur syntaxique
&lt;/h2&gt;

&lt;p&gt;L'analyseur syntaxique est un hybride récursif descendant/Pratt écrit à la main, appliqué au tableau de jetons. Il n'utilise pas la grammaire yacc. Les déclarations, instructions et expressions sont des méthodes de &lt;code&gt;Parser&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Les nœuds AST sont des classes PHP ordinaires situées dans &lt;code&gt;src/Compiler/Common/Ast.php&lt;/code&gt;. Exemples de formes&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FuncDecl&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Decl&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;CType&lt;/span&gt; &lt;span class="nv"&gt;$returnType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nv"&gt;$variadic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;SourceLoc&lt;/span&gt; &lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;?CompoundStmt&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;StorageClass&lt;/span&gt; &lt;span class="nv"&gt;$storageClass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StorageClass&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nv"&gt;$isInline&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BinaryExpr&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Expr&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;BinaryOp&lt;/span&gt; &lt;span class="nv"&gt;$op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt; &lt;span class="nv"&gt;$left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt; &lt;span class="nv"&gt;$right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;SourceLoc&lt;/span&gt; &lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;?CType&lt;/span&gt; &lt;span class="nv"&gt;$resolvedType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CallExpr&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Expr&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt; &lt;span class="nv"&gt;$function&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$arguments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;SourceLoc&lt;/span&gt; &lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;?CType&lt;/span&gt; &lt;span class="nv"&gt;$resolvedType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CompoundLiteralExpr&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Expr&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;CType&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;Expr&lt;/span&gt; &lt;span class="nv"&gt;$initList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;SourceLoc&lt;/span&gt; &lt;span class="nv"&gt;$loc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kt"&gt;?CType&lt;/span&gt; &lt;span class="nv"&gt;$resolvedType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les nœuds d'expression peuvent contenir &lt;code&gt;resolvedType&lt;/code&gt; après l'analyse sémantique&amp;nbsp;; l'analyseur syntaxique construit d'abord la structure. L'analyse sémantique annote et vérifie les types directement, sans produire de réponse intermédiaire (IR) distincte.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pourquoi les déclarateurs C sont difficiles
&lt;/h3&gt;

&lt;p&gt;La grammaire déclarative du C est un piège classique. Il ne s'agit pas du même type&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;      &lt;span class="cm"&gt;/* array of 4 pointers to int */&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;    &lt;span class="cm"&gt;/* pointer to array of 4 int */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La fonction &lt;code&gt;parseDeclarator()&lt;/code&gt; implémente cette distinction. Le chemin non groupé applique d'abord &lt;code&gt;*&lt;/code&gt;, puis &lt;code&gt;[N]&lt;/code&gt; encapsule le type courant&amp;nbsp;; ainsi, &lt;code&gt;*p[4]&lt;/code&gt; devient un tableau de pointeurs. Le chemin groupé &lt;code&gt;(*p)&lt;/code&gt; construit un pointeur, peut collecter les dimensions entre parenthèses, puis applique les suffixes de fin avec &lt;code&gt;applyArraySuffix()&lt;/code&gt;, qui réaffecte &lt;code&gt;[N]&lt;/code&gt; à la &lt;strong&gt;pointée&lt;/strong&gt; lorsque le type courant est déjà un pointeur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Parser/Parser.php&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;applyArraySuffix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;CType&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?int&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;CType&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;PointerCType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
            &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayCType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IncompleteArrayCType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$to&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PointerCType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$array&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayCType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$count&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;IncompleteArrayCType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette fonction auxiliaire existe car une correction simpliste consistant à « appliquer le suffixe de tableau à l'ensemble du type » pour &lt;code&gt;int (*p)[N]&lt;/code&gt; peut accidentellement réécrire &lt;code&gt;int *p[N]&lt;/code&gt; et casser du code réel, y compris, historiquement, le chemin d'accès à SQLite. La fixture &lt;code&gt;051-pointer-to-array&lt;/code&gt; verrouille la lecture correcte&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Littéraux composés et initialiseurs désignés
&lt;/h3&gt;

&lt;p&gt;Les littéraux composés sont reconnus en position de conversion&amp;nbsp;: &lt;code&gt;(type){ ... }&lt;/code&gt; devient &lt;code&gt;CompoundLiteralExpr&lt;/code&gt; au lieu de &lt;code&gt;CastExpr&lt;/code&gt; lorsqu'une accolade initiale suit la parenthèse fermante.&lt;/p&gt;

&lt;p&gt;Les initialiseurs désignés analysent une liste de désignateurs C99 (&lt;code&gt;.&lt;/code&gt;field&lt;code&gt;/&lt;/code&gt;[index]&lt;code&gt;répété, puis&lt;/code&gt;=&lt;code&gt;) pour obtenir soit un désignateur unique, soit un chemin imbriqué stocké dans&lt;/code&gt;InitListExpr&lt;code&gt;. Ce chemin est ensuite normalisé pour les membres de structures et de tableaux imbriqués&amp;nbsp;—&amp;nbsp;le mécanisme sous-jacent au fixture&lt;/code&gt;044-nested-designated-init`.&lt;/p&gt;

&lt;h2&gt;
  
  
  Représentation des types C en PHP
&lt;/h2&gt;

&lt;p&gt;Toutes les classes de types principales se trouvent dans &lt;code&gt;src/Compiler/Common/CType.php&lt;/code&gt;&amp;nbsp;: primitives, &lt;code&gt;PointerCType&lt;/code&gt;, &lt;code&gt;ArrayCType&lt;/code&gt;, &lt;code&gt;IncompleteArrayCType&lt;/code&gt;, &lt;code&gt;FunctionCType&lt;/code&gt;, &lt;code&gt;StructCType&lt;/code&gt;, &lt;code&gt;UnionCType&lt;/code&gt;, &lt;code&gt;EnumCType&lt;/code&gt;, qualificateurs et wrappers typedef.&lt;/p&gt;

&lt;p&gt;Les questions que le compilateur pose à plusieurs reprises — taille, alignement, « est-ce un entier ? » — sont des méthodes sur &lt;code&gt;CType&lt;/code&gt; utilisant &lt;code&gt;match (true)&lt;/code&gt; et &lt;code&gt;instanceof&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
public function isInteger(): bool&lt;br&gt;
{&lt;br&gt;
    return match (true) {&lt;br&gt;
        $this instanceof BoolCType,&lt;br&gt;
        $this instanceof CharCType,&lt;br&gt;
        // ...&lt;br&gt;
        $this instanceof EnumCType =&amp;gt; true,&lt;br&gt;
        $this instanceof QualifiedCType =&amp;gt; $this-&amp;gt;base-&amp;gt;isInteger(),&lt;br&gt;
        $this instanceof TypedefCType =&amp;gt; $this-&amp;gt;base-&amp;gt;isInteger(),&lt;br&gt;
        default =&amp;gt; false,&lt;br&gt;
    };&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Le fait que &lt;code&gt;EnumCType&lt;/code&gt; soit un type entier a une incidence sur l'ABI&amp;nbsp;: les paramètres d'une énumération doivent être stockés dans des registres généraux, comme les autres entiers. La taille et l'alignement suivent une disposition de type LP64 (4 entiers, 8 pointeurs, 4 énumérations&amp;nbsp;; les structures et les unions utilisent la taille et l'alignement de leur enregistrement). La taille des éléments d'un tableau est multipliée par son nombre&amp;nbsp;; les tableaux incomplets n'ont pas de taille.&lt;/p&gt;

&lt;p&gt;La tension en C entre les &lt;strong&gt;tableaux&lt;/strong&gt; et les &lt;strong&gt;pointeurs&lt;/strong&gt; est omniprésente. Les tableaux perdent en performance dans de nombreux contextes d'expression, mais les types tableaux restent prioritaires dans les déclarateurs et pour l'optimisation arithmétique des pointeurs. Ne maîtriser qu'un seul de ces aspects, c'est risquer de livrer un compilateur qui, une fois lié, échoue toujours à l'opération &lt;code&gt;*(a+1)&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Analyse sémantique et résolution des symboles
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Sema&lt;/code&gt; fait plus que « vérifier les types ».&lt;/p&gt;

&lt;p&gt;Il gère des objets &lt;code&gt;Scope&lt;/code&gt; imbriqués (global, function, block), une carte typedef, des types d'enregistrements et une table publique &lt;code&gt;enumConstants&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
// src/Compiler/Sema/Sema.php (excerpt)&lt;br&gt;
final class Sema&lt;br&gt;
{&lt;br&gt;
  private Scope $globalScope;&lt;br&gt;
  private Scope $currentScope;&lt;br&gt;
  /** &lt;a class="mentioned-user" href="https://dev.to/var"&gt;@var&lt;/a&gt; array */&lt;br&gt;
  public array $enumConstants = [];&lt;/p&gt;

&lt;p&gt;public function analyze(array $decls): array&lt;br&gt;
  {&lt;br&gt;
    foreach ($decls as $decl) {&lt;br&gt;
      $this-&amp;gt;collectTopLevel($decl);&lt;br&gt;
    }&lt;br&gt;
    foreach ($decls as $decl) {&lt;br&gt;
      $this-&amp;gt;analyzeDecl($decl);&lt;br&gt;
    }&lt;br&gt;
    return $decls;&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Le premier passage insère les fonctions, variables et typedefs de niveau supérieur, et enregistre les cas d'énumération. Le deuxième passage effectue une vérification de type du corps. L'enregistrement d'une énumération écrit à la fois la table de correspondance plate et une constante globale &lt;code&gt;Symbol::enumConstant(...)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
private function registerEnumConstants(EnumType $enumType): void&lt;br&gt;
{&lt;br&gt;
  foreach ($enumType-&amp;gt;cases as $case) {&lt;br&gt;
    $this-&amp;gt;enumConstants[$case-&amp;gt;name] = $case-&amp;gt;value;&lt;br&gt;
    $this-&amp;gt;globalScope-&amp;gt;insert(Symbol::enumConstant(&lt;br&gt;
      name: $case-&amp;gt;name,&lt;br&gt;
      value: $case-&amp;gt;value,&lt;br&gt;
      type: IntCType::$instance,&lt;br&gt;
    ));&lt;br&gt;
  }&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Les énumérations de type &lt;code&gt;typedef&lt;/code&gt; et les énumérations anonymes imbriquées dans des structures alimentent également ce chemin d'enregistrement. La recherche d'identificateurs parcourt les portées, puis utilise &lt;code&gt;enumConstants&lt;/code&gt; par défaut afin que &lt;code&gt;VALUE&lt;/code&gt; dans &lt;code&gt;int result = VALUE;&lt;/code&gt; soit résolu même si la seule déclaration était un cas d'énumération.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Scope&lt;/code&gt; est une carte liée à son parent, regroupant les valeurs de &lt;code&gt;Symbol&lt;/code&gt; (&lt;code&gt;Variable&lt;/code&gt;, &lt;code&gt;Function&lt;/code&gt;, &lt;code&gt;Typedef&lt;/code&gt;, &lt;code&gt;EnumConstant&lt;/code&gt;). Le corps d'une fonction ouvre une portée de fonction globale&amp;nbsp;; les instructions composées s'imbriquent davantage. Les paramètres sont insérés avant l'analyse du corps.&lt;/p&gt;

&lt;p&gt;Le pilote transmet ensuite explicitement &lt;code&gt;enumConstants&lt;/code&gt; à codegen&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
$codegen = new Codegen($enumConstants);&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Cette conception fait du repliement constant des noms d'énumération dans les initialiseurs statiques un contrat partagé entre sema et le backend, et non une deuxième table de consultation indépendante inventée lors de l'émission.&lt;/p&gt;

&lt;p&gt;Voici à quoi ressemble un chemin de parcours concret pour un initialiseur d'énumération global&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;c&lt;br&gt;
enum { VALUE = 42 };&lt;br&gt;
int result = VALUE;&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;L'analyseur syntaxique construit un &lt;code&gt;EnumDecl&lt;/code&gt; / type énuméré avec le cas &lt;code&gt;VALUE = 42&lt;/code&gt;, puis un &lt;code&gt;VarDecl&lt;/code&gt; dont l'initialiseur est un &lt;code&gt;Identifier("VALUE")&lt;/code&gt;. Lors de la première passe de Sema, &lt;code&gt;VALUE → 42&lt;/code&gt; est enregistré dans &lt;code&gt;enumConstants&lt;/code&gt; et dans la portée globale. Lors de la seconde passe, l'initialiseur est vérifié comme étant un entier. Au moment de générer le &lt;code&gt;result&lt;/code&gt; global, Codegen résout l'identificateur via la table des constantes de l'énumération et génère une directive numérique (généralement &lt;code&gt;.long 42&lt;/code&gt;) plutôt qu'une relocalisation symbolique. Le fixture &lt;code&gt;015-enum-global&lt;/code&gt; permet d'éviter que le chemin d'exécution ne régresse silencieusement vers une erreur d'«&amp;nbsp;identificateur non déclaré&amp;nbsp;» ou vers une erreur d'«&amp;nbsp;émission de zéro&amp;nbsp;».&lt;/p&gt;

&lt;p&gt;Le typage des expressions couvre également les aléas courants dont SQLite dépend encore&amp;nbsp;: la dégradation des tableaux dans la plupart des contextes d’expression, les exigences relatives aux lvalues pour l’affectation et l’opérateur unaire &lt;code&gt;&amp;amp;&lt;/code&gt;, ainsi que les particularités liées à la position dans l’instruction, telles que &lt;code&gt;(void)sizeof(x);&lt;/code&gt; (correctif &lt;code&gt;013-sizeof-stmt&lt;/code&gt;). &lt;code&gt;sizeof&lt;/code&gt; est analysé comme un opérateur unaire pouvant accepter soit une expression, soit un nom de type entre parenthèses&amp;nbsp;; une erreur de classification à la position de l’instruction constitue un bogue de l’analyseur syntaxique qui n’apparaît jamais dans &lt;code&gt;return 42&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Expressions constantes et initialisation statique
&lt;/h2&gt;

&lt;p&gt;SQLite repose sur des données statiques&amp;nbsp;: tables, chaînes de caractères, pointeurs vers des tableaux, initialiseurs composés. L’émission globale n’est donc pas une simple note de bas de page.&lt;/p&gt;

&lt;p&gt;La fonction &lt;code&gt;Codegen::emitInitializer()&lt;/code&gt; sélectionne les directives d'assemblage à partir du type cible. Les entiers étroits et les caractères deviennent &lt;code&gt;.byte&lt;/code&gt;&amp;nbsp;; les entiers larges deviennent &lt;code&gt;.long&lt;/code&gt; / &lt;code&gt;.quad&lt;/code&gt;&amp;nbsp;; les tableaux parcourent chaque élément et &lt;code&gt;.zero&lt;/code&gt; supprime les caractères restants&amp;nbsp;; les chaînes littérales converties en tableaux de caractères copient les octets et complètent le code. Les variables globales de tableaux de caractères sont définies par la fixture &lt;code&gt;010-char-array-global&lt;/code&gt;, qui exige &lt;code&gt;.byte&lt;/code&gt; et interdit &lt;code&gt;.quad 84&lt;/code&gt; dans l'assembleur.&lt;/p&gt;

&lt;p&gt;Une compilation en direct de ce composant produit actuellement&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;asm&lt;br&gt;
.section __DATA,__data&lt;br&gt;
.globl _table&lt;br&gt;
.p2align 3&lt;br&gt;
_table:&lt;br&gt;
.byte 84&lt;br&gt;
.byte 92&lt;br&gt;
.byte 134&lt;br&gt;
.byte 0&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ce résultat dépend de la correspondance entre &lt;code&gt;instanceof ArrayCType&lt;/code&gt; et la classe réelle dans &lt;code&gt;App\Compiler\Common&lt;/code&gt;. En PHP, un nom &lt;code&gt;ArrayCType&lt;/code&gt; simple dans &lt;code&gt;App\Compiler\CodeGen&lt;/code&gt; est résolu en &lt;code&gt;App\Compiler\CodeGen\ArrayCType&lt;/code&gt; sauf s'il est importé. Un élément manquant&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
use App\Compiler\Common\ArrayCType;&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La branche du tableau est devenue inaccessible. Les variables globales ont été déplacées et ont généré des fichiers &lt;code&gt;.quad&lt;/code&gt; au lieu de &lt;code&gt;.byte&lt;/code&gt;. Le programme a pu être assemblé et lié. La disposition à l'exécution restait incorrecte. Il s'agit d'un bogue interlangage au sens strict&amp;nbsp;: &lt;strong&gt;la résolution de noms PHP a corrompu la disposition des données statiques C.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Les initialiseurs globaux de pointeurs (&lt;code&gt;&amp;amp;arr[i]&lt;/code&gt;), les définitions provisoires et les littéraux composés globaux sont des problèmes frères dans le même voisinage : le backend doit comprendre non seulement « émettre un entier », mais aussi « émettre une adresse relocalisable », « fusionner les définitions provisoires » et « matérialiser un agrégat constant dans la section de données ».&lt;/p&gt;
&lt;h2&gt;
  
  
  De l'AST typé à l'ARM64
&lt;/h2&gt;

&lt;p&gt;Le backend est &lt;code&gt;src/Compiler/CodeGen/Codegen.php&lt;/code&gt;, avec les conventions d'enregistrement dans &lt;code&gt;Arm64.php&lt;/code&gt;&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
const SCRATCH_REGS = [&lt;br&gt;
    Arm64Reg::X9, Arm64Reg::X10, Arm64Reg::X11, Arm64Reg::X12,&lt;br&gt;
    Arm64Reg::X13, Arm64Reg::X14, Arm64Reg::X15,&lt;br&gt;
];&lt;/p&gt;

&lt;p&gt;const ARG_REGS = [&lt;br&gt;
    Arm64Reg::X0, Arm64Reg::X1, Arm64Reg::X2, Arm64Reg::X3,&lt;br&gt;
    Arm64Reg::X4, Arm64Reg::X5, Arm64Reg::X6, Arm64Reg::X7,&lt;br&gt;
];&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La fonction &lt;code&gt;RegAlloc&lt;/code&gt; alloue des registres temporaires. Les arguments sont reçus sous forme de &lt;code&gt;x0&lt;/code&gt; à &lt;code&gt;x7&lt;/code&gt;, conformément à l'utilisation de type AAPCS64 dans ce backend. Les valeurs de retour sont de &lt;code&gt;x0&lt;/code&gt; (et de &lt;code&gt;x1&lt;/code&gt; pour les petits agrégats plus importants). L'assembleur est accumulé sous forme de chaînes de caractères et affiché comme du texte&amp;nbsp;— une autre pratique native de PHP.&lt;/p&gt;
&lt;h3&gt;
  
  
  Une fonction concrète
&lt;/h3&gt;

&lt;p&gt;Donné:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;c&lt;br&gt;
int add(int a, int b)&lt;br&gt;
{&lt;br&gt;
    return a + b;&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ce compilateur génère (représentatif)&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;asm&lt;br&gt;
.text&lt;br&gt;
.globl _add&lt;br&gt;
.p2align 2&lt;br&gt;
_add:&lt;br&gt;
stp x29, x30, [sp, #-16]!&lt;br&gt;
mov x29, sp&lt;br&gt;
sub sp, sp, #16&lt;br&gt;
str x0, [x29, #-8]&lt;br&gt;
str x1, [x29, #-16]&lt;br&gt;
add x9, x29, #-8&lt;br&gt;
ldrsw x9, [x9]&lt;br&gt;
add x10, x29, #-16&lt;br&gt;
ldrsw x10, [x10]&lt;br&gt;
add x9, x9, x10&lt;br&gt;
mov x0, x9&lt;br&gt;
mov sp, x29&lt;br&gt;
ldp x29, x30, [sp], #16&lt;br&gt;
ret&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Lire cela au regard de la mise en œuvre&amp;nbsp;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Le prologue sauvegarde le pointeur de cadre et le registre de lien, définit &lt;code&gt;x29&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Les variables locales/paramètres reçoivent des décalages négatifs par rapport à &lt;code&gt;x29&lt;/code&gt;; les arguments sont stockés à partir de &lt;code&gt;x0&lt;/code&gt;/&lt;code&gt;x1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Les chargements utilisent &lt;code&gt;ldrsw&lt;/code&gt; pour les valeurs signées 32 bits dans des registres 64 bits&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;add&lt;/code&gt; produit la somme dans un registre temporaire, puis la déplace vers &lt;code&gt;x0&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;L'épilogue restaure &lt;code&gt;sp&lt;/code&gt; à partir de &lt;code&gt;x29&lt;/code&gt; et renvoie&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;La taille de la trame est calculée en fonction des besoins locaux et insérée dans un espace réservé &lt;code&gt;sub sp, sp, #...&lt;/code&gt; émis au début de &lt;code&gt;emitFunction()&lt;/code&gt;. L'alignement sur 16 octets est important sur AArch64&amp;nbsp;; le backend arrondit/agrège les emplacements temporaires en conséquence.&lt;/p&gt;
&lt;h3&gt;
  
  
  Cadres de pile et variables locales
&lt;/h3&gt;

&lt;p&gt;L'allocation locale est volontairement simple et explicite. &lt;code&gt;emitFunction()&lt;/code&gt; réinitialise l'état de chaque fonction, émet une soustraction de trame de substitution, puis détermine l'espace mémoire nécessaire aux paramètres, aux variables locales et aux variables temporaires&amp;nbsp;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;php&lt;br&gt;
$this-&amp;gt;emitLine('stp x29, x30, [sp, #-16]!');&lt;br&gt;
$this-&amp;gt;emitLine('mov x29, sp');&lt;br&gt;
$this-&amp;gt;emitLine('sub sp, sp, #0  ; FRAME_SIZE_PLACEHOLDER');&lt;br&gt;
$this-&amp;gt;framePlaceholderIndex = count($this-&amp;gt;lines) - 1;&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;La fonction &lt;code&gt;ensureLocalSpace()&lt;/code&gt; incrémente un &lt;code&gt;localOffset&lt;/code&gt; continu, alignant chaque réservation sur 8 octets. La fonction &lt;code&gt;allocLocal()&lt;/code&gt; stocke le décalage négatif choisi par rapport à &lt;code&gt;x29&lt;/code&gt; dans &lt;code&gt;localVarOffsets&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;`php&lt;br&gt;
private function ensureLocalSpace(int $size): void&lt;br&gt;
{&lt;br&gt;
    $aligned = ($size + 7) &amp;amp; ~7;&lt;br&gt;
    $this-&amp;gt;localOffset += $aligned;&lt;br&gt;
    if ($this-&amp;gt;localOffset &amp;gt; $this-&amp;gt;frameSize) {&lt;br&gt;
        $this-&amp;gt;frameSize = $this-&amp;gt;localOffset;&lt;br&gt;
    }&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;private function allocLocal(string $name, CType $type): void&lt;br&gt;
{&lt;br&gt;
    $size = $type-&amp;gt;sizeInBytes() ?? 8;&lt;br&gt;
    $this-&amp;gt;ensureLocalSpace($size);&lt;br&gt;
    $offset = -$this-&amp;gt;localOffset;&lt;br&gt;
    $this-&amp;gt;localVarOffsets[$name] = $offset;&lt;br&gt;
    $this-&amp;gt;localVarTypes[$name] = $type;&lt;br&gt;
}&lt;br&gt;
`&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Les paramètres arrivant dans &lt;code&gt;x0&lt;/code&gt;–&lt;code&gt;x7&lt;/code&gt; sont immédiatement répartis dans les emplacements correspondants (&lt;code&gt;str x0, [x29, #-8]&lt;/code&gt;, etc.). Cela confère à chaque variable locale nommée une adresse stable pour &lt;code&gt;&amp;amp;var&lt;/code&gt;, pour la récupération des adresses de champs et pour le rechargement après les appels. Les structures de grande taille (&amp;gt; 16 octets) réservent également de l'espace pour le pointeur invisible &lt;code&gt;x8&lt;/code&gt; et le stockent en amont.&lt;/p&gt;

&lt;p&gt;Lorsque le corps de la fonction est entièrement émis, la ligne d'espace réservé est raccordée à la véritable &lt;code&gt;sub sp, sp, #&amp;lt;rounded frame&amp;gt; La taille de la trame est arrondie à l'entier supérieur afin que &lt;/code&gt;sp&lt;code&gt; reste aligné sur 16 octets — une exigence stricte sur AArch64. L'épilogue restaure &lt;/code&gt;sp&lt;code&gt; à partir de &lt;/code&gt;x29&lt;code&gt;, retire la paire sauvegardée et &lt;/code&gt;ret`s.&lt;/p&gt;

&lt;p&gt;Les variables temporaires composées, les emplacements de retour d'agrégats de petite taille et la mise en attente des arguments d'appel se disputent les mêmes ressources mémoire. C'est pourquoi les bogues d'ABI ressemblent souvent à une corruption de pile «&amp;nbsp;aléatoire&amp;nbsp;» jusqu'à ce qu'on remarque qu'une variable temporaire a été allouée avec une taille incorrecte ou qu'un appel imbriqué a écrasé un emplacement contenant encore un argument non évalué.&lt;/p&gt;
&lt;h3&gt;
  
  
  Arithmétique des pointeurs
&lt;/h3&gt;

&lt;p&gt;Les opérations binaires &lt;code&gt;+&lt;/code&gt; et &lt;code&gt;-&lt;/code&gt; utilisant des opérandes de type pointeur adaptent la partie entière à la taille de la valeur pointée. Les tableaux sont considérés comme des opérandes de type pointeur à cet effet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/CodeGen/Codegen.php (excerpt)&lt;/span&gt;
&lt;span class="nv"&gt;$leftIsPtrLike&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$leftType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPointer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$leftType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$rightIsPtrLike&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$rightType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPointer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$rightType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$ptrType&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;ArrayCType&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nv"&gt;$ptrType&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;IncompleteArrayCType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$ptrType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;of&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;unqualified&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nv"&gt;$pointeeSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isPointer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$t&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sizeInBytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$pointeeSize&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// lsl #1/#2/#3 or mul by immediate size&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Avant la correction de Loop 32, &lt;code&gt;*(a+1)&lt;/code&gt; pouvait renvoyer &lt;code&gt;add ..., #1&lt;/code&gt; en octets. Le fixture &lt;code&gt;035-array-ptr-arith&lt;/code&gt; nécessite désormais une mise à l'échelle des éléments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Appel de fonctions sur ARM64
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;emitCallExpr()&lt;/code&gt; évalue les arguments, les répartit dans la pile dans un ordre discipliné, charge &lt;code&gt;x0&lt;/code&gt;–&lt;code&gt;x7&lt;/code&gt; (et les arguments de la pile au-delà), puis soit &lt;code&gt;bl _name&lt;/code&gt; pour les appels directs, soit &lt;code&gt;blr xn&lt;/code&gt; pour les appels indirects.&lt;/p&gt;

&lt;p&gt;Les pointeurs de fonction sont des types de première classe dans le système de types (&lt;code&gt;PointerCType&lt;/code&gt; vers &lt;code&gt;FunctionCType&lt;/code&gt;) et dans la génération de code. Un exemple minimal&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Émet une séquence d'appel indirect qui charge l'adresse de l'appelé et utilise &lt;code&gt;blr&lt;/code&gt; (et non &lt;code&gt;bl&lt;/code&gt;) vers un symbole fixe. Les appels directs de &lt;code&gt;main&lt;/code&gt; vers &lt;code&gt;call&lt;/code&gt; utilisent toujours &lt;code&gt;bl _call&lt;/code&gt;, tandis que la récupération de l'adresse de &lt;code&gt;id&lt;/code&gt; utilise &lt;code&gt;adrp&lt;/code&gt;/&lt;code&gt;add&lt;/code&gt; avec les relocalisations &lt;code&gt;@PAGE&lt;/code&gt; / &lt;code&gt;@PAGEOFF&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appels variadiques
&lt;/h3&gt;

&lt;p&gt;Les appels variadiques sont plus précis. L'évaluation des arguments peut avoir des effets de bord&amp;nbsp;; la durée de vie des registres et de la pile interagit mal avec l'émission naïve de gauche à droite, ce qui fausse les résultats précédents. Le fixture &lt;code&gt;016-variadic-spill&lt;/code&gt; est la forme réduite&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d%d%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La sortie standard attendue est &lt;code&gt;123&lt;/code&gt; avec le code de sortie 42. Le chemin d'exécution du backend, de type printf, évalue les arguments en variables temporaires sur la pile avant d'assembler la variable d'origine finale, évitant ainsi la perte d'incréments due à la réutilisation des registres. Générer du code ARM64 syntaxiquement valide est bien plus simple que d'implémenter une convention d'appel qui résiste aux arguments à effets de bord.&lt;/p&gt;

&lt;h3&gt;
  
  
  Faibles rendements agrégés
&lt;/h3&gt;

&lt;p&gt;Apple ARM64 renvoie des agrégats d'au maximum 16 octets dans &lt;code&gt;x0&lt;/code&gt; (et &lt;code&gt;x1&lt;/code&gt; si supérieur à 8). &lt;code&gt;emitSmallAggregateReturn()&lt;/code&gt; matérialise la valeur dans un emplacement de pile, puis charge &lt;code&gt;x0&lt;/code&gt;/&lt;code&gt;x1&lt;/code&gt;&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;elseif&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;CallExpr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitExpr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'str x0, ['&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$addrReg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;']'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'str x1, ['&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$addrReg&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="s1"&gt;', #8]'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ldr x0, [sp]'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$size&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'ldr x1, [sp, #8]'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La branche &lt;code&gt;CallExpr&lt;/code&gt; existe car le transfert de &lt;code&gt;return a();&lt;/code&gt; à l'intérieur d'une autre fonction renvoyant une structure doit préserver l'intégralité du résultat du registre de l'appel imbriqué. Ne stocker qu'une représentation 32 bits de &lt;code&gt;x0&lt;/code&gt; entraîne la perte d'un champ. Ceci correspond à la boucle 48 / fixture &lt;code&gt;054-struct-return-chain&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Dans l'assembleur généré pour &lt;code&gt;b&lt;/code&gt;, vous pouvez voir le modèle : &lt;code&gt;bl _a&lt;/code&gt;, puis &lt;code&gt;str x0, [...]&lt;/code&gt;, puis &lt;code&gt;ldr x0, [sp]&lt;/code&gt; avant de retourner — le petit agrégat est traité comme une valeur de largeur de registre, et non comme un seul &lt;code&gt;w0&lt;/code&gt; restant d'une mentalité scalaire.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structures, unions et littéraux composés
&lt;/h2&gt;

&lt;p&gt;La disposition des structures et des unions est calculée lors de l'analyse de la définition d'enregistrement, puis stockée dans un &lt;code&gt;RecordType&lt;/code&gt; consulté ultérieurement par &lt;code&gt;StructCType&lt;/code&gt; / &lt;code&gt;UnionCType&lt;/code&gt;. Pour les structures, chaque champ est aligné sur son propre alignement, les décalages s'accumulent et la taille totale est arrondie à l'alignement maximal de l'enregistrement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Parser/Parser.php (struct field layout excerpt)&lt;/span&gt;
&lt;span class="nv"&gt;$fieldAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$fieldType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alignOf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$fieldSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$fieldType&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sizeInBytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nv"&gt;$maxAlign&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$maxAlign&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$fieldAlign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$byteOff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$byteOff&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$fieldAlign&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$fieldAlign&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$fields&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecordField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$fieldName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$fieldType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bitWidth&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$byteOff&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bitOffset&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$bitOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$byteOff&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$fieldSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="nv"&gt;$totalBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;intdiv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$bitOffset&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$totalBytes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$totalBytes&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$maxAlign&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$maxAlign&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$rec&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RecordType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$tag&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$fields&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$totalBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;alignment&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;$maxAlign&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les unions prennent la taille maximale des membres (arrondie à l'alignement maximal) et placent chaque champ à l'offset &lt;code&gt;0&lt;/code&gt;. Les champs de bits existent également dans le chemin de structure du parseur&amp;nbsp;; ils suivent les décalages de bits au sein des unités de stockage. Codegen utilise les décalages de champ lors de l'émission de l'accès aux membres (ajout d'une constante à une adresse de base) et lors de la mise en place des initialiseurs de structure globaux (insertion d'un remplissage &lt;code&gt;.zero&lt;/code&gt; entre les positions de champ désignées).&lt;/p&gt;

&lt;p&gt;Ces informations de mise en page rendent possibles les arguments agrégés, les retours et les littéraux composés : sans décalages fiables, « champ &lt;code&gt;b&lt;/code&gt; d'une structure de 8 octets » relève de la conjecture.&lt;/p&gt;

&lt;p&gt;Les littéraux composés sont abaissés en matérialisant un élément temporaire&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// emitAddr() path for CompoundLiteralExpr&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$expr&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nc"&gt;CompoundLiteralExpr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// allocate frame slot, compute address in a register&lt;/span&gt;
    &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;emitLocalInit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$reg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;initList&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expr&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$reg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Passer &lt;code&gt;(struct S){20, 22}&lt;/code&gt; comme argument signifie donc&amp;nbsp;: construire la variable temporaire, puis passer l’agrégat de la mémoire dans les registres d’arguments ou la pile en fonction de sa taille — et non «&amp;nbsp;évaluer la liste d’initialisation comme s’il ne s’agissait que du premier champ&amp;nbsp;». Le fixture &lt;code&gt;034-compound-lit-arg&lt;/code&gt; existe parce que cette erreur a renvoyé &lt;code&gt;20&lt;/code&gt; au lieu de &lt;code&gt;42&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Les initialiseurs désignés imbriqués (&lt;code&gt;{.iy = 2, .ix = 1}&lt;/code&gt;, &lt;code&gt;{.a[1] = 40}&lt;/code&gt;) exigent que le normaliseur d'initialiseurs parcoure les chemins de désignation dans les structures et tableaux imbriqués, y compris à travers les membres anonymes lorsqu'ils sont présents. Le fixture &lt;code&gt;044-nested-designated-init&lt;/code&gt; est la sonde réduite.&lt;/p&gt;

&lt;h2&gt;
  
  
  La limite de la chaîne d'outils native
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Toolchain&lt;/code&gt; est volontairement minimaliste&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Compiler/Platform/Toolchain.php&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;assemble&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$asmPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$objectPath&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;ProcessResult&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'/usr/bin/as'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$asmPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-o'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$objectPath&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$objectPaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$outputExecutable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$extraArgs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;ProcessResult&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;array_merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'/usr/bin/clang'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="nv"&gt;$objectPaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-o'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$outputExecutable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-lm'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-lpthread'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-ldl'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nv"&gt;$extraArgs&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La fonction &lt;code&gt;run()&lt;/code&gt; utilise &lt;code&gt;proc_open&lt;/code&gt;, capture la sortie standard et la sortie d'erreur, et renvoie un code de sortie. Cela suffit. PHP écrit les fichiers &lt;code&gt;.s&lt;/code&gt;&amp;nbsp;; &lt;code&gt;as&lt;/code&gt; écrit les fichiers &lt;code&gt;.o&lt;/code&gt;&amp;nbsp;; le pilote Clang effectue les liens. Clang ne compile toujours pas le code source C sur le chemin d'acceptation.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQLite en tant qu'oracle d'intégration
&lt;/h2&gt;

&lt;p&gt;La compilation de &lt;code&gt;return 42&lt;/code&gt; prouve que le canal est connecté. La compilation de SQLite prouve que les sous-systèmes interagissent.&lt;/p&gt;

&lt;p&gt;Le script (&lt;code&gt;fixtures/compiler/sqlite_smoke_test.c&lt;/code&gt;) ouvre &lt;code&gt;:memory:&lt;/code&gt;, crée une table, y insère &lt;code&gt;'darkwood'&lt;/code&gt;, la sélectionne et affiche le texte. Cela sollicite une unité de traduction importante, des en-têtes riches en macros, des données globales, des pointeurs de fonction, des structures, des énumérations et une quantité suffisante de conventions d'appel pour que des erreurs de débordement de tampon provoquent des échecs à l'exécution, même si l'assembleur semble correct.&lt;/p&gt;

&lt;p&gt;SQLite n'est pas une suite de standards. C'est un oracle d'intégration&amp;nbsp;: de nombreuses fonctionnalités doivent être quasiment parfaites simultanément, sinon le test de validation échoue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Les bugs de l'implémentation exposés
&lt;/h2&gt;

&lt;p&gt;Le principal atout technique de ce projet réside dans l'ensemble des bogues qui n'ont été mis en évidence que par la confrontation d'abstractions. Chaque cas présenté ci-dessous suit le même schéma&amp;nbsp;: petit programme C, comportement attendu, comportement anormal, cause racine en PHP, correctif, fixture.&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas&amp;nbsp;: &lt;code&gt;ArrayCType&lt;/code&gt; et données statiques corrompues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;010-char-array-global&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;84&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;92&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;134&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Résultat attendu&amp;nbsp;:&lt;/strong&gt; sortie &lt;code&gt;84&lt;/code&gt;; l’assembly contient &lt;code&gt;.byte&lt;/code&gt;, et non &lt;code&gt;.quad 84&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec&amp;nbsp;:&lt;/strong&gt; l'absence de &lt;code&gt;use App\Compiler\Common\ArrayCType;&lt;/code&gt; dans &lt;code&gt;Codegen.php&lt;/code&gt; a entraîné le test de la mauvaise classe par &lt;code&gt;instanceof ArrayCType&lt;/code&gt;. La branche d'initialisation du tableau ne s'est jamais exécutée. Des directives plus larges ont mal agencé le tableau.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction&amp;nbsp;:&lt;/strong&gt; importer la classe réelle&amp;nbsp;; émettre un &lt;code&gt;.byte&lt;/code&gt; par élément pour les tableaux de caractères. Conservé explicitement dans les notes d’état du projet et verrouillé par les assertions d’assemblage des fixtures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; une erreur d’espace de noms PHP est un bug d’ABI/de structure C. «&amp;nbsp;Liens&amp;nbsp;» ne signifie pas «&amp;nbsp;fonctionne&amp;nbsp;».&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas&amp;nbsp;: mise à l’échelle arithmétique des pointeurs de tableaux
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;035-array-ptr-arith&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Attendu :&lt;/strong&gt; sortie &lt;code&gt;42&lt;/code&gt; (également comparé avec clang).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; &lt;code&gt;a + 1&lt;/code&gt; avancé d'octets car les tableaux n'ont pas été traités comme des pointeurs pour la mise à l'échelle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction :&lt;/strong&gt; dans &lt;code&gt;emitBinaryExpr&lt;/code&gt;, traiter &lt;code&gt;ArrayCType&lt;/code&gt; comme un pointeur pour &lt;code&gt;+&lt;/code&gt;/&lt;code&gt;-&lt;/code&gt;, mettre à l'échelle par &lt;code&gt;sizeof(element)&lt;/code&gt; via &lt;code&gt;lsl&lt;/code&gt;/&lt;code&gt;mul&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; la dégradation des tableaux et la mise à l’échelle des pointes ne sont pas le même bug, mais ils sont étroitement liés.&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas&amp;nbsp;: déclarations de pointeurs vers des tableaux
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;051-pointeur-vers-tableau&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Résultat attendu&amp;nbsp;:&lt;/strong&gt; correspond à clang.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; l'application du suffixe déclaratif qui a réparé &lt;code&gt;(*p)[N]&lt;/code&gt; pourrait casser &lt;code&gt;*p[N]&lt;/code&gt; si elle est appliquée de manière trop large.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction&amp;nbsp;:&lt;/strong&gt; Fermez le déclarateur &lt;code&gt;(*name)&lt;/code&gt; groupé avant les suffixes de tableau&amp;nbsp;; utilisez &lt;code&gt;applyArraySuffix()&lt;/code&gt; pour que &lt;code&gt;[N]&lt;/code&gt; pointe vers un pointeur de type pointeur. Conservez le chemin non groupé pour la construction de tableaux de pointeurs de manière classique.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; Les déclarateurs C posent un problème d’analyse syntaxique avec des conséquences sémantiques&amp;nbsp;; les fixtures doivent couvrir les deux interprétations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas : arguments littéraux composés
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;034-compound-lit-arg&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;22&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Attendu :&lt;/strong&gt; &lt;code&gt;42&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; l'évaluation d'une liste littérale composée / init comme valeur n'a renvoyé que le premier champ (&lt;code&gt;20&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction :&lt;/strong&gt; matérialiser le littéral composé dans un cadre temporaire dans &lt;code&gt;emitAddr&lt;/code&gt;, puis passer la structure ≤16 octets de la mémoire dans les registres d'arguments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; les agrégats éphémères ont besoin d’adresses, et non d’un «&amp;nbsp;premier scalaire&amp;nbsp;».&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas&amp;nbsp;: initialiseurs désignés imbriqués
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;044-nested-designated-init&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Outer&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Arr&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Résultat attendu&amp;nbsp;:&lt;/strong&gt; les valeurs des champs et des emplacements de tableau correspondent à la lecture de clang.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; les désignateurs à un seul niveau fonctionnaient ; les chemins imbriqués et les désignateurs de tableau à l'intérieur des structures ne fonctionnaient pas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction&amp;nbsp;:&lt;/strong&gt; analyser les listes de désignateurs en chemins&amp;nbsp;; normaliser ces chemins lors de l’application des initialiseurs, y compris à travers les membres imbriqués et anonymes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; L’initialisation simplifiée du C99 n’est pas optionnelle si vous prétendez utiliser du «&amp;nbsp;vrai C&amp;nbsp;» plutôt qu’un code de type SQLite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas : déversements variadiques
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;016-variadic-spill&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%d%d%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Résultat attendu :&lt;/strong&gt; stdout &lt;code&gt;123&lt;/code&gt;, sortie &lt;code&gt;42&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; l'ordre d'évaluation des arguments / la durée de vie des registres ont été détruits par les résultats précédents de &lt;code&gt;next()&lt;/code&gt; avant l'appel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction :&lt;/strong&gt; évaluer dans des temporaires de pile, puis assembler l'appel variadique à la maison (le chemin en forme de printf dans &lt;code&gt;emitCallExpr&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; les arguments à effets secondaires sont un test ABI, et non un test d’analyse syntaxique.&lt;/p&gt;

&lt;h3&gt;
  
  
  Étude de cas&amp;nbsp;: chaînes de retour de structures
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Programme&lt;/strong&gt; (&lt;code&gt;054-struct-return-chain&lt;/code&gt;)&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;S&lt;/span&gt; &lt;span class="nf"&gt;b&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// main: struct S s = b(); return s.a + s.b;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Résultat attendu :&lt;/strong&gt; sortie &lt;code&gt;3&lt;/code&gt; (oracle clang).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mode d'échec :&lt;/strong&gt; le retour agrégé imbriqué n'a préservé qu'une partie de &lt;code&gt;x0&lt;/code&gt; (sortie symptomatique &lt;code&gt;2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Correction :&lt;/strong&gt; dans &lt;code&gt;emitSmallAggregateReturn()&lt;/code&gt;, lorsque l'expression renvoyée est une &lt;code&gt;CallExpr&lt;/code&gt;, stockez &lt;code&gt;x0&lt;/code&gt; complet et, si nécessaire, &lt;code&gt;x1&lt;/code&gt; avant de recharger pour le retour de la fonction actuelle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Leçon&amp;nbsp;:&lt;/strong&gt; générer &lt;code&gt;ret&lt;/code&gt; après &lt;code&gt;bl&lt;/code&gt; n’est pas la même chose que de mettre en œuvre le transfert de retour agrégé.&lt;/p&gt;

&lt;h2&gt;
  
  
  Des échecs aux tests de régression
&lt;/h2&gt;

&lt;p&gt;La méthodologie est plus importante que n'importe quel KEEP individuel&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQLite failure (or clang mismatch)
  → identify subsystem
  → reduce to a tiny C program
  → compare observable behavior
  → create fixtures/compiler/NNN-*.c + .json
  → fix one narrow behavior
  → run app:compiler-fixtures
  → run app:compiler-sqlite
  → KEEP only if still valid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Les métadonnées des fixtures peuvent vérifier les codes de sortie, la sortie standard, les sous-chaînes d'assemblage et &lt;code&gt;compareWithClang&lt;/code&gt;. Les assertions d'assemblage permettent de détecter les erreurs de mise en page qu'un code de sortie chanceux pourrait manquer. Le fait que la suite se termine à &lt;strong&gt;46/46&lt;/strong&gt; n'est pas un simple effet de mode&amp;nbsp;; il s'agit d'un souvenir des interactions qui ont déjà affecté l'amalgame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sondes différentielles
&lt;/h2&gt;

&lt;p&gt;Pour les petits programmes, la compilation et l'exécution du même code source avec clang fournissent un oracle exécutable&amp;nbsp;: le code de sortie et la sortie standard. Des commandes telles que &lt;code&gt;app:compiler-compare-clang&lt;/code&gt; et les flux de test existent pour faciliter ce processus. Clang est ici un &lt;strong&gt;outil de comparaison différentielle à l'exécution&lt;/strong&gt;, et non le compilateur de &lt;code&gt;sqlite3.c&lt;/code&gt; dans le cadre de la validation.&lt;/p&gt;

&lt;p&gt;Cette distinction est importante. Les tests différentiels répondent à la question&amp;nbsp;: «&amp;nbsp;Notre ABI correspond-elle au comportement observable sur cette sonde&amp;nbsp;?&amp;nbsp;» Les tests d’acceptation répondent à la question&amp;nbsp;: «&amp;nbsp;Notre compilateur compile-t-il SQLite&amp;nbsp;?&amp;nbsp;»&lt;/p&gt;

&lt;h2&gt;
  
  
  Où Darkwood Flow trouve sa place
&lt;/h2&gt;

&lt;p&gt;La compilation comprend deux pipelines différents. Les confondre produit soit une abstraction inutile, soit une réimplémentation privée d'un élément qui devrait être partagé.&lt;/p&gt;

&lt;p&gt;Le pipeline algorithmique est étroitement couplé&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tokens → AST → semantic model → assembly
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ces étapes échangent des structures spécifiques au compilateur&amp;nbsp;: listes de jetons, arbres de déclarations, graphes de types C et allocateurs de registres. Encapsuler chaque étape d'analyse syntaxique dans un framework d'orchestration n'apporterait aucune clarté. L'algorithme de masquage d'ensembles ne s'améliore pas du simple fait de son passage par une file d'attente de tâches.&lt;/p&gt;

&lt;p&gt;Le processus opérationnel est différent&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compile → assemble → link → execute → validate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chaque étape possède des limites d'artefacts clairement définies, peut échouer indépendamment, peut enregistrer le temps d'exécution sur un état partagé et peut être remplacée sans réécrire l'analyseur lexical. C'est là que &lt;strong&gt;Darkwood Flow&lt;/strong&gt; trouve toute sa place.&lt;/p&gt;

&lt;p&gt;Ce projet dépend du paquet Composer &lt;code&gt;darkwood/flow&lt;/code&gt; &lt;strong&gt;v8.1.5&lt;/strong&gt;. Le noyau du compilateur situé dans &lt;code&gt;src/Compiler/&lt;/code&gt; n'importe pas Flow. Les workflows externes situés dans &lt;code&gt;src/Flow/&lt;/code&gt;, en revanche, les importent.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SqliteValidationFlow&lt;/code&gt; génère des tâches planifiées. Son API est volontairement réduite&amp;nbsp;: une &lt;code&gt;FlowFactory&lt;/code&gt; construit un flux à partir d'un générateur de tâches&amp;nbsp;; chaque tâche reçoit un &lt;code&gt;Ip&lt;/code&gt; (paquet d'informations) contenant un &lt;code&gt;SqliteValidationState&lt;/code&gt;&amp;nbsp;; &lt;code&gt;await()&lt;/code&gt; exécute la séquence jusqu'à son terme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/Flow/SqliteValidationFlow.php&lt;/span&gt;
&lt;span class="nv"&gt;$flow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FlowFactory&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'compile_sqlite'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;compileSqlite&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'assemble_sqlite'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assembleSqlite&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'compile_harness'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;compileHarness&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'assemble_harness'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;assembleHarness&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'link'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;linkSmokeExecutable&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;timed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'run'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;runSmokeTest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$state&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nv"&gt;$flow&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;await&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La fonction &lt;code&gt;timed()&lt;/code&gt; est un wrapper PHP classique autour d'une &lt;code&gt;JobInterface&lt;/code&gt;&amp;nbsp;: elle ignore le travail restant si &lt;code&gt;failure&lt;/code&gt; est déjà défini, lance la tâche et stocke le temps écoulé en millisecondes dans &lt;code&gt;$state-&amp;gt;timings&lt;/code&gt;. Les tâches concrètes (&lt;code&gt;CompileSqlite&lt;/code&gt;, &lt;code&gt;AssembleSqlite&lt;/code&gt;, &lt;code&gt;CompileHarness&lt;/code&gt;, &lt;code&gt;AssembleHarness&lt;/code&gt;, &lt;code&gt;LinkSmokeExecutable&lt;/code&gt;, &lt;code&gt;RunSmokeTest&lt;/code&gt;) font appel à &lt;code&gt;Compiler&lt;/code&gt; et &lt;code&gt;Toolchain&lt;/code&gt;. Flow ne reconnaît pas la notion de &lt;code&gt;Token&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Du point de vue de l'utilisateur, il n'y a qu'une seule commande&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nv"&gt;memory_limit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4G bin/console app:compiler-sqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En interne, cela se décompose en étapes indépendantes et significatives partageant &lt;code&gt;SqliteValidationState&lt;/code&gt;&amp;nbsp;: PHP produit &lt;code&gt;sqlite3.s&lt;/code&gt;, &lt;code&gt;as&lt;/code&gt; produit &lt;code&gt;sqlite3.o&lt;/code&gt;, PHP génère l'assembly Harness, &lt;code&gt;as&lt;/code&gt; produit l'objet Harness, l'éditeur de liens produit un exécutable, le processus affiche &lt;code&gt;darkwood&lt;/code&gt;, la validation confirme la réussite. Les flux apparentés (&lt;code&gt;CompileFlow&lt;/code&gt; pour la compilation/l'assemblage/l'édition de liens d'un seul fichier, &lt;code&gt;ProbeRunFlow&lt;/code&gt; pour les tests de base de Clang) appliquent le même principe à plus petite échelle.&lt;/p&gt;

&lt;p&gt;Une correction architecturale a été apportée&amp;nbsp;: une version miniature locale de l’environnement d’exécution Flow, située dans &lt;code&gt;src/Flow/Runtime/&lt;/code&gt;, a été supprimée. L’expérimentation du compilateur doit désormais utiliser le package Composer officiel au lieu de maintenir une copie privée. La séparation finale est la suivante&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sqlite-compiler-php
  ├── src/Compiler/   plain PHP algorithms
  └── src/Flow/       darkwood/flow orchestration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Il est tout aussi important de comprendre ce que Flow n'a &lt;strong&gt;pas&lt;/strong&gt; été conçu pour faire. Il ne remplace pas les nœuds AST, n'implémente pas l'expansion des macros, n'alloue pas de registres, n'émet pas de code ARM64, ne remplace pas Symfony ni la chaîne d'outils du système d'exploitation. Il ne s'agit pas d'une couche de performance et il n'a jamais été conçu pour accélérer la compilation de SQLite. Sa valeur réside dans la structure et la visibilité qu'il offre autour d'une compilation native multi-étapes&amp;nbsp;— une application concrète de Darkwood Flow à un contexte très différent d'une requête web.&lt;/p&gt;

&lt;p&gt;En bref&amp;nbsp;: le compilateur montre ce que PHP natif peut faire&amp;nbsp;; Darkwood Flow transforme ces capacités en une expérience reproductible.&lt;/p&gt;

&lt;h2&gt;
  
  
  La boucle d'itération
&lt;/h2&gt;

&lt;p&gt;Le développement s'est déroulé comme un processus de découverte au-delà de la simple implémentation, et non comme une réécriture unique et inspirée.&lt;/p&gt;

&lt;p&gt;Le modèle est le développement de compilateurs différentiels&amp;nbsp;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;construct probe
  → compile with this compiler
  → compile/run with clang when useful
  → compare observable behavior
  → isolate mismatch
  → reduce fixture
  → inspect parser / sema / codegen
  → modify one narrow behavior
  → run fixture suite
  → run SQLite
  → KEEP only if still valid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L'argument pertinent n'est pas qu'un modèle puisse générer des milliers de lignes de PHP, mais qu'un agent puisse interagir de manière répétée avec du code de compilateur &lt;strong&gt;réel&lt;/strong&gt;, du code &lt;code&gt;as&lt;/code&gt;/&lt;code&gt;clang&lt;/code&gt; &lt;strong&gt;réel&lt;/strong&gt;, des fixtures &lt;strong&gt;réelles&lt;/strong&gt; et une cible d'acceptation &lt;strong&gt;importante&lt;/strong&gt; — pour ensuite ne conserver que les modifications validées.&lt;/p&gt;

&lt;p&gt;La discipline apparaissait encore comme un refus d'inventer du travail en retard, et comme un arrêt lorsque de nouveaux changements n'étaient plus justifiés par des enquêtes infructueuses.&lt;/p&gt;

&lt;h2&gt;
  
  
  La boucle de réveil de cinq minutes
&lt;/h2&gt;

&lt;p&gt;Après des boucles d'ingénierie axées sur la correction à travers la &lt;strong&gt;boucle 48&lt;/strong&gt; (chaîne de retour de structure / &lt;code&gt;054-struct-return-chain&lt;/code&gt;), une boucle de réveil a continué à reprendre un agent toutes les cinq minutes avec des instructions pour rechercher la prochaine amélioration la plus importante.&lt;/p&gt;

&lt;p&gt;Trois termes doivent rester distincts :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Terme&lt;/th&gt;
&lt;th&gt;Signification&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boucle de réveil&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Reprise périodique&amp;nbsp;: analyse, validation, décision quant à l’opportunité de modifications.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Boucle d'ingénierie&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Une entrée KEEP numérotée.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Modification conservée&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Code validé et enregistré&amp;nbsp;: CONSERVER.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Les ticks ne correspondent pas à des modifications de code.&lt;/strong&gt; La boucle de réveil a été interrompue. Entre ces deux événements, une longue période de ticks a révélé que la suite était toujours au vert (46/46, SQLite affichant toujours &lt;code&gt;darkwood&lt;/code&gt;), sans qu'aucune anomalie significative ne justifie un autre KEEP.&lt;/p&gt;

&lt;p&gt;Si la boucle de veille avait continué à inventer des refactorisations sans qu'une sonde ne soit défaillante, cela n'aurait été que du bruit déguisé en progrès. La conclusion intéressante est d'ordre méthodologique&amp;nbsp;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Finalement, la boucle de rétroaction a convergé vers des décisions de maintien du statu quo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Ce que le compilateur prend en charge
&lt;/h2&gt;

&lt;p&gt;Suffisamment de C pour compiler et exécuter le chemin de fumée d'amalgame SQLite 3.46.0 sur macOS ARM64, plus un réseau de régression de 46 fixtures couvrant les bords du préprocesseur, les variables globales, les littéraux composés, les énumérations, les modèles de déversement variadiques, les déclarateurs, les initialiseurs désignés et les cas d'ABI agrégés.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce qu'il ne cherche pas délibérément à être
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ne constitue pas une allégation de conformité totale aux normes C99/C11/C17&lt;/li&gt;
&lt;li&gt;Aucun optimiseur CIR/IR n'est intégré par conception.&lt;/li&gt;
&lt;li&gt;Ne remplace pas Clang/GCC en production&lt;/li&gt;
&lt;li&gt;Un récit de compatibilité avec le SDK Darwin incomplet&lt;/li&gt;
&lt;li&gt;L'ABI à virgule flottante et d'autres écarts plus importants restent en dehors de la barre «&amp;nbsp;SQLite smoke + current fixtures&amp;nbsp;».&lt;/li&gt;
&lt;li&gt;L'IA ne supprime pas la nécessité de tests d'acceptation exécutables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Il est préférable d'utiliser la formulation exacte&amp;nbsp;: &lt;strong&gt;assez du sous-ensemble C utilisé par SQLite et les tests de régression actuels.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Ce que j'ai appris
&lt;/h2&gt;

&lt;p&gt;PHP peut héberger une implémentation de compilateur non triviale utilisant des objets ordinaires, des tableaux, la distribution &lt;code&gt;instanceof&lt;/code&gt;, de l'assembleur construit à partir de chaînes de caractères et &lt;code&gt;proc_open&lt;/code&gt; pour les outils natifs. Un chemin direct lexer → préprocesseur → analyseur syntaxique → sema → ARM64 permet de gérer suffisamment de code C pour compiler l'amalgame de SQLite et exécuter un véritable système de simulation de fumée.&lt;/p&gt;

&lt;p&gt;Les bogues les plus difficiles n'étaient pas dus à un simple point-virgule oublié dans l'émetteur. Il s'agissait d'interactions complexes&amp;nbsp;: espaces de noms PHP vs structure C, équivalence entre tableaux et pointeurs, arbres de déclarateurs, transfert d'ABI agrégé, ordre d'évaluation variadique. SQLite impose ces interactions. Les fixtures les mémorisent.&lt;/p&gt;

&lt;p&gt;Darkwood Flow a mérité sa place en tant que pipeline &lt;strong&gt;externe&lt;/strong&gt;. Il n'avait pas sa place au sein du flux de jetons.&lt;/p&gt;

&lt;p&gt;La boucle de rétroaction tardive a permis de tirer une leçon plus discrète. L'absence de changement persistant après l'analyse prouve que la boucle fonctionne et que l'expérience a atteint un point d'arrêt qu'il convient de respecter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Où je l'emmènerais ensuite
&lt;/h2&gt;

&lt;p&gt;Les prochaines étapes importantes sont plus ambitieuses&amp;nbsp;: une interface utilisateur logicielle (ABI) plus étendue pour les nombres à virgule flottante, une couverture plus large du langage C au-delà du sous-ensemble de type SQLite, et peut-être des stratégies de streaming ou d’émission plus légères. Aucune de ces solutions ne peut être considérée comme un simple «&amp;nbsp;maintien de cinq minutes&amp;nbsp;», et aucune ne devrait être relancée sans une procédure de validation rigoureuse.&lt;/p&gt;

&lt;p&gt;Pour Darkwood, la leçon à retenir est d'ordre architectural&amp;nbsp;: conserver les algorithmes du compilateur en PHP pur&amp;nbsp;; conserver les pipelines opérationnels dans Flow&amp;nbsp;; insister sur le fait que «&amp;nbsp;fonctionne&amp;nbsp;» signifie des fixtures plus un test d'acceptation rigoureux — et non pas simplement quelque chose d'assemblé.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Code source : &lt;a href="https://github.com/matyo91/squlite-compiler-php" rel="noopener noreferrer"&gt;https://github.com/matyo91/squlite-compiler-php&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Slides : &lt;a href="https://github.com/matyo91/slidewire" rel="noopener noreferrer"&gt;https://github.com/matyo91/slidewire&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
  </channel>
</rss>
