Le but de ce devoir est de traduire un Langage Alf fourni sous forme de fichier AST avec des données sémantiques dans Web Assembly. Votre programme recevra deux paramètres: le fichier source (le fichier des devoirs précédents, avec la table des symboles, l'AST et la liste des erreurs) et le fichier de sortie. Vous n'avez pas besoin d'une version correcte du devoir 4! Les fichiers de test ont déjà été générés et vous pouvez les trouver sur github. Les programmes auront n'importe quel type de variable. La concaténation de chaînes n'est pas fournie (à l'exception de quelques tests de test).
node main.js fisier.alf.json fisier.alf.opt.json fisier.wat [optimisations,]
Vous devez écrire deux fichiers:
Les variables sont divisées en deux types:
Nous en discuterons en détail. Chaque type de variable d'ALF doit être traduit dans un type WebAssembly suivant le tableau.
ALF Type | WebAssembly Type |
---|---|
int | i32 |
real | i32 |
character | i32 |
bool | i32 |
string | a 256 bytes memory space |
array (type:[from – to]) | a bytes * length memory space |
struct | a sum of the struct's properties bytes memory space |
Toutes ces valeurs sont représentées par i32.
Toutes ces valeurs sont représentées par f32.
Toutes ces valeurs sont représentées par i32, en ascii.
La valeur bool est représentée par:
La représentation utilisée pour les chaînes est de type Pascal et a une longueur de 256 octets:
Les variables peuvent être attribuées différemment en fonction de leur type et de leur position. Les types d'allocation sont globla
, data
, param
, local
, stack
et relocated
.
Variable Type | Variable Location | Allocation Type |
---|---|---|
simple | script | global |
complex | script | data |
string | script | data |
simple | function parameter | param |
complex | function parameter | param (sent as pointer, see note) |
string | function parameter | param (sent as pointer, see note) |
simple | function | local |
complex | function | stack |
string | function | stack |
simple | if, for, loop | relocated |
complex | if, for, loop | relocated |
string | if, for, loop | relocated |
Les variables allouées comme global
sont des variables simples du script principal. Celles-ci seront attribuées en tant qu'instructions (global $title type)
. Exemple: simple.alf simple.wat
L'accès à ces variables se fait à l'aide des instructions global.set
et global.get
.
Les variables allouées comme data
sont des variables complexes et des chaînes du script principal. Ceux-ci seront alloués comme dans l'espace mémoire. Chaque variable de ce type aura un paramètre address
avec la position de la variable en mémoire. Exemple: simple.alf simple.wat.
L'accès à ces variables se fait à l'aide des instructions i32.load
et i32.store
pour charger et stocker l'adresse de variable dans la pile de données.
(global $title i32 (i32.const address_of_variable)
pour faciliter la lecture du code.
L'allocation de paramètres est utilisée pour les paramètres de fonction de type simple. Celles-ci seront allouées en tant qu'instructions (param $title type)
dans la définition de la fonction. Exemple: definition_variables.alf definition_variables.wat.
L'accès à ces variables se fait à l'aide des instructions local.set
et local.get
.
Les variables allouées comme local sont de simples variables issues d'une fonction. Celles-ci seront affectées en tant qu'instructions (local $title type)
dans la définition de la fonction. Exemple: definition_variables.alf definition_variables.wat.
L'accès à ces variables se fait à l'aide des instructions local.set
et local.get
.
Les variables attribuées à la pile sont des variables complexes et des chaînes d'une fonction. Ceux-ci seront alloués comme dans l'espace mémoire d'une pile simulée. Chaque variable de ce type aura un paramètre address
avec la position de la variable en mémoire liée à un pointeur de base de pile.
Pour simuler une pile, vous devez déclarer une variable globale (dans notre exemple $stack_pointer
) et une variable locale dans chaque fonction (dans notre exemple $base_pointer
). Chaque fois que vous entrez une fonction, stockez la valeur de $stack_pointer
dans $base_pointer
. Chaque fois que vous quittez une fonction (retour ou fin de fonction), retournez le $stack_pointer
d'origine à partir de $base_pointer
.
Les adresses variables sont calculées par rapport au $base_pointer
. Par exemple, si vous avez une variable avec l'adresse 100, l'adresse réelle de la variable sera $base_pointer
+ 100.
Exemple: definition_variables_stack.alf definition_variables_stack.alf.wat.
(local $title i32)
et définir sa valeur comme (local.set $title address_of_variable)
pour faciliter la lecture du code.
Les variables de type relocated sont toutes les variables déclarées dans un if, loop ou for. Celles-ci seront déplacées (relocated) en tant que variables globales si l'instruction est dans un script ou en tant que variables locales si l'instruction est dans une fonction. La variable sera renommée en $(node.symbol_table)+_+variable.title
.
Exemple: local_variable.alf local_variable.alf.wat
Votre script principal (section de script
de l'ast sémantique) sera la fonction dans webassembly. Le nom de la fonction dépend de vous.
Une valeur est un nombre entier, un nombre réel, un logique (true ou false) ou une chaîne de caractères.
Certaines fonctions de la table des symboles ont un paramètre use
. Cela signifie que ces fonctions sont importées du module déclaré dans la propriété use
.
Exemple: 2_simple/real_number.alf real_number.alf.json real_number.alf.wat
Toutes les constantes string (valeurs) sont stockées dans la mémoire principale juste après les variables globales. Vous pouvez utiliser (data (i32.const address) “\SSvalue”)
, où SS est la valeur base16 de la longueur. Le premier octet de la chaîne représente la longueur de la chaîne.
Implémentez le devoir de manière à ce qu'ils effectuent les optimisations suivantes:
Pour le bonus, il y a 2 parametres supplementaires dans la ligne de commande:
node main.js fisier.alf.json fisier.alf.opt.json fisier.wat [fold_constants] [unused]