Site icon Antonio Lamorgese

Come creare un interprete come TypeScript

Come creare un interprete come TypeScript

In questo tutorial, realizzerai un interprete che converte un’istruzione del linguaggio TypeScript in JavaScript utilizzando Flex per il lexer e Bison per il parser. Il tuo traduttore di codice prenderà in input un file TypeScript e genererà un file JavaScript corrispondente. Esattamente quello che fa Typescript con il comando “tsc” che è l’abbreviazione di TypeScript Compiler ed è lo strumento principale per compilare il codice TypeScript in JavaScript.

1. Installazione degli strumenti necessari

Per la progettazione di questo interprete devi assicurati di avere installati Flex e Bison. Di seguito troverai le istruzioni da eseguire per installare questi due strumenti gratuiti sui più diffusi sistemi operativi:

Linux (Ubuntu/Debian)

sudo apt update
sudo apt install flex bison gcc

MacOS (con Homebrew)

brew install flex bison gcc

Windows (con MSYS2 e pacman)

MSYS2 è un ambiente che fornisce una shell Unix-like su Windows e permette di installare strumenti GNU, come Flex e Bison, utilizzando il gestore di pacchetti pacman (simile a quello di Arch Linux).

Innanzitutto scarica e installa MSYS2 dal sito ufficiale: https://www.msys2.org/. MSYS2 (acronimo di Minimal System 2) è un ambiente di sviluppo open-source per Windows, che fornisce strumenti Unix-like per compilare, eseguire e gestire software in modo simile a un sistema dotato di kernel Linux. Basato su Cygwin e MinGW-w64, MSYS2 offre una shell Bash, in poche parole un terminale, e un gestore di pacchetti Pacman, simile a quello di Arch Linux.

Dopo l’installazione, apri MSYS2 MSYS, e aggiorna il package manager con il comando:

pacman -Syu

Nota: Dopo questo comando, MSYS2 potrebbe chiudersi automaticamente. Riaprilo e riesegui pacman -Syu per completare l’aggiornamento.

Ora, devi installare Flex, Bison e GCC eseguendo questo semplice comando all’interno del terminale MSYS2:

pacman -S mingw-w64-x86_64-flex mingw-w64-x86_64-bison mingw-w64-x86_64-gcc

Assicurati che il percorso C:\msys64\mingw64\bin sia aggiunto alla variabile d’ambiente PATH di Windows, in modo da poter eseguire Flex e Bison da qualsiasi posizione all’interno del file system.


Leggi anche: Creare un linguaggio di programmazione con Python


2. Creazione del Lexer con Flex

Il lexer analizza il codice TypeScript e suddivide le parole chiave, gli identificatori e i simboli in token. A questo punto crea un file di nome “lexer.l”, copia e incolla il seguente codice al suo interno:

File: lexer.l

%{

// Include il file header generato da Bison
#include "parser.tab.h"
#include <stdio.h>
%}

// Evita problemi con l'input di Flex
%option noyywrap

%%
Let       { return LET; }
[a-zA-Z_][a-zA-Z0-9_]*  { yylval.str = strdup(yytext); return IDENTIFIER; }
[0-9]+    { yylval.num = atoi(yytext); return NUMBER; }
=         { return ASSIGN; }
;         { return SEMICOLON; }
[ \t\n]   { /* Ignora spazi e nuove righe */ }
.         { printf("Carattere sconosciuto: %s\n", yytext); }

%%

3. Creazione del Parser con Bison

Il parser analizza la sequenza di token, restituiti dal lexer, e genera un file JavaScript corrispondente.

File: parser.y

%{

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void yyerror(const char *s);
int yylex();
extern int yylineno;
FILE *outputFile;

%}

%union {
    char *str;
    int num;
}

%token LET IDENTIFIER ASSIGN NUMBER SEMICOLON
%type <str> IDENTIFIER
%type <num> NUMBER

%%

program:
    statement { fprintf(outputFile, "var %s = %d;\n", $1, $3); }
    ;

statement:
    LET IDENTIFIER ASSIGN NUMBER SEMICOLON { $$ = $2; $$ = $4; }
    ;

%%

void yyerror(const char *s) {
    fprintf(stderr, "Errore: %s alla riga %d\n", s, yylineno);
}

4. Creazione del File di Esecuzione

File: main.c

#include <stdio.h>
#include <stdlib.h>
extern FILE *yyin;
extern FILE *outputFile;
int yyparse();

int main(int argc, char *argv[]) {
    if (argc < 3) {
        fprintf(stderr, "Usa: %s input.ts output.js\n", argv[0]);
        return 1;
    }

    yyin = fopen(argv[1], "r");
    if (!yyin) {
        perror("Errore nell'apertura del file sorgente");
        return 1;
    }

    outputFile = fopen(argv[2], "w");
    if (!outputFile) {
        perror("Errore nella creazione del file di output");
        fclose(yyin);
        return 1;
    }

    yyparse();
    fclose(yyin);
    fclose(outputFile);
    return 0;

}

5. Compilazione e Esecuzione

Ora puoi compilare il tuo interprete di codice in Linux, macOS e Windows. Prima però crea il file “input.ts” con questa istruzione: “Let x = 42;”e successivamente l’interprete creerà il file “output.js” con questa istruzione: “var x = 42;” cioè con l’istruzione Typescript convertita in Javascript.

Linux/macOS

bison -d parser.y -o parser.tab.c
flex -o lexer.c lexer.l
gcc -o transpiler lexer.c parser.tab.c main.c -lfl
./transpiler input.ts output.js

Windows (MSYS2)

bison -d parser.y -o parser.tab.c
flex -o lexer.c lexer.l
gcc -o transpiler.exe lexer.c parser.tab.c main.c -lfl
./transpiler input.ts output.js

6. Conclusione

Hai creato un interprete di codice che converte da TypeScript in JavaScript utilizzando Flex e Bison. Ora, per migliorarlo, potresti implementare la gestione di tipi TypeScript. Rivedi pazientemente quanto è stato fatto nei file lexer.l e parser.y e aggiungi le istruzioni necessarie per integrare la conversione di altre istruzioni. 

Exit mobile version