Fin du readme

This commit is contained in:
Yohann D'ANELLO 2020-05-17 18:24:19 +02:00
parent 45723682bf
commit d8df43acf3
3 changed files with 71 additions and 13 deletions

View File

@ -12,7 +12,7 @@ geometry:
# Analyse lexicale
Le fichier `example.l` peut se compiler en un analyseur lexical `example` en appelant simplement la commande `make`. Il permet à partir d'une entrée textuelle (un fichier, le TTY ou l'entrée standard suivie d'un Ctrl+D) de filter les nombres et de les afficher, sous forme décimale ou hexadécimale. De plus, les mots clés `if`, `then` et `else` sont réécrits en majsucule. Tout le reste est ignoré.
Le fichier `example.l` peut se compiler en un analyseur lexical `example` en appelant simplement la commande `make example`. Il permet à partir d'une entrée textuelle (un fichier, le TTY ou l'entrée standard suivie d'un Ctrl+D) de filter les nombres et de les afficher, sous forme décimale ou hexadécimale. De plus, les mots clés `if`, `then` et `else` sont réécrits en majsucule. Tout le reste est ignoré.
Un entier `n` affichera sur la sortie `int(n)`, un entier `0xh` écrit en hexadécimal affichera dans la sortie `hex(n)``n` est la représentation décimale de `0xh`.
@ -34,6 +34,51 @@ else
Le programme va renvoyer la sortie suivante :
```
int(1)IFTHENint(1)int(20)int(20)int(100)int(3)ELSEhex(16777215)int(10)int(12)int(42)int(13)int(7832)
int(1)IFTHENint(1)int(20)int(20)int(100)int(3)ELSEhex(16777215)int(10)int(12)int(42)int(14)int(7832)
```
# Analyse syntaxique
Le programme `lang`, après compilation en appelant successivement `make langlex.c` et `make lang`, se comporte comme un interpréteur d'un langage de programmation fait à la main. L'extension attribuée est le `*.my`, même si cela n'est pas obligatoire.
Un programme est composé de trois parties :
* La déclaration des variables booléennes (faculatif). Cela se fait en écrivant `bool` suivi de la liste des variables booléennes à déclarer séparées par des virgules. La déclaration doit se finir par un point-virgule. Par exemple, on notera `bool x, y, z;` pour déclarer les variables booléenes `x`, `y` et `z`.
* De la même manière, on notera `int a, b, c;` pour déclarer les variables entières `a`, `b` et `c` (facultatif). La déclaration des variables entières doit se faire après la déclaration des variables booléennes s'il y en a.
* Enfin, le code. Le code est une succession d'instructions séparées par des point-virgules. Il existe 4 types d'instructions :
* L'affectation, de la forme `x := expr``x` est une variable déclarée et `expr` une expression du même type que `x`.
* Un test conditionnel, de la forme `if cond then stmt1 else stmt2``cond` est une expression booléenne et `stmt1` et `stmt2` deux blocs d'instructions. L'interprétation est naturelle : si la condition `cond` vaut `true`, on exécute le bloc `stmt1`, sinon on évalue le bloc `stmt2`. La partie `else stmt2` est facultative. Le problème du `dangling else` est résolu de la même manière qu'en C : le premier `else` porte sur le premier `if`.
* Une boucle de la forme `while cond do stmt od``cond` est une expression booléenne et `stmt` une suite d'instructions. L'expression `cond` sera évaluée à chaque passage de boucle, et on reste dans la boucle tant que que la condition vaut `true`.
* Un affichage des variables. Le code doit être de la forme `print list``list` est la liste des variables à afficher, séparées par des virgules. La fonction fonctionne à la fois avec des variables booléennes et des variables entières.
Une expression peut être de différentes formes. Chaque type d'expression est associée à une "classe" : booléen ou entier, ou les deux.
* La valeur d'une variable (du type de la variable)
* Un ou exclusif de deux expressions booléennes (renvoie un booléen)
* La disjonction de deux expressions booléennes (renvoie un booléen)
* La conjection de deux expressions booléennes (renvoie un booléen)
* L'équivalence deux expressions booléennes (renvoie un booléen)
* Une négation d'une expression booléenne (renvoie un booléen)
* `true` (booléen pour dire vrai)
* `false` (booléen pour dire faux)
* Une expression entre parenthèse (du type de ce qui est entre parenthèses)
* La somme de deux expressions entières (renvoie un entier)
* Le produit de deux expressions entières (renvoie un entier)
* La comparaison par inégalité stricte entre deux expression entières (renvoie un booléen)
* L'égalité entre deux expressions entières (renvoie un booléen)
Les priorités opérations sont les mêmes qu'en C :
1. La négation booléenne
2. La mutliplication entière
3. L'addition entière
4. L'inégalité stricte entre entiers
5. L'égalité entière
6. L'équivalence booléenne
7. La conjonction
8. La disjonction (éventuellement exclusive)
Lors de l'évaluation des expressions, les types sont correctement vérifiés.

Binary file not shown.

View File

@ -108,6 +108,8 @@ expr* make_expr (int type, int class, var *var, expr *left, expr *right)
expr *e = malloc(sizeof(expr));
e->type = type;
e->class = class;
if (var != NULL)
e->class = var->class;
e->var = var;
e->left = left;
e->right = right;
@ -230,28 +232,28 @@ int eval (expr *e)
case FALSE: return 0;
case XOR: {
if (e->left->class != 0 || e->right->class != 0) {
yyerror("An expression has wrong types");
yyerror("A xor expression has wrong types");
exit(-1);
}
return eval(e->left) ^ eval(e->right);
}
case OR: {
if (e->left->class != 0 || e->right != NULL && e->right->class != 0) {
yyerror("An expression has wrong types");
yyerror("An or expression has wrong types");
exit(-1);
}
return eval(e->left) || eval(e->right);
}
case AND: {
if (e->left->class != 0 || e->right->class != 0) {
yyerror("An expression has wrong types");
yyerror("An and expression has wrong types");
exit(-1);
}
return eval(e->left) && eval(e->right);
}
case EQUIV: {
if (e->left->class != 0 || e->right->class != 0) {
yyerror("An expression has wrong types");
yyerror("An equivalence expression has wrong types");
exit(-1);
}
int right = eval(e->right);
@ -261,28 +263,28 @@ int eval (expr *e)
}
case NOT: {
if (e->left->class != 0) {
yyerror("An expression has wrong types");
yyerror("A not expression has wrong types");
exit(-1);
}
return !eval(e->left);
}
case PLUS: {
if (e->left->class != 1 || e->right->class != 1) {
yyerror("An expression has wrong types");
yyerror("A plus expression has wrong types");
exit(-1);
}
return eval(e->left) + eval(e->right);
}
case TIMES: {
if (e->left->class != 1 || e->right->class != 1) {
yyerror("An expression has wrong types");
yyerror("A times expression has wrong types");
exit(-1);
}
return eval(e->left) * eval(e->right);
}
case EQUALS: {
if (e->left->class != 1 || e->right->class != 1) {
yyerror("An expression has wrong types");
yyerror("An equality expression has wrong types");
exit(-1);
}
@ -291,7 +293,7 @@ int eval (expr *e)
}
case LT: {
if (e->left->class != 1 || e->right->class != 1) {
yyerror("An expression has wrong types");
yyerror("A comparison expression has wrong types");
exit(-1);
}
return eval(e->left) < eval(e->right) ? 1 : 0;
@ -332,15 +334,26 @@ void execute (stmt *s)
execute(s->left);
execute(s->right);
break;
case WHILE:
case WHILE: {
if (s->expr->class != 0 && s->expr->class != 2) {
yyerror("A while condition must be a boolean expression");
exit(-1);
}
while (eval(s->expr)) execute(s->left);
break;
case IF:
}
case IF: {
if (s->expr->class != 0 && s->expr->class != 2) {
yyerror("An if condition must be a boolean expression");
exit(-1);
}
if (eval(s->expr))
execute(s->left);
else if (s->right != NULL)
execute(s->right);
break;
}
case PRINT:
print_vars(s->list);
puts("");