{"id":16334930,"url":"https://github.com/ncfavier/pgo","last_synced_at":"2026-05-01T06:34:11.670Z","repository":{"id":66325192,"uuid":"301120178","full_name":"ncfavier/pgo","owner":"ncfavier","description":"Tiny Go compiler for the compilation project at ENS","archived":false,"fork":false,"pushed_at":"2020-10-04T12:09:56.000Z","size":274,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-05-16T09:11:10.980Z","etag":null,"topics":["compiler","golang"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ncfavier.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-04T12:07:57.000Z","updated_at":"2023-01-26T03:44:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"c0275f0e-2b3c-4549-be8f-c2a29b20e98c","html_url":"https://github.com/ncfavier/pgo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ncfavier/pgo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncfavier%2Fpgo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncfavier%2Fpgo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncfavier%2Fpgo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncfavier%2Fpgo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ncfavier","download_url":"https://codeload.github.com/ncfavier/pgo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ncfavier%2Fpgo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32487597,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-30T13:12:12.517Z","status":"online","status_checked_at":"2026-05-01T02:00:05.856Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","golang"],"created_at":"2024-10-10T23:39:38.370Z","updated_at":"2026-05-01T06:34:11.653Z","avatar_url":"https://github.com/ncfavier.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pgo\n\nCe projet est réalisé en Haskell, et dépend des bibliothèques et extensions fournies par le compilateur [GHC](https://www.haskell.org/ghc/).\n\n## Analyse lexico-syntaxique\n\nJ'utilise la bibliothèque [parsec](https://hackage.haskell.org/package/parsec), basée sur les combinateurs de parseurs (*parser combinators*), pour l'analyse lexicale et syntaxique.\n\nLa principale difficulté de cette partie a été l'insertion automatique de point-virgules. Je maintiens une valeur booléenne pendant le parsage, indiquant la présence d'un point-virgule automatique : quand la valeur est à `True`, le seul moyen de parser quoi que ce soit est d'appeler `semicolon` directement.\n\nIl y a sans doute des façons plus élégantes de faire ça, notamment en séparant l'analyse lexicale et l'analyse syntaxique.\n\n## Compilation\n\nJ'ai choisi de faire le typage et la production de code en une seule passe, dans le module `Compile`.\n\nLes arbres de syntaxe abstraite sont définis dans le module `AST`.\n\nLe module `Pack` fournit un type `Pack` permettant de représenter une zone contiguë en mémoire dans laquelle sont stockés des objets, éventuellement nommés.\n\nLe module `X86_64` fournit des fonctions pour la génération de code assembleur.\n\nLa compilation globale a lieu dans la monade `Compiler`, composée des [transformateurs de monades](https://en.wikipedia.org/wiki/Monad_transformer) suivants :\n\n- `Except TypeError` pour les erreurs de typage ;\n- `WriterT String` pour la production de code ;\n- `StateT GlobalState` pour l'état global.\n\nLa compilation des fonctions a lieu dans la monade `FunctionCompiler`, qui rajoute un niveau `StateT FunctionState` par-dessus la monade `Compiler`.\n\nLa structure de donnée utilisée pour les associations (structures, champs, fonctions, variables, etc.) est [`Data.Map`](https://hackage.haskell.org/package/containers-0.6.2.1/docs/Data-Map-Strict.html), qui est implémentée avec des arbres binaires de recherche équilibrés.\n\nLa compilation débute avec `compileFile` et se déroule ainsi, dans les grandes lignes :\n\n- on ajoute les structures dans l'environnement, en deux temps :\n    - d'abord, on ajoute les champs de chaque structure, sans information de taille ; on en profite pour vérifier l'unicité des noms de structures\n    - puis on construit un `Pack` pour les champs chaque structure, récursivement, en gardant une trace explicite de la pile d'appels récursifs afin de détecter les cycles\n- on ajoute les fonctions dans l'environnement :\n    - on vérifie l'unicité des noms\n    - on vérifie que la fonction `main` a la bonne signature\n    - on construit un `Pack` pour les arguments, et un pour les valeurs de retour\n- on compile le point d'entrée du programme C\n- on compile les fonctions : pour chaque fonction,\n    - on ajoute les paramètres de la fonction à la portée initiale\n    - on compile le corps de la fonction\n    - on vérifie que toutes les branches de la fonction ont atteint une instruction `return`, le cas échéant\n- on compile les littéraux de chaîne de caractères\n- on vérifie qu'il y a une fonction `main`\n- on vérifie que `fmt` est utilisé, s'il est importé\n\nLe type de `nil` est représenté par `Pointer Any`, où `Any` est un type fictif égal à n'importe quel type ; c'est une forme ultra-simpliste d'unification où les types sont unifiés par simple comparaison d'égalité.\n\nLe code produit fait usage des [étiquettes locales](https://sourceware.org/binutils/docs/as/Symbol-Names.html#Local-Labels-1).\n\nLa bibliothèque standard du C est utilisée pour l'affichage (`printf` et `putchar`) et pour l'allocation sur le tas (`sbrk`).\n\nLes variables locales sont allouées sur la pile, sauf si elles sont utilisées comme opérande de l'opérateur `\u0026`, auquel cas elles sont allouées sur le tas. Les variables allouées sur le tas sont représentées par un pointeur sur la pile.\n\nToutes les variables sont initialement mises à zéro, puisque c'est la valeur par défaut pour chacun des types de base.\n\nLes booléens sont représentés par 0 (`false`) ou 1 (`true`).\n\nLa comparaison des chaînes de caractères ne nécessite que de comparer les adresses, puisque toute chaîne de caractères est soit la chaîne vide (représentée par 0), soit un pointeur vers un *unique* littéral associé au contenu de la chaîne dans le segment de données.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncfavier%2Fpgo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fncfavier%2Fpgo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fncfavier%2Fpgo/lists"}