This is an old revision of the document!


TP 7 - AST

AST

L'AST est un arbre représentant le format source. Il est indépendant de la forme de la grammaire. L'AST peut être une transformation du parse tree ou peut être généré directement par l'analyseur.

Dans l'AST, chaque règle de langue a comme corespondant un noeud.

Pour ce laboratoire, vous pouvez définir le format de nœud AST comme vous le souhaitez. Un point de départ est le suivant:

{
  type:"node_type",
  ...
}

Exemple d'AST

Pour le code suivant

2+3
var a of int
function fid (a of int)
5+6
endoffunction

Nous pouvons décrire l'AST suivant

{
  type: 'program',
  elements:
  [
    {
      type:'expr',
      op: '+',
      left: {
        type: 'int',
        value: 2
      },
      right: {
        type: 'int',
        value: 3
      }
    },
    {
      type: 'var',
      variables: [
        {
          id: 'a',
          type: 'int'
        }
      ]
    },
    {
      type: 'function_definition',
      id: 'fid',
      parameters:[
        {
          id:'a',
          type:'int'
        }
      ]
    }
  ]
}

Grammaire pour le langage

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 '+' '-'
// * and / have higher priority
%left '*' '/' 
 
%{
// function for grammar rule
function rule (rule_name, items)
{
  return {
    rule: rule_name,
    items: items
  };
}
 
// function for token
function token (token_name, value)
{
  return {
    token: token_name,
    value: value
  };
}
 
 
%}
 
%% 
 
start: expressions { 
				$$ = rule ('start', [$1]);
				return $$; 
				// AST
				// return {
				//    type: 'program',
				//    elements: $1
				// }
            };
 
expressions: statement NEWLINE expressions	{
											$$ = rule ('statement', [$1, token ('NEWLINE', $2), $3]);
											// AST 
											// $3.splice (0, 0, $1); // add the expression to the array produced by expressions ($3)
											// $$ = $3;
										}
			| statement NEWLINE		{
									$$ = rule ('statement', [$1, token ('NEWLINE', $2)]);
									// AST
									// $$ = [$1]; // an array with one element
								}
			| statement	{
						$$ = rule ('statement', [$1]);
						// AST
						// $$ = [$1]; // an array with one element
					};
 
statement:  expr  {
                    $$ = rule ('statement', [$1]);
                }
            | variable {
                        $$ = rule ('statement', [$1]);
                    }
            | assign {
                        $$ = rule ('statement', [$1]);
                    }
            | function {
            			$$ = rule ('function', [$1]);
            		}
			| function_run {
            			$$ = rule ('function_run', [$1]);
            		};
 
 
expr:	'LP' expr 'RP'	{
							$$ = rule ('expr', [token ('(', $1), $2, token (')', $3)]);
						}
	  | expr '+' expr	{ 
				$$ = rule ('expr', [$1, token ('+', $2), $3]);
			}
      | expr '-' expr 	{
    				$$ = rule ('expr', [$1, token ('-', $2), $3]);
      			}
      | expr '*' expr	{ 
    			$$ = rule ('expr', [$1, token ('*', $2), $3]);
			}
      | expr '/' expr 	{
    				$$ = rule ('expr', [$1, token ('/', $2), $3]);
      			}
      | NUMBER 	{ 
	  		// $1 is string so we store its float value
	  		$$ = token ('NUMBER', parseFloat ($1));
	  	}
	  | IDENTIFIER {
			// store the variable
	  		$$ = token ('IDENTIFIER', $1);
		}
	   | STRING_VALUE {
			// store the variable
			// get the value of the string without the quotes
	  		$$ = token ('STRING_VALUE', $1.substring (1, $1.length-2));
		};
 
variable:	VAR variables
			{
				$$ = rule ('variable', [token ('VAR', $1), $2]);
			};
 
variables:	IDENTIFIER ',' variables   
			{
				$$ = rule ('variables', 
				           [
				              token ('IDENTIFIER', $1), 
				              token (',', ','), 
				              $3
				           ]
				          );
 
			}
		| IDENTIFIER 
			{
				$$ = token ('IDENTIFIER', $1);
 
			}
		| IDENTIFIER OF type ',' variables   
			{
				$$ = rule ('variables', 
				           [
				              token ('IDENTIFIER', $1), 
				              token ('OF', 'of'),
				              $3,
				              token (',', ','), 
				              $5
				           ]
				          );
 
			}
		| IDENTIFIER OF type
			{
				$$ = rule ('variables', 
    			           [
    			              token ('IDENTIFIER', $1), 
    			              token ('OF', 'of'),
    			              $3
    			           ]
    			          );
 
			};
 
type:   INT 
            {
                $$ = token ('INT', 'int');
            }
        | FLOAT
            {
                $$ = token ('FLOAT', 'float');
            }
        | STRING
            {
                $$ = token ('STRING', 'string');
            };
 
assign: IDENTIFIER '=' expr
            {
                $$ = rule ('assign', 
				           [
				              token ('IDENTIFIER', $1), 
				              token ('=', '='), 
				              $3
				           ]
				          );
 
            };
 
 
 
function: FUNCTION IDENTIFIER 'LP' parameters 'RP' NEWLINE expressions END_FUNCTION {$$ = rule ('function', [token('FUNCTION', $1), token('IDENTIFIER', $2), token('(', $3), $4, token(')', $5), token('NEWLINE', $6), $7, token('END_FUNCTION', $8)]);};
 
parameters: IDENTIFIER OF type ',' parameters
				{
					$$ = rule ('parameters', [$1, token ('OF', 'of'), $3, token (',', $4), $5]);
				}
			| IDENTIFIER OF type
				{
					$$ = rule ('parameters', [$1, token ('OF', 'of'), $3]);
				}
			|	{
					$$ = token ('EMPTY', '');
				};
 
function_run: IDENTIFIER 'LP' parameters_run 'RP' { $$ = rule ('function_run', [token ('IDENTIFIER', $1), token ('(', $2), $3, token (')', $4)]);
						};
 
parameters_run: expr ',' parameters_run
				{
					$$ = rule ('parameters_run', [$1, token (',', $2), $3]);
				}
			| expr
				{
					$$ = rule ('parameters_run', [$1]);
				}
			|	{
					$$ = token ('EMPTY', '');
				};

Le javascript

main.js
"use strict";
 
// import fs for reading 
var fs = require ('fs');
 
// import the generated Parser
var parser = require ('./program.js').parser;
 
var str = fs.readFileSync (process.argv[2], 'UTF-8');
 
// add a text to the parser
try
{
        // run the parser using a string, why are the values printed upside down?
	var info = parser.parse (str);
	console.log ('AST');
	console.log (JSON.stringify (info, null, 4));
}
catch (e)
{
        // display the error message and data
// 	console.log ('You have an error at line '+(e.hash.line+1)+' at position '+e.hash.loc.first_column);
// 	console.log (e.message);
    console.log (e);
}

Exemple de program

var a of int
a=10
function f ()
var s of int
endfunction

Exercises

L'exemple inclus dans la structure du tp génère le parse tree pour le langage du fichier script.alf. Utilisez la même source pour tous les exercices, écrivez des fonctions pour toutes les actions et ajoutez-les dans le meme fichier .y. Écrivez les erreurs sur l'écran.

  1. Téléchargez/clonez la structure du tp. Ajoutez des numéros de ligne au parse tree (Indice: modifiez la fonction rule() de sorte qu'elle accèpte comme paramètre yylineno pour chaque règle) (2p)
  2. Modifiez la grammaire de l'exemple pour générer un AST pour les expressions. Suivez les explications marquées par TODO 2. Pour chaque règle correspondant a expression/expression_string, on doit attribuer a la variable $$ un objet avec les propriétés suivantes: type (nom de la règle), op (valeur de l'opérateur), left (valeur du premier opérande), right (valeur du deuxième opérande). Pour chaque feuille, $$ recevra un objet contenant le type et la valeur du noeud. Au moment de la génération de l'AST, il faut commenter l'appel des fonctions rule et token. L'AST pour les expressions doit etre similaire a celui présenté dans la section Exemple d'AST. Pour tester la correctitude de votre grammaire, parsez le contenu du fichier ex2.txt. (3p)
  3. Modifiez la grammaire de l'exemple afin de générer un AST pour tout le programme. Suivez les indications marquées par TODO 3. Parsez le contenu du fichier ex3.txt. (5p)
  4. Bonus Vérifiez que toutes les variables utilisées dans les expressions sont définies avant. Parsez le contenu du fichier ex4.txt pour vérifier votre grammaire. (1p)
alf/laboratoare/07.1585507756.txt.gz · Last modified: 2020/03/29 21:49 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