%{ #include "y.tab.h" #include "table_sym.h" #include "reloc.h" #include "asm_defs.h" #include #include #include symbolStack tableSym = NULL; // Table de symboles initialement vide extern int yylineno; // Bidouille pour avoir le numero de ligne du lexer ^^ int SP = 0; // StackPointer int contextProf = 0; // Profondeur de contexte int tempCount = 0; // Compteur pour génerer des noms de temporaires uniques int structCount = 0; // Compteur pour génerer des noms de labels pour les structures unique int yylex(); void yyerror(char *s); void warning(char *msg); struct symbolEntry * addSym(char *varName, int contextProf, int readOnly); void genCode(int opcode, int op1, int op2, int op3); void genCodeJump(int opcode, int op1, int op2, int op3, char *targetLabel); void genLabel(char *lbl, char *prefix, int id); %} %token ERROR %token IF %token ELSE %token WHILE %token DO %token MAIN %token CONST %token INT %token PRINTF %left FOIS DIV %left '+' '-' %left '>' '<' %left EGALE DIFFERENT /* TODO : if contractés : ?: */ %token AFF /* TODO : += -= *= /= */ %token IDENTIFICATEUR %token ENTIER %type InitVarLoc %type DeclVarLoc1 %type DeclConst1 %type Symbole %type Constante %type LValue %type RValue /* %type BeginIfWithoutElse */ %type BeginIf %type BeginWhile %type BeginDoWhile %union { int nb; char *str; struct symbolEntry *sym; } %start Prog %% Prog: MAIN Block { /* printSymTable(tableSym);*/ } Block: '{' { contextProf++; } Declarations Instructions '}' { /* printf("Block\n");*/ /*printSymTable(tableSym);*/ cleanSymStack(&tableSym, --contextProf); } BlockOuInstr: Block | Instruction Declarations: /*vide*/ { printf("Declaration vide\n"); } | Decl ';' Declarations Decl: INT DeclVarLocList { /*printf("Decl\n");*/ } | CONST INT DeclConstList | error /* TODO : essayer de perdre moins d'informations */ /*********************** ** Liste de variables ** ***********************/ DeclVarLocList: DeclVarLoc { /* printf("DeclVarLoc\n");*/ } | DeclVarLoc ',' DeclVarLocList DeclVarLoc: DeclVarLoc1 { /*printf("Variable non initalisee : '%s'\n", $1->symName);*/ } | DeclVarLoc1 InitVarLoc { //printf("Variable initalisee '%s' à %i\n", $1->symName, $2); if ( $1 == NULL ) { yyerror("Symbol already declared"); YYERROR; } else { genCode(I_AFC, $1->address, $2, PAD); $1->initialized = 1; // oui (et pas peut-être, car nouveau profondeur) } } DeclVarLoc1: IDENTIFICATEUR { $$ = addSym($1, contextProf, 0); } InitVarLoc: AFF ENTIER { $$=$2; /*printf("Init à la valeur %i\n", $2);*/ } /************************ ** Liste de constantes ** ************************/ DeclConstList: DeclConst | DeclConst ',' DeclConstList DeclConst: DeclConst1 AFF ENTIER { if ( $1 == NULL ) { yyerror("Symbol already declared"); YYERROR; } else { genCode(I_AFC, $1->address, $3, PAD); $1->initialized = 1; // oui (et pas peut-être, car nouveau profondeur) } } DeclConst1: IDENTIFICATEUR { $$ = addSym($1, contextProf, 1); } /***************** ** Instructions ** *****************/ Instructions: /* Vide */ | Instruction Instructions /* TODO : ajouter gestion d'erreur */ Instruction: PRINTF '(' RValue ')' ';' { if ( $3->initialized == 0) // non { yyerror("Symbol uninitialized"); YYERROR; } else { if ( $3->initialized == 2 ) // peut-etre { warning("Symbol may be uninitialized"); } genCode(I_PRI, $3->address, PAD, PAD); } } | LValue AFF RValue ';' { genCode(I_COP, $1->address, $3->address, PAD); if ( contextProf > 0 ) { $1->initialized=2; // TODO peut-être (gestion très limitée car nécessiterai un arbre de contextes numerotés au minimum pour être plus fin) } else { $1->initialized=1; // oui (on est dans le main) } } | BeginIf Block/*OuInstr*/ { // TODO : comprendre pourquoi ça génère un décalage/réduction char lbl[MAX_LABEL_LEN]; genLabel(lbl, "if1_",$1); writeLabel(lbl); } | BeginIf Block/*OuInstr*/ ELSE { char lbl[MAX_LABEL_LEN]; genLabel(lbl, "if2_", $1); genCodeJump(I_JMP, UNK, PAD, PAD, lbl); genLabel(lbl, "if1_", $1); writeLabel(lbl); } BlockOuInstr { char lbl[MAX_LABEL_LEN]; genLabel(lbl,"if2_",$1); writeLabel(lbl); } | BeginWhile BlockOuInstr { char lbl[MAX_LABEL_LEN]; genLabel(lbl, "wh1_", $1); genCodeJump(I_JMP, UNK, PAD, PAD, lbl); genLabel(lbl, "wh2_", $1); writeLabel(lbl); } | BeginDoWhile BlockOuInstr WHILE '(' RValue ')' ';' { char lbl1[MAX_LABEL_LEN], lbl2[MAX_LABEL_LEN]; genLabel(lbl1, "do1_", $1); genLabel(lbl2, "do2_", $1); genCodeJump(I_JMF, $5->address, PAD, PAD, lbl2); genCodeJump(I_JMP, UNK, PAD, PAD, lbl1); writeLabel(lbl2); } BeginIf: IF '(' RValue ')' { char lbl[MAX_LABEL_LEN]; $$=structCount++; genLabel(lbl, "if1_", $$); genCodeJump(I_JMF, $3->address, UNK, PAD, lbl); } BeginWhile: WHILE '(' RValue ')' { char lbl[MAX_LABEL_LEN]; $$=structCount++; genLabel(lbl, "wh1_", $$); writeLabel(lbl); genLabel(lbl, "wh2_", $$); genCodeJump(I_JMF, $3->address, UNK, PAD, lbl); } BeginDoWhile: DO { char lbl[MAX_LABEL_LEN]; $$=structCount++; genLabel(lbl, "do1_", $$); writeLabel(lbl); } Symbole: IDENTIFICATEUR { $$=symbolFind(tableSym, $1, contextProf, contextProf); if ( $$==NULL ) { yyerror("Symbol not declared"); YYERROR; } } LValue: Symbole { if ( $1->readOnly ) { $$=NULL; yyerror("Not a valid LValue : is read-only"); YYERROR; } else { $$=$1; } } RValue: Constante { $$=$1; } | Symbole { //TODO : expression complete et pas symbole (qui retourne addresse ou symbole ?) $$=$1; } Constante: ENTIER { char tempoName[MAX_LABEL_LEN]; sprintf(tempoName, "!tempo%d", tempCount++); // TODO : si tempo trop long, bug $$ = addSym(tempoName, contextProf, 1); if ( $$ == NULL ) { yyerror("Error while declaring a temp variable"); YYERROR; } else { $$->initialized=1; genCode(I_AFC, $$->address, $1, PAD); } } %% void yyerror(char *s) { //fprintf(stderr, "Syntax Error : '%s' at l%d,c%d-l%d,c%d\n", s, @$.first_column, @$.last_line, @$.last_column); // Nécessite l'option %locations et un lexer qui va bien fprintf(stderr, "(stdin):%i: error: %s\n", yylineno, s); } void warning(char *msg) { fprintf(stderr, "(stdin):%i: warning: %s\n", yylineno, msg); } int main(int argc, char **argv) { // Par défaut, c'est l'analyse LEXICALE qui est lancée ! if ( argc != 2 ) { fprintf(stderr, "Usage : %s \n", argv[0]); exit(-1); } printf("Opening...\n"); openWriteDestFiles(argv[1]); printf("Parsing...\n"); // TODO : fichier d'entrée yyparse(); printf("Closing...\n"); closeDestFiles(); printf("Linking...\n"); linker(argv[1],0); // TODO tester autre que 0 return 0; } // TODO : passer &tableSym en param struct symbolEntry * addSym(char *varName, int contextProf, int readOnly) { struct symbolEntry *sym = NULL; if ( symbolFind(tableSym, varName, contextProf, contextProf) == NULL ) { sym = malloc(1*sizeof(struct symbolEntry)); sym->symName = malloc(strlen(varName) * sizeof(char)); strcpy(sym->symName,varName); sym->address = SP++; sym->readOnly = readOnly; sym->initialized = 0; sym->contextProf = contextProf; symbolPush(&tableSym,sym); } /* else return NULL */ return sym; } void genCode(int opcode, int op1, int op2, int op3) { writeCode(opcode,op1,op2,op3); } void genCodeJump(int opcode, int op1, int op2, int op3, char *targetLabel) { int addr=writeCode(opcode,op1,op2,op3); switch (opcode) { case I_JMP: writeHole(addr+1, targetLabel); break; case I_JMF: writeHole(addr+2, targetLabel); break; default: yyerror("Internal error : genCodeJump called whiout a I_JMP or I_JMF opcode"); /* YYERROR; TODO : dégager...*/ break; } } void genLabel(char *lbl, char *prefix, int id) { sprintf(lbl, "!%s%d", prefix, id); } // TODO : variable globales en dehors du main ?