This is an old revision of the document!
Le code de trois adresses est un moyen d'écrire des instructions. Chaque instruction consiste en:
Ws [ \t]
Number [0-9]+("."[0-9]+)?
String_value \"[^\"]*\"
Identifier [A-Za-z][A-Za-z0-9]*
Newline \r?\n
%%
"def" { return 'DEF'; }
"int" { return 'INT'; }
"float" { return 'FLOAT'; }
"string" { return 'STRING'; }
"function" { return 'FUNCTION'; }
"end" { return 'END'; }
"=" { 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'; }
%left '+' '-'
// * and / have higher priority
%left '*' '/'
%%
start: expressions {
$$ =
{
type:'script',
statements: $1
};
return $$;
};
expressions: statement NEWLINE expressions {
$3.splice (0, 0, $1);
$$ = $3;
}
| statement NEWLINE {
$$ = [$1];
}
| statement {
$$ = [$1];
};
statement: expr {
}
| assign {
}
| function_run {
};
expr: '(' expr ')' {
$$ = $2;
}
| expr '+' expr {
$$ = {
type: 'expression',
op: '+',
left: $1,
right: $3
};
}
| expr '-' expr {
$$ = {
type: 'expression',
op: '-',
left: $1,
right: $3
};
}
| expr '*' expr {
$$ = {
type: 'expression',
op: '*',
left: $1,
right: $3
};
}
| expr '/' expr {
$$ = {
type: 'expression',
op: '/',
left: $1,
right: $3
};
}
| IDENTIFIER
{
$$ = {
type: 'identifier',
value: $1
};
}
| NUMBER {
$$ = {
type: 'nr',
value: parseFloat ($1)
};
}
| STRING_VALUE {
$$ = {
type: 'str',
value: $1.substring (1, $1.length-2)
};
};
assign: IDENTIFIER '=' expr
{
$$ = {
type: 'set',
to: $1,
from: $3
};
}
| IDENTIFIER '=' function_run
{
$$ = {
type: 'set',
to: $1,
from: $3
};
};
function_run: IDENTIFIER 'LP' parameters_run 'RP' {
$$ = {
type: 'fn_run',
id: $1,
parameters: $3
};
};
parameters_run: expr ',' parameters_run
{
$3.splice (0, 0, $1);
$$ = $3;
}
| expr
{
$$ = [$1];
}
| {
$$ = [];
};
"use strict"; // import fs for reading var fs = require ('fs'); // import the generated Parser var parser = require ('./alf.js').parser; var str = fs.readFileSync (process.argv[2], 'UTF-8'); var variable_id = 0; // get a new temporary variable function nextVar () { return 'v' + variable_id++; } function writeThreeAddressCode (node) { if (node.type === 'script') { for (var statement of node.statements) { writeThreeAddressCode(statement); } } else if (node.type === 'fn_run') { /**TODO: * generate the three address code for each parameter of the node.parameters array * write on the screen the three address code for each parameter * node.result will be nextVar() * write on the screen the three address code for function call */ } else if (node.type === 'nr') { // the result for a number is the number itself node.result = node.value; } else if (node.type === 'set') { /** TODO: * generate the three address code for node.from * write on the screen the three address code for assign */ } else if (node.type === 'identifier') { /*TODO: the result is the value of the identifier */ } else if (node.type === 'expression') { if (node.left !== undefined && node.right !== undefined) { writeThreeAddressCode (node.left); writeThreeAddressCode (node.right); // node.left.result is the result of node.left // node.right.result is the result of node.right /** TODO: * node.result will be nextVar() * write on the screen the three address code based on result, left result, right result and operator*/ } } } var ast = parser.parse (str); console.log (JSON.stringify(ast, null, 4)); writeThreeAddressCode(ast);
Nous voulons transformer l'AST suivant dans une liste de Three Address Code.
if (a > 0 && a < 10000) { result = 'pozitive'; } else { result = 'negative'; }
function power (nr, e) { let n = 1; for (let i=0; i<e; i++) n = n * nr; return nr; } power (7, 2);