Commit f6c2d656 authored by qanastek's avatar qanastek

update post backup de l'uapv

parent 58867e23
# CERIcompiler :computer:
*Author: Labrak Yanis*
*Degree: Licence 2 Informatique - Groupe 4*
*School: Université d'Avignon*
**Task List :**
- [x] Initialize the project
- [x] LL(1)
- [x] Modify Main
- [x] Create function OperatorComparaison()
- [x] Create function Comparaison()
- [x] Check result of the compilator
- [x] Numbers
- [ ] Mul / Div
- [ ] Program
- [x] DeclarationPart
- [ ] Statements
- [ ] if
- [ ] while
- [ ] do while
- [ ] for
- [ ] AssignementStatement - A = B
- [ ] LL(2)
- [x] Read next char
- [ ] MultiplicativeOperator
- [ ] RelationalOperator
- [ ] AdditiveOperator
**Errors to fix :**
- [ ] Cannot do (a+2)
**Compile, inject the arithmetic expression in the program and check functionement in DDD**
> g++ -ggdb compilateur.cpp -o compilateur && cat test.p | ./compilateur > test.s && gcc -ggdb test.s -o test && ddd ./test
**Program working diagram :** *(So big to be fully modelized)*
```mermaid
graph TD;
input_expression-->ReadChar;
ReadChar-->CheckSign;
CheckSign-->ReadChar;
CheckSign-->Error;
ReadChar-->Stop;
ReadChar-->Comparaison;
Comparaison-->ReadChar;
Comparaison-->ArithmeticExpression;
ArithmeticExpression-->Term;
Term-->IfParemthese;
Term-->IfNotParemthese;
IfParemthese-->ReadChar;
IfParemthese-->ArithmeticExpression;
```
>>>
A simple compiler.
From : `Pascal`-like imperative LL(k) langage
To : 64 bit 80x86 assembly langage (`AT&T`)
>>>
# CERIcompiler
# Usage Informations
A simple compiler.
From : Pascal-like imperative LL(k) langage
To : 64 bit 80x86 assembly langage (AT&T)
**Download the repository :**
> git clone https://framagit.org/qanastek/cericompiler
**Build the compiler with debug symbols :**
> git clone git@framagit.org:jourlin/cericompiler.git
> g++ -ggdb compilateur.cpp -o compilateur
**Build the compiler and test it :**
**Compile the test program :**
> cat test.p | ./compilateur > test.s
> make test
**Have a look at the output :**
> gedit test.s
**Produce the executable (with debug info) :**
> gcc -ggdb test.s -o test :
**Debug the executable :**
> ddd ./test
......@@ -103,3 +32,24 @@ To : 64 bit 80x86 assembly langage (`AT&T`)
> git pull -u origin master
**This version Can handle :**
// Program := [DeclarationPart] StatementPart
// DeclarationPart := "[" Identifier {"," Identifier} "]"
// StatementPart := Statement {";" Statement} "."
// Statement := AssignementStatement
// AssignementStatement := Identifier ":=" Expression
// Expression := SimpleExpression [RelationalOperator SimpleExpression]
// SimpleExpression := Term {AdditiveOperator Term}
// Term := Factor {MultiplicativeOperator Factor}
// Factor := Number | Letter | "(" Expression ")"| "!" Factor
// Number := Digit{Digit}
// Identifier := Letter {(Letter|Digit)}
// AdditiveOperator := "+" | "-" | "||"
// MultiplicativeOperator := "*" | "/" | "%" | "&&"
// RelationalOperator := "==" | "!=" | "<" | ">" | "<=" | ">="
// Digit := "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
// Letter := "a"|...|"z"
No preview for this file type
......@@ -21,446 +21,504 @@
#include <string>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <set>
#include <map>
#include <FlexLexer.h>
#include "tokeniser.h"
#include <cstring>
using namespace std;
char current, lookedAhead; // Current char
int NLookedAhead=0;
void ReadChar(void){
if(NLookedAhead>0){
current=lookedAhead; // Char has already been read
NLookedAhead--;
}
else
// Read character and skip spaces until
// non space character is read
while(cin.get(current) && (current==' '||current=='\t'||current=='\n'));
}
enum OPREL {EQU, DIFF, INF, SUP, INFE, SUPE, WTFR};
enum OPADD {ADD, SUB, OR, WTFA};
enum OPMUL {MUL, DIV, MOD, AND ,WTFM};
enum TYPES {INTEGER, BOOLEAN};
void LookAhead(void)
{
while(cin.get(lookedAhead) && (lookedAhead==' '||lookedAhead=='\t'||lookedAhead=='\n'));
NLookedAhead++;
}
TOKEN current; // Current token
void Error(string s)
{
cerr << s << endl;
exit(-1);
FlexLexer* lexer = new yyFlexLexer; // This is the flex tokeniser
// tokens can be read using lexer->yylex()
// lexer->yylex() returns the type of the lexicon entry (see enum TOKEN in tokeniser.h)
// and lexer->YYText() returns the lexicon entry as a string
map<string, enum TYPES> DeclaredVariables; // Store declared variables and their types
unsigned long long TagNumber=0;
bool IsDeclared(const char *id){
return DeclaredVariables.find(id)!=DeclaredVariables.end();
}
/**
* Return if its a digit or not
* @param C Character to analyze
* @return true or false
*/
bool isDigit(char C)
{
if (C >= '0' and C <= '9')
{
return true;
}
else
{
return false;
}
void Error(string s){
cerr << "Ligne n°"<<lexer->lineno()<<", lu : '"<<lexer->YYText()<<"'("<<current<<"), mais ";
cerr<< s << endl;
exit(-1);
}
/**
* Return if its a letter or not
* @param C Character to analyze
* @return true or false
*/
bool isLetter(char C)
{
if (C >= 'A' and C <= 'Z')
{
return true;
}
else if (C >= 'a' and C <= 'z')
{
return true;
}
else
{
return false;
}
// Program := [DeclarationPart] StatementPart
// DeclarationPart := "[" Letter {"," Letter} "]"
// StatementPart := Statement {";" Statement} "."
// Statement := AssignementStatement
// AssignementStatement := Letter "=" Expression
// Expression := SimpleExpression [RelationalOperator SimpleExpression]
// SimpleExpression := Term {AdditiveOperator Term}
// Term := Factor {MultiplicativeOperator Factor}
// Factor := Number | Letter | "(" Expression ")"| "!" Factor
// Number := Digit{Digit}
// AdditiveOperator := "+" | "-" | "||"
// MultiplicativeOperator := "*" | "/" | "%" | "&&"
// RelationalOperator := "==" | "!=" | "<" | ">" | "<=" | ">="
// Digit := "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
// Letter := "a"|...|"z"
// To avoid cross references problems :
enum TYPES Expression(void); // Called by Term() and calls Term()
void Statement(void);
void StatementPart(void);
enum TYPES Identifier(void){
cout << "\tpush "<<lexer->YYText()<<endl;
current=(TOKEN) lexer->yylex();
return INTEGER;
}
/**
* Return if its a additif operator or not
* @param C Character to analyze
* @return true or false
*/
bool isAddOpp(char C)
{
if (C == '+' or C == '-')
{
return true;
}
else
{
return false;
}
enum TYPES Number(void){
cout <<"\tpush $"<<atoi(lexer->YYText())<<endl;
current=(TOKEN) lexer->yylex();
return INTEGER;
}
bool isCompOpp(char C)
{
if (current == '<' or current == '>' or current == '!' or current == '=')
{
return true;
}
else
{
return false;
enum TYPES Factor(void){
enum TYPES type;
if(current==RPARENT){
current=(TOKEN) lexer->yylex();
type=Expression();
if(current!=LPARENT)
Error("')' était attendu"); // ")" expected
else
current=(TOKEN) lexer->yylex();
}
else
if (current==NUMBER)
type=Number();
else
if(current==ID)
type=Identifier();
else
Error("'(' ou chiffre ou lettre attendue");
return type;
}
/**
* Convert an Character to an Integer
* @param C The char you want to convert
* @return Integer
*/
int CharToInt(char C)
{
return C - '0';
// MultiplicativeOperator := "*" | "/" | "%" | "&&"
OPMUL MultiplicativeOperator(void){
OPMUL opmul;
if(strcmp(lexer->YYText(),"*")==0)
opmul=MUL;
else if(strcmp(lexer->YYText(),"/")==0)
opmul=DIV;
else if(strcmp(lexer->YYText(),"%")==0)
opmul=MOD;
else if(strcmp(lexer->YYText(),"&&")==0)
opmul=AND;
else opmul=WTFM;
current=(TOKEN) lexer->yylex();
return opmul;
}
// int toInteger(string leNombre)
// {
// unsigned long long nbr;
// stringStream laConversion(leNombre);
// laConversion >> nbr;
// return nbr;
// }
// ArithmeticExpression := Term {AdditiveOperator Term}
// Term := Digit | "(" ArithmeticExpression ")"
// AdditiveOperator := "+" | "-"
// ComparaisonOperator := "<" | ">" | "="
// Digit := "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"
void AdditiveOperator(void)
{
if(current == '+' or current == '-')
{
ReadChar();
}
else
{
Error("Opérateur additif attendu"); // Additive operator expected
// Term := Factor {MultiplicativeOperator Factor}
enum TYPES Term(void){
TYPES type1, type2;
OPMUL mulop;
type1=Factor();
while(current==MULOP){
mulop=MultiplicativeOperator(); // Save operator in local variable
type2=Factor();
if(type2!=type1)
Error("types incompatibles dans l'expression");
cout << "\tpop %rbx"<<endl; // get first operand
cout << "\tpop %rax"<<endl; // get second operand
switch(mulop){
case AND:
if(type2!=BOOLEAN)
Error("le type doit être BOOLEAN dans l'expression");
cout << "\tmulq %rbx"<<endl; // a * b -> %rdx:%rax
cout << "\tpush %rax\t# AND"<<endl; // store result
break;
case MUL:
if(type2!=INTEGER)
Error("le type doit être INTEGER dans l'expression");
cout << "\tmulq %rbx"<<endl; // a * b -> %rdx:%rax
cout << "\tpush %rax\t# MUL"<<endl; // store result
break;
case DIV:
if(type2!=INTEGER)
Error("le type doit être INTEGER dans l'expression");
cout << "\tmovq $0, %rdx"<<endl; // Higher part of numerator
cout << "\tdiv %rbx"<<endl; // quotient goes to %rax
cout << "\tpush %rax\t# DIV"<<endl; // store result
break;
case MOD:
if(type2!=INTEGER)
Error("le type doit être INTEGER dans l'expression");
cout << "\tmovq $0, %rdx"<<endl; // Higher part of numerator
cout << "\tdiv %rbx"<<endl; // remainder goes to %rdx
cout << "\tpush %rdx\t# MOD"<<endl; // store result
break;
default:
Error("opérateur multiplicatif attendu");
}
}
return type1;
}
void OperatorComparaison(void)
{
if(isCompOpp(current))
{
ReadChar();
}
else
{
Error("Opérateur comparaison attendu"); // Additive operator expected
}
// AdditiveOperator := "+" | "-" | "||"
OPADD AdditiveOperator(void){
OPADD opadd;
if(strcmp(lexer->YYText(),"+")==0)
opadd=ADD;
else if(strcmp(lexer->YYText(),"-")==0)
opadd=SUB;
else if(strcmp(lexer->YYText(),"||")==0)
opadd=OR;
else opadd=WTFA;
current=(TOKEN) lexer->yylex();
return opadd;
}
void Declaration()
{
cout << "\t.data" << endl;
cout << "\t.align 8"<<endl;
if (isLetter(current))
{
cout << current << ":\t.quad 0" << endl;
LookAhead();
while (lookedAhead != ']')
{
if (lookedAhead == ',')
{
ReadChar();
}
else if (isLetter(lookedAhead))
{
ReadChar();
cout << current << ":\t.quad 0" << endl;
}
LookAhead();
// SimpleExpression := Term {AdditiveOperator Term}
enum TYPES SimpleExpression(void){
enum TYPES type1, type2;
OPADD adop;
type1=Term();
while(current==ADDOP){
adop=AdditiveOperator(); // Save operator in local variable
type2=Term();
if(type2!=type1)
Error("types incompatibles dans l'expression");
cout << "\tpop %rbx"<<endl; // get first operand
cout << "\tpop %rax"<<endl; // get second operand
switch(adop){
case OR:
if(type2!=BOOLEAN)
Error("le type doit être BOOLEAN dans l'expression");
cout << "\taddq %rbx, %rax\t# OR"<<endl;// operand1 OR operand2
break;
case ADD:
if(type2!=INTEGER)
Error("le type doit être INTEGER dans l'expression");
cout << "\taddq %rbx, %rax\t# ADD"<<endl; // add both operands
break;
case SUB:
if(type2!=INTEGER)
Error("le type doit être INTEGER dans l'expression");
cout << "\tsubq %rbx, %rax\t# SUB"<<endl; // substract both operands
break;
default:
Error("opérateur additif inconnu");
}
ReadChar();
}
else
{
Error("Letter expected");
cout << "\tpush %rax"<<endl; // store result
}
return type1;
}
void Digit(void)
{
if(!isDigit(current))
{
Error("Chiffre attendu"); // Digit expected
// DeclarationPart := "[" Ident {"," Ident} "]"
void DeclarationPart(void){
if(current!=RBRACKET)
Error("caractère '[' attendu");
current=(TOKEN) lexer->yylex();
if(current!=ID)
Error("Un identificater était attendu");
cout << lexer->YYText() << ":\t.quad 0"<<endl;
DeclaredVariables[lexer->YYText()]=INTEGER;
current=(TOKEN) lexer->yylex();
while(current==COMMA){
current=(TOKEN) lexer->yylex();
if(current!=ID)
Error("Un identificateur était attendu");
cout << lexer->YYText() << ":\t.quad 0"<<endl;
DeclaredVariables[lexer->YYText()]=INTEGER;
current=(TOKEN) lexer->yylex();
}
else
{
unsigned long long num = CharToInt(current);
if(current!=LBRACKET)
Error("caractère ']' attendu");
current=(TOKEN) lexer->yylex();
}
ReadChar();
// RelationalOperator := "==" | "!=" | "<" | ">" | "<=" | ">="
OPREL RelationalOperator(void){
OPREL oprel;
if(strcmp(lexer->YYText(),"==")==0)
oprel=EQU;
else if(strcmp(lexer->YYText(),"!=")==0)
oprel=DIFF;
else if(strcmp(lexer->YYText(),"<")==0)
oprel=INF;
else if(strcmp(lexer->YYText(),">")==0)
oprel=SUP;
else if(strcmp(lexer->YYText(),"<=")==0)
oprel=INFE;
else if(strcmp(lexer->YYText(),">=")==0)
oprel=SUPE;
else oprel=WTFR;
current=(TOKEN) lexer->yylex();
return oprel;
}
while(isDigit(current))
{
num *= 10; // Move curent first digit to the left
num += CharToInt(current); // Add the current digit to it
ReadChar(); // Move to the next one
// Expression := SimpleExpression [RelationalOperator SimpleExpression]
enum TYPES Expression(void){
enum TYPES type1, type2;
unsigned long long tag;
OPREL oprel;
type1=SimpleExpression();
if(current==RELOP){
tag=++TagNumber;
oprel=RelationalOperator();
type2=SimpleExpression();
if(type2!=type1)
Error("types incompatibles pour la comparaison");
cout << "\tpop %rax"<<endl;
cout << "\tpop %rbx"<<endl;
cout << "\tcmpq %rax, %rbx"<<endl;
switch(oprel){
case EQU:
cout << "\tje Vrai"<<tag<<"\t# If equal"<<endl;
break;
case DIFF:
cout << "\tjne Vrai"<<tag<<"\t# If different"<<endl;
break;
case SUPE:
cout << "\tjae Vrai"<<tag<<"\t# If above or equal"<<endl;
break;
case INFE:
cout << "\tjbe Vrai"<<tag<<"\t# If below or equal"<<endl;
break;
case INF:
cout << "\tjb Vrai"<<tag<<"\t# If below"<<endl;
break;
case SUP:
cout << "\tja Vrai"<<tag<<"\t# If above"<<endl;
break;
default:
Error("Opérateur de comparaison inconnu");
}
cout << "\tpush $" << num << endl; // Push the full number
cout << "\tpush $0\t\t# False"<<endl;
cout << "\tjmp Suite"<<tag<<endl;
cout << "Vrai"<<tag<<":\tpush $0xFFFFFFFFFFFFFFFF\t\t# True"<<endl;
cout << "Suite"<<tag<<":"<<endl;
return BOOLEAN;
}
return type1;
}
void Variable(void)
{
if(!isLetter(current))
{
Error("Lettre attendu"); // Digit expected
// AssignementStatement := Identifier ":=" Expression
void AssignementStatement(void){
enum TYPES type1, type2;
string variable;
if(current!=ID)
Error("Identificateur attendu");
if(!IsDeclared(lexer->YYText())){
cerr << "Erreur : Variable '"<<lexer->YYText()<<"' non déclarée"<<endl;
exit(-1);
}
else
{
cout << "\tpush " << current << "\t# Variable - " << current << endl; // Push the full number
variable=lexer->YYText();
type1=DeclaredVariables[variable];
current=(TOKEN) lexer->yylex();
if(current!=ASSIGN)
Error("caractères ':=' attendus");
current=(TOKEN) lexer->yylex();
type2=Expression();
if(type2!=type1){
cerr<<"Type variable "<<type1<<endl;
cerr<<"Type Expression "<<type2<<endl;
Error("types incompatibles dans l'affectation");
}
cout << "\tpop "<<variable<<endl;
}
void ArithmeticExpression(void); // Called by Term() and calls Term()
// DisplayStatement := "DISPLAY" Expression
void DisplayStatement(void){
current=(TOKEN) lexer->yylex();
if(Expression()!=INTEGER)
Error("DISPLAY ne fonctionne que pour les nombres entiers");
cout << "\tpop %rdx\t# The value to be displayed"<<endl;
cout << "\tmovq $FormatString1, %rsi\t# \"%llu\\n\""<<endl;
cout << "\tmovl $1, %edi"<<endl;
cout << "\tmovl $0, %eax"<<endl;
cout << "\tcall __printf_chk@PLT"<<endl;
}
void LoadDeclaration(void)
// ForStatement := "For" ID ":=" Expression ("TO"|"DOWNTO") Expression "DO" Statement
void ForStatement(void)
{
if (current == '[')
{
ReadChar();
unsigned long long tag = TagNumber++;
Declaration();
if (strcmp(lexer->YYText(), "FOR")!=0) Error("FOR expected");
if(current != ']')
{
Error("']' expected");
}
else
{
ReadChar();
}
}
}
cout << "ForInit" << tag << ":" << endl;
void Term(void)
{
if(current == '(')
{
ReadChar();
current = (TOKEN) lexer->yylex();
ArithmeticExpression();
string variable = lexer->YYText(); // Récupère le nom de la variable
// ReadChar();
// cout << " current : " << current << endl;
AssignementStatement();
if(current != ')')
{
Error("')' expected");
}
else
{
ReadChar();
}
}
else
{
if (isDigit(current))
{
Digit();
}
else if (isLetter(current))
{
Variable(); // Push the variable
}
else
{
Error("Letter or '(' or number expected");
}
}
}
if (strcmp(lexer->YYText(), "TO")!=0) Error("TO expected");
void ArithmeticExpression(void)
{
char ope;
current = (TOKEN) lexer->yylex();
Term();
Expression();
// ReadChar();
if (isLetter(current))
{
ReadChar();
}
// cout << " current : " << current << endl;
cout << "\tpop %rax" << endl; // Récupère le résultat goal
while (isAddOpp(current))
{
ope = current; // Save operator in local variable
cout << "For" << tag << " :" << endl;
if (isAddOpp(current))
{
AdditiveOperator();
}
cout << "\tcmpq %rax, " << variable << endl; // Regarde si i respecte le goal
cout << "\tjge SuiteFor" << tag << endl; // Si il à dépassé ou il est au goal jump vers SuiteFor
Term();
if (strcmp(lexer->YYText(), "DO")!=0) Error("DO expected");
cout << "\tpop %rbx"<<endl; // get first operand
cout << "\tpop %rax"<<endl; // get second operand
current = (TOKEN) lexer->yylex();
if (ope == '+')
{
cout << "\taddq %rbx, %rax"<<endl; // add both operands
}
else if (ope == '-')
{
cout << "\tsubq %rbx, %rax"<<endl; // substract both operands
}
else
{