This is an old revision of the document!


TP 8 - Analyse Semantique

Table de symboles

La table 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 à la table 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. Ajoutez les variables et le type au tableau des symboles (2p).
  2. Afficher une erreur si une variable est redéfinie. (2p)
  3. Pour une expression, calculer le type de chaque élément (int, float ou string) et afficher une erreur si vous ne pouvez pas calculer la valeur de l'expression (ex: int divisé par 'string') (3p).
  4. Pour les variables sans type, déterminez le type lorsque la variable obtient une valeur (1p).
  5. Ajoutez la definition de fonction dans la table des symboles. L'entrée de la table de symboles aura la fonction et la liste des paramètres de la fonction. (2p)

Solutions

alf/laboratoare/08.1554403025.txt.gz · Last modified: 2019/04/04 21:37 by teodor.deaconu
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