359 lines
8.3 KiB
Plaintext
359 lines
8.3 KiB
Plaintext
%{
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
int yylex();
|
|
|
|
void yyerror(char *s)
|
|
{
|
|
fflush(stdout);
|
|
fprintf(stderr, "%s\n", s);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
/* Data structures for storing a programme. */
|
|
|
|
typedef struct var // a variable
|
|
{
|
|
char *name;
|
|
int class;
|
|
int value; // 0 = bool, 1 = int
|
|
struct var *next;
|
|
} var;
|
|
|
|
typedef struct varlist // variable reference (used for print statement)
|
|
{
|
|
struct var *var;
|
|
struct varlist *next;
|
|
} varlist;
|
|
|
|
typedef struct expr // boolean expression
|
|
{
|
|
int type; // TRUE, FALSE, OR, AND, EQUIV, NOT, 0 (variable), PLUS, TIMES, INT, EQUALS, LT
|
|
int class; // 0 = bool, 1 = int, 2 = both
|
|
var *var;
|
|
struct expr *left, *right;
|
|
} expr;
|
|
|
|
typedef struct stmt // command
|
|
{
|
|
int type; // ASSIGN, ';', WHILE, IF, PRINT
|
|
var *var;
|
|
expr *expr;
|
|
struct stmt *left, *right;
|
|
varlist *list;
|
|
} stmt;
|
|
|
|
/****************************************************************************/
|
|
/* All data pertaining to the programme are accessible from these two vars. */
|
|
|
|
var *program_vars;
|
|
var *program_ints;
|
|
stmt *program_stmts;
|
|
|
|
/****************************************************************************/
|
|
/* Functions for settting up data structures at parse time. */
|
|
|
|
var* make_ident (char *s, int class) // type = 0 for a boolean var, type = 1 for an int var
|
|
{
|
|
var *v = malloc(sizeof(var));
|
|
v->name = s;
|
|
v->class = class;
|
|
v->value = 0; // make variable false initially
|
|
v->next = NULL;
|
|
return v;
|
|
}
|
|
|
|
var* find_ident (char *s)
|
|
{
|
|
var *v = program_vars;
|
|
while (v && strcmp(v->name,s))
|
|
v = v->next;
|
|
if (!v) {
|
|
// Check in int vars
|
|
v = program_ints;
|
|
while (v && strcmp(v->name, s))
|
|
v = v->next;
|
|
}
|
|
if (!v) {
|
|
yyerror("undeclared variable");
|
|
exit(1);
|
|
}
|
|
return v;
|
|
}
|
|
|
|
var* make_int(int val)
|
|
{
|
|
var *v = malloc(sizeof(var));
|
|
v->name = NULL;
|
|
v->class = 1; // int
|
|
v->value = val;
|
|
v->next = NULL;
|
|
return v;
|
|
}
|
|
|
|
varlist* make_varlist (char *s)
|
|
{
|
|
var *v = find_ident(s);
|
|
varlist *l = malloc(sizeof(varlist));
|
|
l->var = v;
|
|
l->next = NULL;
|
|
return l;
|
|
}
|
|
|
|
expr* make_expr (int type, int class, var *var, expr *left, expr *right)
|
|
{
|
|
expr *e = malloc(sizeof(expr));
|
|
e->type = type;
|
|
e->class = class;
|
|
e->var = var;
|
|
e->left = left;
|
|
e->right = right;
|
|
return e;
|
|
}
|
|
|
|
stmt* make_stmt (int type, var *var, expr *expr,
|
|
stmt *left, stmt *right, varlist *list)
|
|
{
|
|
stmt *s = malloc(sizeof(stmt));
|
|
s->type = type;
|
|
s->var = var;
|
|
s->expr = expr;
|
|
s->left = left;
|
|
s->right = right;
|
|
s->list = list;
|
|
return s;
|
|
}
|
|
|
|
|
|
%}
|
|
|
|
/****************************************************************************/
|
|
|
|
/* types used by terminals and non-terminals */
|
|
|
|
%union {
|
|
char *i;
|
|
var *v;
|
|
varlist *l;
|
|
expr *e;
|
|
stmt *s;
|
|
int val;
|
|
}
|
|
|
|
%type <v> bool_declist
|
|
%type <v> int_declist
|
|
%type <l> varlist
|
|
%type <e> expr
|
|
%type <s> stmt assign
|
|
|
|
%token BOOL TYPE_INT WHILE DO OD IF THEN ELSE FI ASSIGN PRINT OR AND XOR NOT TRUE FALSE
|
|
%token <i> IDENT
|
|
%token <val> INT
|
|
|
|
%left ';'
|
|
|
|
%left OR XOR
|
|
%left AND
|
|
%left EQUIV
|
|
%left EQUALS
|
|
%left LT
|
|
%left PLUS
|
|
%left TIMES
|
|
%right NOT
|
|
|
|
%%
|
|
|
|
prog : bools ints stmt { program_stmts = $3; }
|
|
| bools stmt { program_stmts = $2; }
|
|
| ints stmt { program_stmts = $2; }
|
|
| stmt { program_stmts = $1; }
|
|
|
|
bools : BOOL bool_declist ';' { program_vars = $2; }
|
|
|
|
bool_declist : IDENT { $$ = make_ident($1, 0); }
|
|
| bool_declist ',' IDENT { ($$ = make_ident($3, 0))->next = $1; }
|
|
|
|
ints : TYPE_INT int_declist ';' { program_ints = $2; }
|
|
|
|
int_declist : IDENT { $$ = make_ident($1, 1); }
|
|
| int_declist ',' IDENT { ($$ = make_ident($3, 1))->next = $1; }
|
|
|
|
stmt : assign
|
|
| stmt ';' stmt
|
|
{ $$ = make_stmt(';',NULL,NULL,$1,$3,NULL); }
|
|
| WHILE expr DO stmt OD
|
|
{ $$ = make_stmt(WHILE,NULL,$2,$4,NULL,NULL); }
|
|
| IF expr THEN stmt ELSE stmt FI
|
|
{ $$ = make_stmt(IF,NULL,$2,$4,$6,NULL); }
|
|
| IF expr THEN stmt FI
|
|
{ $$ = make_stmt(IF,NULL,$2,$4,NULL,NULL); }
|
|
| PRINT varlist
|
|
{ $$ = make_stmt(PRINT,NULL,NULL,NULL,NULL,$2); }
|
|
|
|
assign : IDENT ASSIGN expr
|
|
{ $$ = make_stmt(ASSIGN,find_ident($1),$3,NULL,NULL,NULL); }
|
|
|
|
varlist : IDENT { $$ = make_varlist($1); }
|
|
| varlist ',' IDENT { ($$ = make_varlist($3))->next = $1; }
|
|
|
|
expr : IDENT { $$ = make_expr(0, 2, find_ident($1), NULL, NULL); }
|
|
| expr XOR expr { $$ = make_expr(XOR, 0, NULL, $1, $3); }
|
|
| expr OR expr { $$ = make_expr(OR, 0, NULL, $1, $3); }
|
|
| expr AND expr { $$ = make_expr(AND, 0, NULL, $1, $3); }
|
|
| expr EQUIV expr { $$ = make_expr(EQUIV, 0, NULL, $1, $3); }
|
|
| NOT expr { $$ = make_expr(NOT, 0, NULL, $2, NULL); }
|
|
| TRUE { $$ = make_expr(TRUE, 0, NULL, NULL, NULL); }
|
|
| FALSE { $$ = make_expr(FALSE, 0, NULL, NULL, NULL); }
|
|
| '(' expr ')' { $$ = $2; }
|
|
| INT { $$ = make_expr(INT, 1, make_int($1), NULL, NULL); }
|
|
| expr TIMES expr { $$ = make_expr(TIMES, 1, NULL, $1, $3); }
|
|
| expr PLUS expr { $$ = make_expr(PLUS, 1, NULL, $1, $3); }
|
|
| expr LT expr { $$ = make_expr(LT, 0, NULL, $1, $3); }
|
|
| expr EQUALS expr { $$ = make_expr(EQUALS, 0, NULL, $1, $3); }
|
|
|
|
|
|
%%
|
|
|
|
#include "langlex.c"
|
|
|
|
/****************************************************************************/
|
|
/* programme interpreter : */
|
|
|
|
int eval (expr *e)
|
|
{
|
|
switch (e->type)
|
|
{
|
|
case TRUE: return 1;
|
|
case FALSE: return 0;
|
|
case XOR: {
|
|
if (e->left->class != 0 || e->right->class != 0) {
|
|
yyerror("An 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");
|
|
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");
|
|
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");
|
|
exit(-1);
|
|
}
|
|
int right = eval(e->right);
|
|
int left = eval(e->left);
|
|
return (right && left) || (!right && !left); // Équivalent avec left == right avec la définition.
|
|
// Toutefois, on privilégie cette forme car faux = 0 et vrai = tout entier non nul
|
|
}
|
|
case NOT: {
|
|
if (e->left->class != 0) {
|
|
yyerror("An 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");
|
|
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");
|
|
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");
|
|
exit(-1);
|
|
}
|
|
|
|
printf("%d, %d\n", eval(e->left), eval(e->right));
|
|
return eval(e->left) == eval(e->right) ? 1 : 0;
|
|
}
|
|
case LT: {
|
|
if (e->left->class != 1 || e->right->class != 1) {
|
|
yyerror("An expression has wrong types");
|
|
exit(-1);
|
|
}
|
|
return eval(e->left) < eval(e->right) ? 1 : 0;
|
|
}
|
|
case INT:
|
|
case 0:
|
|
return e->var->value;
|
|
}
|
|
}
|
|
|
|
void print_vars (varlist *l)
|
|
{
|
|
// Attention, varlist is in reverse order (this was easier to set up
|
|
// at parse time, see the code for varlist in the grammar).
|
|
|
|
if (!l) return;
|
|
print_vars(l->next);
|
|
if (l->var->class == 0)
|
|
printf("%s = %c ", l->var->name, l->var->value ? 'T' : 'F');
|
|
else if (l->var->class == 1)
|
|
printf("%s = %d ", l->var->name, l->var->value);
|
|
else
|
|
fprintf(stderr, "The type of the var %s is unknown", l->var->name);
|
|
}
|
|
|
|
void execute (stmt *s)
|
|
{
|
|
switch(s->type)
|
|
{
|
|
case ASSIGN:
|
|
if (s->var->class != s->expr->class) {
|
|
yyerror("An assignment has the wrong type");
|
|
exit(-1);
|
|
}
|
|
s->var->value = eval(s->expr);
|
|
break;
|
|
case ';':
|
|
execute(s->left);
|
|
execute(s->right);
|
|
break;
|
|
case WHILE:
|
|
while (eval(s->expr)) execute(s->left);
|
|
break;
|
|
case IF:
|
|
if (eval(s->expr))
|
|
execute(s->left);
|
|
else if (s->right != NULL)
|
|
execute(s->right);
|
|
break;
|
|
case PRINT:
|
|
print_vars(s->list);
|
|
puts("");
|
|
break;
|
|
}
|
|
}
|
|
|
|
/****************************************************************************/
|
|
|
|
int main (int argc, char **argv)
|
|
{
|
|
if (argc <= 1) { yyerror("no file specified"); exit(1); }
|
|
yyin = fopen(argv[1],"r");
|
|
if (!yyparse()) execute(program_stmts);
|
|
}
|