This is an old revision of the document!


TP 8 - Analyse Semantique

Tableau de symboles

Le tableau de symboles représente une structure de données où tous les identifiants trouvés lors de l'analyse sont stockés. Il permet de vérifier les types, de stocker les valeurs et autres paramètres.

Nous utiliserons un dictionnaire javascript.

Nous ajoutons une autre fonction qui nous permet d'ajouter une variable au tableau des symboles.

function addVariable (variable)
{
  symbol_table[variable] = {
    type:'variable',
    value: undefined
  };
}

Nous avons maintenant le parse tree et la table des symboles. Nous devons les retourner tous les deux. La règle de départ renvoie maintenant un objet qui contient le parse tree et la table de symboles.

{
  ast: $1,
  symbol_table: symbol_table
}
alf.l
Newline               \r?\n
Ws                    [ \t]
Number                [0-9]+("."[0-9]+)?
String_value          \"[^\"]*\"
Identifier            [A-Za-z][A-Za-z0-9]*
 
 
%%
 
 
"var"                 { return 'VAR'; }
"of"                  { return 'OF'; }
"int"                 { return 'INT'; }
"float"               { return 'FLOAT'; }
"string"              { return 'STRING'; }
"function"            { return 'FUNCTION'; }
"endfunction"         { return 'END_FUNCTION'; }
"="				      { return '='; }
"-"                   { return '-'; }
"+"                   { return '+'; }
"*"                   { return '*'; }
"/"                   { return '/'; }
"("                   { return 'LP'; }
")"	                  { return 'RP'; }
','				      { return ','; }
{Ws}                  { /*skip whitespace*/ }
{Newline}             { return 'NEWLINE'; }
{Number}              { return 'NUMBER'; }
{String_value}        { return 'STRING_VALUE'; }
{Identifier}          { return 'IDENTIFIER'; }
alf.y
%left '+' '-'
%left '*' '/' 
 
%{
// function for grammar rule
var symbol_table = {};
 
function addVariable (variable, type)
{
  symbol_table[variable] = {
    type: type,
    value: undefined
  };
}
 
function isDefined (variable)
{
   // add here the code to verify if a variable is already in the symbol table
}
 
%}
 
%% 
 
start
: expressions 	{
					return { ast: {
						type: 'program',
						elements: $1,
						line: yylineno + 1
                                             },
                                             symbol_table: symbol_table
					};
            	}
;
 
expressions
: expressions NEWLINE statement		{
										$1.push($3); // add the expression to the array produced by expressions ($1)
										$$ = $1;
									}
| statement							{
										$$ = [];
										$$.push($1); // an array with one element
									}
;
 
statement
: expr
| variable
| assign
| function
| function_run
;
 
 
expr
: '(' expr ')'			{
							$$ = {
								type: 'expr',
								value: $2,
								line: yylineno + 1
							};
						}
| expr '+' expr			{
							$$ = {
								type: 'expr',
								op: $2,
								left: $1,
								right: $3,
								line: yylineno + 1
							};
						}
| expr '-' expr 		{
							$$ = {
								type: 'expr',
								op: $2,
								left: $1,
								right: $3,
								line: yylineno + 1
							};
						}
| expr '*' expr			{ 
							$$ = {
								type: 'expr',
								op: $2,
								left: $1,
								right: $3,
								line: yylineno + 1
							};
						}
| expr '/' expr 		{
							$$ = {
								type: 'expr',
								op: $2,
								left: $1,
								right: $3,
								line: yylineno + 1
							};
						}
| NUMBER 				{ 
							$$ = {
									type: 'int',
									value: $1,
									line: yylineno + 1
							};
						}
| IDENTIFIER 			{
							if(!isDefined($1)) {
								return 'ERROR at line ' + (yylineno + 1) + ': ' + $1 + ' is not defined';
							}
 
							$$ = {
								type: 'variable',
								value: $1,
								line: yylineno + 1
							};
						}
| STRING_VALUE 			{
							$$ = {
									type: 'string',
									value: $1,
									line: yylineno + 1
							};
						}
;
 
variable: VAR variables {
							$$ = {
								type: 'var',
								variables: $2,
								line: yylineno + 1
							};
						}
;
 
variables
: variables ',' IDENTIFIER			{
										// add the variable to the symbol table
 
										$1.push({
											id: $3,
											line: yylineno + 1
										});
										$$ = $1;
									}
| IDENTIFIER 						{
										// add the variable to the symbol table
 
										$$ = [];
										$$.push({
											id: $1,
											line: yylineno + 1
										})	
									}
| variables ',' IDENTIFIER OF type 	{
										// add the variable to the symbol table
 
										$1.push({
											id: $3,
											type: $5,
											line: yylineno + 1
										});
										$$ = $1;
									}
| IDENTIFIER OF type 				{
										// add the variable to the symbol table
 
										$$ = [];
										$$.push({
											id: $1,
											type: $3,
											line: yylineno + 1
										});	
									}
;
 
type
: INT 
| FLOAT
| STRING
;
 
assign
: IDENTIFIER '=' expr 	{
							if(!isDefined($1)) {
								return 'ERROR at line ' + (yylineno + 1) + ': ' + $1 + ' is not defined';
							}
 
							$$ = {
								type: 'assign',
								to: {
									id: $1,
									line: yylineno + 1
								},
								from: $3,
								line: yylineno + 1
							};
						}
;
 
function
: FUNCTION IDENTIFIER '(' parameters ')' NEWLINE expressions NEWLINE END_FUNCTION 	{
																						$$ = {
																							type: 'function_declaration',
																							id: $2,
																							parameters: $4,
																							expressions: $7,
																							line: yylineno + 1
																						};																			
																					}
;
 
parameters
: parameters ',' IDENTIFIER OF type 	{
											$1.push({
												id: $3,
												type: $5,
												line: yylineno + 1
											});
											$$ = $1;
										}
| IDENTIFIER OF type 					{
											$$ = [];
											$$.push({
												id: $1,
												type: $3,
												line: yylineno + 1
											});
										}
|										{
											$$ = [];
										}
;
 
function_run
: IDENTIFIER '(' parameters_run ')' 	{
											$$ = {
												type: 'function_run',
												id: $1,
												parameters: $3,
												line: yylineno + 1
											};
										}
;
 
parameters_run
: parameters_run ',' expr  				{
											$1.push($3);
											$$ = $1;
										}
| expr 									{
											$$ = [];
											$$.push($1);
										}
|										{
											$$ = [];
										}
;
index.js
"use strict";
 
var parser = require ('./alf.js').parser;
var fs = require ('fs');
 
try {
    var data = fs.readFileSync('ex1.txt').toString();
    console.log(JSON.stringify(parser.parse (data), null, 2));
}
catch (e) {
    console.log (e.message);
}

Exercises

  1. Téléchargez la structure du TP. Ajoutez une nouvelle regle dans la grammaire, afin que la programme reconnaisse aussi la déclaration des listes. Une liste est définie de la maniere suivante:
     list array_name = [el1, el2, ... ] 

    La déclaration de la liste doit etre ajoutée aussi dans l'AST, let parametres étant: type (nom de la regle), array (nom de la liste), elements (liste des éléments de la liste - chaque élément est une expression) et line. Testez avec le fichier ex1.txt. (1p)

  2. En suivant les lignes marquées par TODO 2, ajoutez les variables et leur type au tableau des symboles. Testez avec le fichier ex2.txt (2p).
  3. Si une variable est définie plusieurs fois, retournez sur l'écran une erreur et arretez le programme. Suivez les lignes marquées par TODO 3 et puis testez avec le ficher ex3.txt (2p)
  4. Pour chaque type d'expression, vérifiez le type de chaque élément (int, float ou string). Si l'operateur est une variable, vérifiez son type en utilisant le tableau des symboles. Retournez une erreur et arretez l'exécution du programme si vous ne pouvez pas calculer la valeur de l'expression (par exemple, toute opération entre les string et les nombres, sauf la somme). (Hint: Vous pouvez définir une fonction supplémentaire qui fait toutes les validations et seulement l'appeler pour chaque regle). Suivez les lignes avec TODO 4 et testez avec ex4.txt. (3p).
  5. Pour les variables qui n'ont pas recu un type au moment de la déclaration, déterminez le type lorsque la variable obtient une valeur (regle assign). Vous devrez déterminer le type de chaque expression (exprType pour $$) en tenant compte du type de chaque opérande. (Hint: Si l'un des opérandes est nombre réel/string, le résultat sera réel/string. Vous pouvez implémenter une fonction qui fait les vérifications et l'appeler pour déterminer le type de chaque expression). Testez avec le fichier ex5.txt. Suivez les lignes avec TODO 5. (1p).
  6. Ajoutez la définition de fonction dans la table des symboles, de facon similaire a l'ajout d'une variable. Chaque parametre doit etre ajouté au tableau des symboles avec le type parameter. L'entrée de la table de symboles recevra la fonction et la liste des paramètres de la fonction. Testez avec ex6.txt. Suivez les lignes marquées par TODO 6. (2p)

Solutions

alf/laboratoare/08.1586156877.txt.gz · Last modified: 2020/04/06 10:07 by diana.ghindaoanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0