780 lines
39 KiB
Text
780 lines
39 KiB
Text
%code requires {
|
|
#include "../Tables/Symboles/table_symboles.h"
|
|
|
|
struct while_t {
|
|
int n_ins_cond;
|
|
int n_ins_jmf;
|
|
};
|
|
}
|
|
|
|
%union {
|
|
int nombre;
|
|
struct symbole_t symbole;
|
|
char id[30];
|
|
char str[300];
|
|
struct while_t my_while;
|
|
}
|
|
%{
|
|
#include "../Tables/Fonctions/tab_fonctions.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "../Tables/Instructions/tab_instruc.h"
|
|
#define TAILLE 1024
|
|
#define SECURISED (1)
|
|
|
|
struct type_t type_courant;
|
|
struct type_t return_type_fonc;
|
|
|
|
// Tableau pour le management des patchs des JMP
|
|
int instructions_ligne_to_patch[10][20];
|
|
int nbs_instructions_to_patch[10];
|
|
|
|
// Utile a l'affectation avec des pointeurs
|
|
int first_etoile = 1;
|
|
|
|
%}
|
|
|
|
// Récupération des tokens
|
|
%token tMAIN
|
|
%token tOBRACKET tCBRACKET
|
|
%token<nombre> tOBRACE tCBRACE
|
|
%token tOCROCH tCCROCH
|
|
%token tINT
|
|
%token tCONST
|
|
%token tPV tCOMA
|
|
%token tMUL tDIV tADD tSUB tEQ
|
|
%token<nombre> tNB tNBEXP
|
|
%token<id> tID
|
|
%token<str> tSTR
|
|
%token tPRINT tGET tSTOP
|
|
%token<nombre> tIF tELSE
|
|
%token<my_while> tWHILE
|
|
%token tRETURN
|
|
%token tLT tGT tEQCOND
|
|
%token tAND tOR
|
|
%token tADDR
|
|
|
|
%left tLT tGT
|
|
%left tEQCOND
|
|
%left tAND tOR
|
|
%left tNOT
|
|
%left tADD tSUB
|
|
%left tMUL tDIV
|
|
|
|
%right tINT tMAIN
|
|
|
|
%type<symbole> SymboleAffectation
|
|
%type<nombre> E EBis Invocation Args ArgSuite Arg SuiteParams Params Get InitTab SuiteInitTab
|
|
|
|
%%
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/*********** Programme C *************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Un programme C correspond a des focntion et un main, une fois que le programme est compilé, on ajoute le STOP et l'on exporte l'assembleur.
|
|
C : Fonctions {add_operation(STOP,0,0,0);
|
|
create_asm();
|
|
};
|
|
|
|
// Le main, renvoi un int, possède le mot clé main, des arguments et un body
|
|
// Dès que le main est reconnu (token main) on met en place le JMP
|
|
Main : tINT tMAIN {create_jump_to_main(get_current_index());
|
|
}
|
|
tOBRACE Args tCBRACE Body;
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Fonctions **************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Des fonctions sont une suite de fonctions (possiblement nulle)
|
|
Fonctions : Main ;
|
|
Fonctions : Fonction Fonctions ;
|
|
|
|
// Une fonction possède un Type , un identifiant
|
|
Fonction : Type tID {return_type_fonc = type_courant; // On récupère le ype de la fonction
|
|
}
|
|
tOBRACE {inc_prof(); // On incrémente la profondeur pour les arguments, ils font parti de la fonction
|
|
}
|
|
Args {decrement_prof(); // Quand les arguments sont passés, on peur décrémenter la profondeur (sans effacer les variables)
|
|
push_fonction($2,return_type_fonc,get_current_index(), $6); // On enregistre la fonction dans la table des fonctions
|
|
}
|
|
tCBRACE Body {add_operation(RET,0,0,0); // On ajoute le RET
|
|
};
|
|
|
|
// Get, une fonction particulière -> renvoi l'adresse de la valeur getée
|
|
Get : tGET tOBRACE tCBRACE {int addr = push("0_TEMPORARY", 0, integer); // On déclare la var temporelle
|
|
add_operation(GET,addr,0,0); // On ajoute le GET
|
|
$$ = addr; // On renvoi l'adresse
|
|
};
|
|
|
|
// Print, une fonction particulière
|
|
Print : tPRINT tOBRACE E tCBRACE {add_operation(PRI,$3,0,0); // On ajoute l'instruction PRI
|
|
pop(); // On supprime la variable temporaire
|
|
};
|
|
|
|
// Print, une fonction particulière
|
|
Print : tPRINT tOBRACE tSTR tCBRACE {int i = 0;
|
|
int decalage = 0;
|
|
char previous = 'a';
|
|
while ($3[i] != '\0') {
|
|
if (previous == '\\' && $3[i] == 'n') {
|
|
$3[i - decalage - 1] = '\n';
|
|
previous = 'a';
|
|
decalage++;
|
|
} else if (previous == '\\' && $3[i] == '0') {
|
|
$3[i - decalage - 1] = '\0';
|
|
previous = 'a';
|
|
decalage++;
|
|
} else {
|
|
$3[i-decalage] = $3[i];
|
|
previous = $3[i];
|
|
}
|
|
i++;
|
|
}
|
|
$3[i-decalage] = $3[i];
|
|
i=0;
|
|
int termine = $3[i+1] == '"';
|
|
int addr = push("0_TEMPORARY", 0, integer);
|
|
while (!termine) {
|
|
if ($3[i+1] != '"') {
|
|
add_operation(AFC, addr + i, $3[i+1], 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(AFC, addr + i, $3[i+1], 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(AFC, addr + i, $3[i+1], 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(AFC, addr + i, $3[i+1], 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
|
|
i = i - 3;
|
|
termine = 0;
|
|
if ($3[i+1] != '"') {
|
|
add_operation(PRIC, addr + i, 0, 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(PRIC, addr + i, 0, 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(PRIC, addr + i, 0, 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
if (!termine && $3[i+1] != '"') {
|
|
add_operation(PRIC, addr + i, 0, 0);
|
|
} else {
|
|
termine = 1;
|
|
}
|
|
i++;
|
|
}
|
|
pop(); // On supprime la variable temporaire
|
|
};
|
|
|
|
// Stop, une fonction particulière
|
|
Stop : tSTOP tOBRACE tNB tCBRACE {add_operation(STOP,$3,0,0); // On ajoute juste l'instruction stop
|
|
};
|
|
|
|
// Return, etape clé d'une fonction
|
|
Return : tRETURN E tPV {add_operation(COP,0,$2,0); // On copie la valeur retournée à l'adresse 0 de la frame
|
|
pop(); // On pop la variable temporaire
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Arguments **************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Les arguments : Args, Arg, ArgSuite renvoient la taille dans la pile des arguments déjà reconnus
|
|
// Des argmuments correspondent à : un argument, puis la suite d'arguments
|
|
Args : Arg ArgSuite {$$ = $1 + $2; // La taille des arguments est la taille du premier argument plus celle des suivants
|
|
};
|
|
Args : {$$ = 0; // Il peut ne pas y avoir d'arguments, alors la taille est 0
|
|
};
|
|
// Un argument possède un type et un identifiant (nom)
|
|
Arg : Type tID {type_courant.nb_blocs = 1;
|
|
int addr = push($2,1, type_courant); // On stocke l'argument dans la pile des symboles
|
|
if (type_courant.pointeur_level > 0) {
|
|
$$ = taille_types[ADDR];
|
|
} else {
|
|
$$ = taille_types[type_courant.base];
|
|
}
|
|
};
|
|
// Un argument peut aussi être un tableau (argument classique et crochets) il est considéré comme un pointeur
|
|
Arg : Type tID tOCROCH tCCROCH {type_courant.nb_blocs = 1;
|
|
type_courant.pointeur_level++; // Considéré comme un simple pointeur
|
|
int addr = push($2,1, type_courant);
|
|
$$ = taille_types[ADDR];
|
|
};
|
|
// La suite d'un argument, une virgule, un argument, et d'autres arguments
|
|
ArgSuite : tCOMA Arg ArgSuite {$$ = $2 + $3;
|
|
};
|
|
// Cela peut être aucun arguments
|
|
ArgSuite : {$$ = 0;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/*************** Body ****************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Un body n'est rien d'autre qu'une suite d'instructions entre deux accolades
|
|
Body : tOBRACKET {inc_prof(); // Lors de l'ouverture de l'accolade la profondeur augmente
|
|
}
|
|
Instructions tCBRACKET {reset_prof(); // A la sortie d'un body, on détruit toutes les variables locales de ce body
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/*********** Instructions ************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Des instructions sont une instruction suivie d'autres instructions, ou, rien
|
|
Instructions : Instruction Instructions ;
|
|
Instructions : ;
|
|
|
|
// Un instruction peut être : une affectation, une déclaration, une invocation, un if, un while, un return, une fonction particulière
|
|
Instruction : Aff;
|
|
Instruction : Decl;
|
|
Instruction : Invocation tPV {pop();};
|
|
Instruction : If;
|
|
Instruction : While;
|
|
Instruction : Return;
|
|
Instruction : Stop tPV;
|
|
Instruction : Print tPV;
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Invocation *************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
Invocation : tID tOBRACE {if (!SECURISED) {
|
|
push("0_TEMPORARY_CTX", 0, integer); // On reserve la place du contexte
|
|
push("0_TEMPORARY_ADDR_RT", 0, pointer); // On reserve la place de l'adresse de retour
|
|
}
|
|
}
|
|
Params tCBRACE {struct fonction_t fonc = get_fonction($1); // On récupère la fonction
|
|
if (!SECURISED) {
|
|
multiple_pop($4 + 2); // On pop les paramètres de la table des symboles
|
|
} else {
|
|
multiple_pop($4); // On pop les paramètres de la table des symboles
|
|
}
|
|
add_operation(CALL,fonc.first_instruction_line, get_last_addr(),0); // On écrit le CALL
|
|
// On renvoi l'adresse de la valeur retour de la fonction
|
|
if (fonc.return_type.pointeur_level > 0 || fonc.return_type.isTab) {
|
|
$$ = push("0_TEMPORARY_RETURN", 0, pointer);
|
|
} else {
|
|
$$ = push("0_TEMPORARY_RETURN", 0, fonc.return_type);
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Paramètres *************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Ici aussi, 0, 1 ou plusieurs paramètres avec une suite paramètre pour prendre en compte la virgule, on renvoi le nombre de paramètres
|
|
Params : {$$ = 0;
|
|
};
|
|
Params : Param SuiteParams {$$ = $2 + 1;
|
|
};
|
|
Param : E
|
|
SuiteParams : tCOMA Param SuiteParams {$$ = $3 + 1;};
|
|
SuiteParams : {$$ = 0;};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/******** Sauts conditionnels ********/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Un if : le token, une expression entre parenthèse suivie d'un body et d'un else
|
|
If : tIF tOBRACE E tCBRACE {add_operation(JMF,$3,0,0); // On ajoute le JMF sans préciser la ligne du saut
|
|
$1 = get_current_index() - 1; // On stocke le numéro d'instruction à patcher
|
|
}
|
|
Body {int current = get_current_index(); // On récupère le numéro d'instrcution
|
|
patch($1,current + 1); // On patch le Jump en cas d'instruction fausse
|
|
add_operation(JMP,0,0,0); // JMP pour skip le else si on devait faire le body
|
|
instructions_ligne_to_patch[get_prof()][nbs_instructions_to_patch[get_prof()]] = current; // On spécifie que le JMP est a patcher
|
|
nbs_instructions_to_patch[get_prof()]++;
|
|
pop(); // On pop la condition du if
|
|
}
|
|
Else
|
|
|
|
// Elsif
|
|
Else : tELSE If;
|
|
|
|
// Else
|
|
Else : tELSE Body {int current = get_current_index();
|
|
for (int i = 0; i< nbs_instructions_to_patch[get_prof()]; i++) {
|
|
patch(instructions_ligne_to_patch[get_prof()][i],current); // On patch après le else
|
|
}
|
|
nbs_instructions_to_patch[get_prof()] = 0;
|
|
};
|
|
|
|
// If sans else
|
|
Else : {int current = get_current_index();
|
|
for (int i = 0; i< nbs_instructions_to_patch[get_prof()]; i++){
|
|
patch(instructions_ligne_to_patch[get_prof()][i],current); // On patch après le else
|
|
}
|
|
nbs_instructions_to_patch[get_prof()] = 0;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************** Boucles **************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
While : tWHILE {$1.n_ins_cond = get_current_index(); // On enregistre l'endroit de la condition (pour le JMP en fin de while)
|
|
}
|
|
|
|
tOBRACE E tCBRACE {add_operation(JMF,$4,0,0); // Ecriture du JMF
|
|
$1.n_ins_jmf = get_current_index() - 1; // Enregistrement du numero d'instruction du jmf à patch
|
|
pop(); // Pop de la condition
|
|
}
|
|
Body {int current = get_current_index(); // Patch du JMF apres le body
|
|
patch($1.n_ins_jmf,current + 1);
|
|
add_operation(JMP,$1.n_ins_cond,0,0); // JMP au debut de la boucle
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Affectations ***********/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Affectation simple
|
|
Aff : tID tEQ E tPV {struct symbole_t * symbole = get_variable($1);
|
|
symbole->initialized = 1;
|
|
if (symbole->type.isConst == 1 && symbole->type.pointeur_level == 0 || symbole->type.isTab) {
|
|
printf("\033[31;01m ERROR : \033[00m %s est READ-ONLY\n", symbole->nom);
|
|
exit(2);
|
|
} else {
|
|
add_operation(COP,symbole->adresse,$3,0); // On affecte la valeur
|
|
pop(); // On pop l'expression
|
|
first_etoile = 1; // On reinitialise first_etoile
|
|
}
|
|
};
|
|
|
|
// Affectation sur un pointeur
|
|
Aff : SymboleAffectation tEQ E tPV {if ($1.type.isConst == 1 && $1.type.pointeur_level == 0 || $1.type.isTab) {
|
|
printf("\033[31;01m ERROR : \033[00m %s ou un de ses déréférencement est READ-ONLY\n", $1.nom);
|
|
exit(2);
|
|
} else {
|
|
add_operation(WR,$1.adresse,$3,0); // On affecte la valeur
|
|
pop(); // On pop l'expression
|
|
pop(); // On pop la variable temporaire de l'adresse
|
|
}
|
|
};
|
|
|
|
// Debut d'une affectation avec déreférencement de pointeur
|
|
SymboleAffectation : tID {struct symbole_t * symbole = get_variable($1);
|
|
symbole->initialized = 1;
|
|
int addr = push("0_TEMPORARY", 1, pointer);
|
|
if (symbole->type.isTab) {
|
|
add_operation(AFCA, addr, symbole->adresse,0); // Si tableau AFCA
|
|
} else {
|
|
add_operation(COP, addr, symbole->adresse,0); // Si pointeur COP
|
|
}
|
|
struct symbole_t symbolebis = *symbole;
|
|
symbolebis.adresse = addr;
|
|
$$ = symbolebis; // On renvoi un symbole pointant sur la copie de l'adresse
|
|
};
|
|
|
|
SymboleAffectation : SymboleAffectation tOCROCH E tCCROCH {if ($1.type.pointeur_level == 0) { // Check déréférençable
|
|
printf("\033[35;01m WARNING : \033[00m déréférencement exessif\n");
|
|
} else {
|
|
$1.type.pointeur_level--; // On baisse le niveau de pointeur
|
|
int addr = push("0_TEMPORARY", 1, integer); // On alloue la place pour stocker la taille du type pointé
|
|
if ($1.type.pointeur_level > 0) {
|
|
add_operation(AFC, addr, taille_types[ADDR],0); // Si on est encore un pointeur, la taille d'un adresse
|
|
} else {
|
|
add_operation(AFC, addr, taille_types[$1.type.base],0); // Sinon le type de base
|
|
}
|
|
add_operation(MUL,$3,addr,$3); // On multiple le nombre de décalage par la taille du type
|
|
add_operation(ADD,$1.adresse,$1.adresse,$3); // On l'ajoute a l'adresse de base
|
|
$1.type.isTab = 0;
|
|
$$=$1;
|
|
pop();
|
|
pop();
|
|
}
|
|
};
|
|
|
|
SymboleAffectation : tMUL SymboleAffectation {if ($2.type.pointeur_level == 0) { // Check déréférençable
|
|
printf("\033[35;01m WARNING : \033[00m déréférencement exessif\n");
|
|
} else {
|
|
$2.type.pointeur_level--; // On baisse le niveau de pointeur
|
|
$2.type.isTab = 0;
|
|
if (first_etoile) {
|
|
first_etoile = 0; // Le premier déréférencement doit être skip a cause du WR
|
|
} else {
|
|
add_operation(READ, $2.adresse, $2.adresse,0); //
|
|
$$=$2;
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/***** Expressions Arithmetiques *****/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Pour une expression arithmétique, nous renvoyons toujours l'adresse du resultat
|
|
|
|
// Un simple nombre
|
|
E : tNB {int addr = push("0_TEMPORARY", 1, integer); // On reserve la place de la variable temporaire
|
|
add_operation(AFC, addr,$1,0); // On Affecte la valeur a cette adresse
|
|
$$ = addr; // On renvoi l'adresse
|
|
};
|
|
|
|
// Un nombre sous forme XeY, même traitement qu'un nombre classique
|
|
E : tNBEXP {int addr = push("0_TEMPORARY", 1, integer);
|
|
add_operation(AFC, addr,$1,0);
|
|
$$ = addr;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Une Multiplication
|
|
E : E tMUL E {add_operation(MUL,$1,$1,$3); // On Multiplie les valeurs et stockons le résultat dans la première variable temporaire
|
|
$$ = $1; // On renvoi l'adresse du resultat
|
|
pop(); // On libère la seconde variable temporaire
|
|
};
|
|
|
|
// Une Division (idem multiplication)
|
|
E : E tDIV E {add_operation(DIV, $1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
// Une Soustraction (idem multiplication)
|
|
E : E tSUB E {add_operation(SOU,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
// Une Addition (idem multiplication)
|
|
E : E tADD E {add_operation(ADD,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Une invocation
|
|
E : Invocation {$$ = $1; // Une invocation renvoi déjà l'adresse, cette règle n'est qu'un cast d'Invocation en E
|
|
};
|
|
|
|
// Consomation de parenthèses
|
|
E : tOBRACE E tCBRACE {$$ = $2; // Cela permet de garantir la prioricité des expressions entre parenthèse
|
|
};
|
|
|
|
// Négatif --> -E <=> 0-E
|
|
E : tSUB E {int addr = push("0_TEMPORARY", 1, integer); // On réserve la variable temporaire pour le 0
|
|
add_operation(AFC, addr,0,0); // On affecte le 0
|
|
add_operation(SOU, $2, addr, $2); // On applique le 0-E
|
|
$$ = $2; // On renvoi l'adresse
|
|
pop(); // On libère la mémoire temporaire utilisée par 0
|
|
};
|
|
|
|
|
|
|
|
|
|
// Opérateur == (idem multiplication)
|
|
E : E tEQCOND E {add_operation(EQU,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
// Opérateur > (idem multiplication)
|
|
E : E tGT E {add_operation(SUP,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
// Opérateur < (idem multiplication)
|
|
E : E tLT E {add_operation(INF,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
// Opérateur !E <=> E==0
|
|
E : tNOT E {int addr = push("0_TEMPORARY", 1, integer); // On réserve la variable temporaire pour le 0
|
|
add_operation(AFC, addr,0,0); // On affecte le 0
|
|
add_operation(EQU, $2, addr, $2); // On applique le 0==E
|
|
$$ = $2; // On renvoi l'adresse
|
|
pop();
|
|
};
|
|
|
|
// Opérateur E && E' <=> E*E' (idem multiplication)
|
|
E : E tAND E {add_operation(MUL,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
// Opérateur E || E' <=> E+E' (idem multiplication)
|
|
E : E tOR E {add_operation(ADD,$1,$1,$3);
|
|
$$ = $1;
|
|
pop();
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Déréférencement de pointeur
|
|
E : tMUL E {add_operation(READ, $2, $2, 0); // Extraction en mémoire
|
|
$$=$2;
|
|
};
|
|
|
|
|
|
|
|
// Une variable
|
|
E : tID {struct symbole_t * symbole = get_variable($1); // On cherche la variable dans la table des symboles
|
|
struct type_t type = symbole->type; // On récupère le type
|
|
type.nb_blocs = 1;
|
|
int addr = push("0_TEMPORARY", 1, type); // On créé la variable temporaire
|
|
if (symbole->type.isTab == 1) {
|
|
add_operation(AFCA, addr,symbole->adresse,0); // Si c'est un tableau on affecte l'adresse du début
|
|
} else {
|
|
add_operation(COP, addr,symbole->adresse,0); // Si c'est autre chose, on copie la valeur
|
|
}
|
|
$$ = addr;
|
|
};
|
|
|
|
// Une variable sous forme de tableau
|
|
E : tID tOCROCH E tCCROCH {struct symbole_t * symbole = get_variable($1); // On récupère le symbole
|
|
struct type_t type = symbole->type; // On récupère le type
|
|
type.nb_blocs = 1;
|
|
int addr = push("0_TEMPORARY", 1, type); // On créé la variable temporaire
|
|
if (type.isTab) {
|
|
add_operation(AFCA, addr,symbole->adresse,0);
|
|
} else {
|
|
add_operation(COP, addr,symbole->adresse,0);
|
|
}
|
|
int addr2 = push("0_TEMPORARY", 1, integer);
|
|
add_operation(AFC, addr2, taille_types[symbole->type.base],0);
|
|
add_operation(MUL,$3,addr2,$3);
|
|
add_operation(ADD,$3,addr,$3);
|
|
add_operation(READ,$3,$3,0);
|
|
$$=$3;
|
|
pop();
|
|
pop();
|
|
};
|
|
|
|
E : tADDR EBis {$$=$2;};
|
|
E : Get {$$ = $1;};
|
|
|
|
EBis : tID tOCROCH E tCCROCH {struct symbole_t * symbole = get_variable($1);
|
|
struct type_t type = symbole->type;
|
|
type.nb_blocs = 1;
|
|
int addr = push("0_TEMPORARY", 1, type);
|
|
if(type.isTab) {
|
|
add_operation(AFCA, addr,symbole->adresse,0);
|
|
} else {
|
|
add_operation(COP, addr,symbole->adresse,0);
|
|
}
|
|
int addr2 = push("0_TEMPORARY", 1, integer);
|
|
add_operation(AFC, addr2, taille_types[symbole->type.base],0);
|
|
add_operation(MUL,$3,addr2,$3);
|
|
add_operation(ADD,$3,addr,$3);
|
|
$$=$3;
|
|
pop();
|
|
pop();
|
|
};
|
|
|
|
|
|
EBis : tID { struct symbole_t * symbole = get_variable($1); struct type_t type = symbole->type; type.nb_blocs = 1; int addr = push("0_TEMPORARY", 1, type); add_operation(AFCA, addr,symbole->adresse,0); $$=addr;};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/*************** Types ***************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Type INT
|
|
Type : tINT {type_courant.base = INT;
|
|
type_courant.pointeur_level = 0;
|
|
type_courant.isConst = 0;
|
|
};
|
|
|
|
// Type pointeur
|
|
Type : Type tMUL {type_courant.pointeur_level++; // On ajoute un niveau de pointeur
|
|
};
|
|
|
|
// Constante
|
|
Type : tCONST Type {type_courant.isConst = 1;
|
|
};
|
|
|
|
|
|
|
|
|
|
/*
|
|
Type : tINT TypeNext
|
|
Type : tCONST tINT TypeNext
|
|
|
|
TypeNext :
|
|
| tMUL TypeNext
|
|
*/
|
|
|
|
|
|
|
|
/*************************************/
|
|
/*************************************/
|
|
/************ Déclaration ************/
|
|
/*************************************/
|
|
/*************************************/
|
|
|
|
// Une déclaration est un type, un identifiant eventuellement initialisé, et fin de déclaration (une autre ou un ;);
|
|
Decl : Type UneDecl FinDecl ;
|
|
|
|
// Une déclaration d'une simple variable sans initialisation
|
|
UneDecl : tID {type_courant.isTab = 0; // On est pas un tableau
|
|
type_courant.nb_blocs = 1; // On fixe le nombre de blocs
|
|
push($1, 0, type_courant);
|
|
};
|
|
|
|
// Une déclaration d'une simple variable avec initialisation
|
|
UneDecl : tID tEQ E {pop(); // On pop l'expression
|
|
type_courant.isTab = 0; // On est pas un tableau
|
|
type_courant.nb_blocs = 1; // On fixe le nombre de blocs
|
|
int addr = push($1,1, type_courant); // On déclare la variable qui a la même adresse que la variable temporaire, et, a donc déjà la valeur
|
|
};
|
|
|
|
// Une déclaration d'un tableau sans initialisation
|
|
UneDecl : tID tOCROCH tNB tCCROCH {type_courant.isTab = 1; // On est un tableau
|
|
type_courant.pointeur_level++; // On augmente le niveau de pointeur (un tableau est un pointeur)
|
|
type_courant.nb_blocs = $3; // On fixe le nombre de blocs
|
|
push($1, 0, type_courant);
|
|
};
|
|
|
|
// Une déclaration d'un tableau avec initialisation
|
|
UneDecl : tID tOCROCH tNB tCCROCH tEQ tOBRACKET InitTab tCBRACKET {if ($3 != $7) {
|
|
printf("\033[31;01m ERROR : \033[00m Initialisation de %s : %d éléments donnés, %d éléments requis\n", $1, $7, $3);
|
|
exit(2);
|
|
} else {
|
|
type_courant.isTab = 1;
|
|
type_courant.pointeur_level++; // On augmente le niveau de pointeur (un tableau est un pointeur)
|
|
type_courant.nb_blocs = $3;
|
|
int i;
|
|
for (i=0;i<$3;i++) {
|
|
pop();
|
|
}
|
|
push($1, 1, type_courant);
|
|
}
|
|
};
|
|
|
|
// Un ; ou une autre déclaration
|
|
FinDecl : tPV;
|
|
FinDecl : tCOMA UneDecl FinDecl ;
|
|
|
|
// Initialisation des tableau
|
|
InitTab : E SuiteInitTab {$$ = $2 + 1;
|
|
};
|
|
SuiteInitTab : tCOMA E SuiteInitTab {$$ = $3 + 1;
|
|
};
|
|
SuiteInitTab : {$$ = 0;
|
|
};
|
|
|
|
|
|
|
|
%%
|
|
void main(void) {
|
|
init();
|
|
yyparse();
|
|
}
|