You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
428 lines
11 KiB
428 lines
11 KiB
/**
|
|
* #(@)parser.y ENSICAEN 2005
|
|
*
|
|
* @author MASSE Nicolas (2005-Groupe3-LIMIN) <nicolas27.masse@laposte.net>
|
|
* @author LIMIN Thomas (2005-Groupe3-MASSE) <thomas.limin@laposte.net>
|
|
*
|
|
* ENSICAEN
|
|
* 6 Boulevard Marechal Juin
|
|
* F-14050 Caen Cedex
|
|
*
|
|
* Ce fichier est l'oeuvre d'eleves de l'ENSI de Caen. Il ne peut etre
|
|
* reproduit, utilise ou modifie sans l'avis express de ses auteurs.
|
|
*/
|
|
|
|
/*
|
|
* @version 05/04/2006
|
|
*
|
|
* done: -
|
|
*
|
|
* todo: -
|
|
*/
|
|
|
|
/**
|
|
* @file parser.y
|
|
*
|
|
* Part of the Pascal grammar in Yacc format, based originally on BNF.
|
|
* The grammar has been massaged somewhat to make it LALR, and limited
|
|
* to integer type, and if and while control structure.
|
|
*/
|
|
|
|
%{
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
/* Fonctions utilitaires */
|
|
#include "generator.h"
|
|
|
|
/* Header commun */
|
|
#include "epc.h"
|
|
|
|
/* voir le corps de la méthode ci-dessous */
|
|
int yyerror(char * s);
|
|
|
|
/** Le nom du programme, utilisée par yacc */
|
|
char * progname;
|
|
%}
|
|
|
|
/**
|
|
* The list of attributes associated to each terminal
|
|
* and non terminal of the grammar.
|
|
*/
|
|
%union {
|
|
char strval[255]; /* The value of the token. */
|
|
|
|
/**
|
|
* This structure defines the convenient
|
|
* information for building the code.
|
|
*/
|
|
struct t_code {
|
|
char* code; /* The string that contains the 3 address code */
|
|
char* place; /* The name of the identifier or the temporary variable. */
|
|
char* before; /* The name of the label before the code. */
|
|
char* after; /* The name of the label after the code. */
|
|
char* type; /* The name of the type (int, float, ...). */
|
|
} code3a;
|
|
}
|
|
|
|
/* Les jetons */
|
|
%token AND ASSIGNMENT
|
|
%token COLON COMMA DO DOT END EQUAL
|
|
%token GE GT IF IN INTEGER LBRAC LE
|
|
%token LPAREN LT MINUS NOT NOTEQUAL OF OR
|
|
%token PBEGIN PLUS
|
|
%token PROGRAM
|
|
%token RBRAC RPAREN
|
|
%token SEMICOLON DIV MULT THEN
|
|
%token VAR WHILE
|
|
%token <strval> IDENTIFIER
|
|
%token <strval> REALNUMBER
|
|
%token <strval> INTNUMBER
|
|
%token <strval> CHARACTER_STRING
|
|
|
|
/* Operator associativity. */
|
|
%left PLUS MINUS
|
|
%left OR AND NOT
|
|
%right MULT DIV
|
|
|
|
/* The axiom. */
|
|
%start program
|
|
|
|
/* Information de typage des non termimaux */
|
|
%type <code3a> identifier number term type_denoter sign
|
|
%type <code3a> compound_statement statement_sequence procedure_statement
|
|
%type <code3a> simple_expression expression instruction
|
|
%type <code3a> actual_parameter_list relop variable_declaration
|
|
%type <code3a> program_heading block statement_part
|
|
%%
|
|
program: program_heading SEMICOLON block DOT
|
|
{
|
|
puts("#include <stdio.h>");
|
|
puts("#include <math.h>");
|
|
puts($1.code);
|
|
puts($3.code);
|
|
}
|
|
;
|
|
|
|
program_heading: PROGRAM identifier
|
|
{
|
|
init(&$$);
|
|
$$.code = concat("/* nom du programme : '", $2.place, "' */", NULL);
|
|
}
|
|
;
|
|
|
|
block: variable_declaration_part statement_part
|
|
{
|
|
init(&$$);
|
|
$$.code = concat("int main(void) {\n",
|
|
$2.code,
|
|
prod("return 0"),
|
|
"}\n", NULL);
|
|
}
|
|
;
|
|
|
|
statement_part: compound_statement
|
|
{
|
|
init(&$$);
|
|
$$.code = concat(" /* début des variables */\n",
|
|
genDeclarationVars(),
|
|
" /* fin des variables */\n\n",
|
|
$1.code, NULL);
|
|
}
|
|
;
|
|
|
|
variable_declaration_part : VAR variable_declaration_list SEMICOLON
|
|
{
|
|
}
|
|
|
|
|
{
|
|
}
|
|
;
|
|
|
|
variable_declaration_list : variable_declaration_list SEMICOLON variable_declaration
|
|
{
|
|
}
|
|
|
|
| variable_declaration
|
|
{
|
|
}
|
|
|
|
;
|
|
variable_declaration : identifier COLON type_denoter
|
|
{
|
|
init(&$$);
|
|
addType($1.place, $3.type);
|
|
$$.type = $3.type;
|
|
}
|
|
| identifier COMMA variable_declaration
|
|
{
|
|
init(&$$);
|
|
addType($1.place, $3.type);
|
|
$$.type = $3.type;
|
|
}
|
|
|
|
;
|
|
type_denoter: INTEGER
|
|
{
|
|
init(&$$);
|
|
$$.type = "int";
|
|
}
|
|
;
|
|
|
|
compound_statement: PBEGIN statement_sequence SEMICOLON END
|
|
{
|
|
init(&$$);
|
|
$$.code = concat(" { /* début du bloc */\n", $2.code, " } /* fin du bloc */\n", NULL);
|
|
}
|
|
;
|
|
statement_sequence: instruction
|
|
{
|
|
init(&$$);
|
|
$$.code = $1.code;
|
|
}
|
|
| statement_sequence SEMICOLON instruction
|
|
{
|
|
init(&$$);
|
|
$$.code = concat($1.code, $3.code, NULL);
|
|
}
|
|
;
|
|
/* INSTRUCTION */
|
|
instruction: identifier ASSIGNMENT expression /* S -> id:=E */
|
|
{
|
|
init(&$$);
|
|
$$.code = concat($3.code, prod(concat($1.place , " = ", $3.place, NULL)), NULL);
|
|
}
|
|
| procedure_statement /* S->procedure(args) */
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| compound_statement /* S -> BEGIN S END */
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| IF expression THEN instruction /* S -> IF THEN */
|
|
{
|
|
$$.after = newLabel();
|
|
$$.code = concat($2.code,
|
|
prod(concat("if (", $2.place, " == 0) goto ", $$.after, NULL)),
|
|
$4.code,
|
|
prod(concat($$.after, ":", NULL)),
|
|
NULL);
|
|
}
|
|
| WHILE expression DO instruction /* S-> WHILE DO */
|
|
{
|
|
$$.before = newLabel();
|
|
$$.after = newLabel();
|
|
$$.code = concat(prod(concat($$.before, ":", NULL)),
|
|
$2.code,
|
|
prod(concat("if (", $2.place, " == 0) goto ", $$.after, NULL)),
|
|
$4.code,
|
|
prod(concat("goto ", $$.before, NULL)),
|
|
prod(concat($$.after, ":", NULL)),
|
|
NULL);
|
|
}
|
|
;
|
|
/* PROCEDURE CALL */
|
|
procedure_statement: identifier /* no actual parameter list */
|
|
{
|
|
init(&$$);
|
|
$$.code = prod(concat($1.place, "()", NULL));
|
|
$$.type = "void";
|
|
}
|
|
| identifier LPAREN actual_parameter_list RPAREN /* with actual argument list */
|
|
{
|
|
init(&$$);
|
|
$$.code = concat($3.code, prod(concat($1.place, "(", $3.place, ")", NULL)), NULL);
|
|
$$.type= "void";
|
|
}
|
|
;
|
|
actual_parameter_list: expression
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| actual_parameter_list COMMA expression
|
|
{
|
|
init(&$$);
|
|
$$.code = concat($1.code, $3.code, NULL);
|
|
$$.place = concat($1.place, ", ", $3.place, NULL);
|
|
}
|
|
;
|
|
/* EXPRESSIONS */
|
|
expression: simple_expression
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| simple_expression relop simple_expression
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " ", $2.code , " ", $3.place, NULL)), NULL);
|
|
}
|
|
;
|
|
simple_expression: term /* E -> T */
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| sign term /* E-> +/- T */
|
|
{
|
|
init(&$$);
|
|
$$.type = $2.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($2.code,
|
|
prod(concat($$.place, " = ", $1.code, " ", $2.place, NULL)),
|
|
NULL);
|
|
}
|
|
| NOT simple_expression /* E-> NOT E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $2.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($2.code,
|
|
prod(concat($$.place, " = ! ", $2.place, NULL)),
|
|
NULL);
|
|
|
|
}
|
|
| simple_expression PLUS simple_expression /* E -> E + E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " + ", $3.place, NULL)), NULL);
|
|
}
|
|
| simple_expression MINUS simple_expression /* E -> E - E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " - ", $3.place, NULL)), NULL);
|
|
}
|
|
| simple_expression MULT simple_expression /* E -> E * E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " * ", $3.place, NULL)), NULL);
|
|
}
|
|
| simple_expression DIV simple_expression /* E -> E / E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " / ", $3.place, NULL)), NULL);
|
|
}
|
|
| simple_expression AND simple_expression /* E -> E AND E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " && ", $3.place, NULL)), NULL);
|
|
}
|
|
| simple_expression OR simple_expression /* E -> E OR E */
|
|
{
|
|
init(&$$);
|
|
$$.type = $1.type; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($1.code, $3.code, prod(concat($$.place, " = ", $1.place, " || ", $3.place, NULL)), NULL);
|
|
}
|
|
| LPAREN expression RPAREN /* E -> (E) */
|
|
{
|
|
$$ = $2; // pass through
|
|
}
|
|
;
|
|
term: identifier
|
|
{
|
|
init(&$$);
|
|
$$.place = $1.place;
|
|
$$.type = $1.type;
|
|
}
|
|
| identifier LPAREN actual_parameter_list RPAREN /* Function call */
|
|
{
|
|
init(&$$);
|
|
$$.type = "int"; // TODO type checking
|
|
$$.place = newTemp($$.type);
|
|
$$.code = concat($3.code,
|
|
prod(concat($$.place, " = ", $1.place, "(", $3.place, ")", NULL)),
|
|
NULL);
|
|
}
|
|
| number
|
|
{
|
|
$$ = $1; // pass through
|
|
}
|
|
| CHARACTER_STRING
|
|
{
|
|
init(&$$);
|
|
$$.type = "char *";
|
|
$$.place = newTemp($$.type);
|
|
$$.code = prod(concat($$.place, " = ", concat("\"", trim($1), "\"", NULL), NULL));
|
|
}
|
|
;
|
|
identifier: IDENTIFIER
|
|
{
|
|
init(&$$);
|
|
$$.place = strdup($1);
|
|
$$.type = getType($1);
|
|
}
|
|
;
|
|
number: INTNUMBER
|
|
{
|
|
init(&$$);
|
|
$$.place = strdup($1);
|
|
$$.type = "int";
|
|
}
|
|
;
|
|
sign: PLUS
|
|
{
|
|
init(&$$);
|
|
$$.code = "+";
|
|
}
|
|
| MINUS
|
|
{
|
|
init(&$$);
|
|
$$.code = "-";
|
|
}
|
|
;
|
|
relop: EQUAL
|
|
{
|
|
init(&$$);
|
|
$$.code = "==";
|
|
}
|
|
| NOTEQUAL
|
|
{
|
|
init(&$$);
|
|
$$.code = "!=";
|
|
}
|
|
| LT
|
|
{
|
|
init(&$$);
|
|
$$.code = "<";
|
|
}
|
|
| GT
|
|
{
|
|
init(&$$);
|
|
$$.code = ">";
|
|
}
|
|
| LE
|
|
{
|
|
init(&$$);
|
|
$$.code = "<=";
|
|
}
|
|
| GE
|
|
{
|
|
init(&$$);
|
|
$$.code = ">=";
|
|
}
|
|
;
|
|
%%
|
|
|
|
/**
|
|
* Provides a yyerror routine which simply reports error line.
|
|
* It is called when the parser finds something not covered by any rule.
|
|
*
|
|
* @param s the error message to print.
|
|
*/
|
|
int yyerror(char * s) {
|
|
fprintf(stderr, "%s:%d: %s: at or before '%s'\n", progname, line_no, s, yytext);
|
|
return 0;
|
|
}
|
|
|