Hexanôme : 4221
Membres :
- NGO Truong Son
- SCHLEE Adam
- FAKRONI Mohamed
- SUN Jixiang
- VU Thi Tho
- HUYNH Huu Thanh Tu
- FORERO GUTIERREZ Santiago
- CARVAJAL Matéo
Ce projet implémente un compilateur capable de traduire un sous-ensemble significatif du langage C en code assembleur pour deux architectures (x86-64, ARM64). Le compilateur gère un large éventail de fonctionnalités du C, de la gestion des types de base aux structures de contrôle complexes, en passant par l'analyse statique pour assurer la robustesse du code généré. Le processus de compilation s'appuie sur une Représentation Intermédiaire (IR) pour faciliter l'optimisation et le reciblage.
Notre compilateur prend en charge les caractéristiques suivantes du langage C :
- Types de base :
int(entier signé 32 bits)float(flottant double précision)char(caractère)void(principalement comme type de retour de fonction)
- Conversions implicites : Gestion des conversions automatiques entre les types numériques (par exemple,
intversfloat). - Constantes :
- Entières (ex :
123,-5) - Caractères (ex :
'a','\n')
- Entières (ex :
- Déclaration : Variables locales et globales. Possibilité de déclarer des variables n'importe où dans un bloc (style C++ / C99).
- Initialisation : Possibilité d'initialiser une variable lors de sa déclaration (ex :
int count = 0;). - Portée (Scope) : Gestion correcte de la portée des variables grâce aux blocs
{ ... }. - Masquage (Shadowing) : Support du masquage de variables (une variable locale peut masquer une variable globale ou d'un bloc englobant).
- Affectation : Opérateur d'affectation simple (
=) et opérateurs d'affectation composée (+=,-=etc.). L'affectation est une expression qui retourne une valeur.
- Arithmétiques : Addition (
+), Soustraction (-), Multiplication (*). - Comparaison : Égalité (
==), Différence (!=), Inférieur (<), Supérieur (>). - Logiques (évaluation paresseuse) : OU logique (
||), ET logique (&&). - Logiques bit-à-bit : OU (
|), ET (&), OU exclusif (^). - Unaires : Négation logique (
!), Moins unaire (-). - Incrémentation / Décrémentation : Préfixe et postfixe (
++var,var++,--var,var--).
- Conditionnelles :
if,else. - Boucles :
while,for. - Blocs : Utilisation de
{ ... }pour délimiter les blocs d'instructions et les portées.
- Définition : Définition de fonctions avec paramètres typés.
- Types de retour : Support des types de retour
intetvoid. - Appel : Appels de fonctions avec passage de paramètres.
- Retour : Instruction
returnpermettant de retourner une valeur (pour les fonctionsint) ou de terminer l'exécution (pourvoid). Lereturn expression;peut apparaître n'importe où dans le corps de la fonction.
- Tableaux : Support des tableaux à une dimension.
- Chaînes de caractères : Représentées classiquement comme des tableaux de
char(char[]). - Structures : Définition et utilisation de
struct.
- Cohérence des appels de fonction : Vérification du nombre et (potentiellement) du type des paramètres lors des appels.
- Gestion des déclarations :
- Vérification qu'une variable utilisée a bien été déclarée au préalable.
- Vérification qu'une variable n'est pas déclarée plusieurs fois dans la même portée.
- Utilisation des variables : Vérification qu'une variable déclarée est effectivement utilisée dans le code (aide à détecter le code mort ou les erreurs).
- Fichier unique : Le compilateur traite un seul fichier source
.c. - Commentaires : Les commentaires C sont correctement ignorés.
- Représentation Intermédiaire (IR) : Le code source est traduit en une IR avant la génération du code final.
- Génération de code :
- Production de code assembleur.
- Reciblage vers plusieurs architectures : x86-64, ARM64.
Le code source est organisé de manière modulaire pour une meilleure maintenabilité :
CodeGenVisitor.cpp/CodeGenVisitor.h: Responsable de la traversée de l'AST (Arbre Syntaxique Abstrait) et de la génération de la Représentation Intermédiaire ou du code assembleur final. Contient la logique de traduction des différentes constructions du langage.SymbolTable.cpp/SymbolTable.h: Implémente la table des symboles pour gérer les informations sur les variables (type, portée, adresse mémoire/registre).main.cpp: Point d'entrée du programme. Gère les arguments de la ligne de commande, lance l'analyse lexicale/syntaxique et initie le processus de compilation (visite de l'AST).
Les tâches ont été définies et réparties entre les membres de l'équipe, en utilisant un tableau collaboratif pour suivre l'avancement.
Première étape :
Etablir votre propre compiler/config.mk. Voici un exemple :
ANTLRJAR=/home/$(USER)/antlr4-install/antlr-4.13.2-complete.jar
ANTLRINC=/home/$(USER)/antlr4-install/include/antlr4-runtime/
ANTLRLIB=/home/$(USER)/antlr4-install/lib/libantlr4-runtime.a
ANTLR=java -jar $(ANTLRJAR)Utilisation de make pour compiler le projet :
cd compiler/
makePour compiler un fichier source :
./ifcc fichier.c -o fichier.sPour assembler et exécuter le programme généré :
gcc fichier.s -o fichier.out
./fichier.outPour afficher les valeurs retourné dans le shell :
echo $?Pour lancer les tests :
python3 ifcc-test.py testfiles/!!! Important : Pour le test 43 43_getchar, il faut rentrer 2 caractères car il y a deux getchar() (un pour gcc et un pour ifcc)