compile
:
1 package PL::Tutu; 2 use 5.008004; # Versión mínima de Perl 5.84 3 use strict; # Variables deben ser declaradas, etc. 4 use warnings; # Enviar warnings 5 use IO::File; 6 use Carp; # Provee alternativas a "die" and "warn" 7 8 require Exporter; 9 10 our @ISA = qw(Exporter); # Heredamos los métodos de la clase Exporter 11 our @EXPORT = qw( compile compile_from_file); # Estas funciones serán exportadas 12 our $VERSION = '0.01'; # Variable que define la versión del módulo 13 14 our %symbol_table; # La tabla de símbolos $symbol_table{x} contiene 15 our $data; # la información asociada con el objeto 'x' 16 our $target; # tipo, dirección, etc. 17 our @tokens; # La lista de terminales 18 our $errorflag; 19 our ($lookahead, $value); # Token actual y su atributo 20 our $tree; # referencia al objeto que contiene 21 our $global_address; # el árbol sintáctico 22 23 # Lexical analyzer 24 package Lexical::Analysis; 25 sub scanner { 26 } 27 28 package Syntax::Analysis; 29 sub parser { 30 } 31 32 package Machine::Independent::Optimization; 33 sub Optimize { 34 } 35 36 package Code::Generation; 37 sub code_generator { 38 } 39 40 package Peephole::Optimization; 41 sub transform { 42 } 43 44 package PL::Tutu; 45 sub compile { 46 my ($input) = @_; # Observe el contexto! 47 local %symbol_table = (); 48 local $data = ""; # Contiene todas las cadenas en el programa fuente 49 local $target = ""; # target code 50 local @tokens =(); # "local" salva el valor que será recuperado al finalizar 51 local $errorflag = 0; # el ámbito 52 local ($lookahead, $value) = (); 53 local $tree = undef; # Referencia al árbol sintÃctico abstracto 54 local $global_address = 0; # Usado para guardar la Ãltima direcciÃn ocupada 55 56 ########lexical analysis 57 &Lexical::Analysis::scanner($input); 58 59 ########syntax (and semantic) analysis 60 $tree = &Syntax::Analysis::parser; 61 62 ########machine independent optimizations 63 &Machine::Independent::Optimization::Optimize; 64 65 ########code generation 66 &Code::Generation::code_generator; 67 68 ########peephole optimization 69 &Peephole::Optimization::transform($target); 70 71 return \$target; #retornamos una referencia a $target 72 } 73 74 sub compile_from_file { 75 my ($input_name, $output_name) = @_; # Nombres de ficheros 76 my $fhi; # de entrada y de salida 77 my $targetref; 78 79 if (defined($input_name) and (-r $input_name)) { 80 $fhi = IO::File->new("< $input_name"); 81 } 82 else { $fhi = 'STDIN'; } 83 my $input; 84 { # leer todo el fichero 85 local $/ = undef; # localizamos para evitar efectos laterales 86 $input = <$fhi>; 87 } 88 $targetref = compile($input); 89 90 ########code output 91 my $fh = defined($output_name)? IO::File->new("> $output_name") : 'STDOUT'; 92 $fh->print($$targetref); 93 $fh->close; 94 1; # El último valor evaluado es el valor retornado 95 } 96 97 1; # El 1 indica que la fase de carga termina con éxito 98 # Sigue la documentación ...
Vamos a añadir un script que use el módulo
PL::Tutu
para asi poder ejecutar nuestro compilador:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/$ mkdir scripts lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ cd scripts/A continuación creamos dos versiones del compilador
tutu.pl
y tutu
y un programa de prueba test01.tutu
:
... # despues de crear los ficheros lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ ls test01.tutu tutu tutu.pl lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ cat tutu.pl #!/usr/bin/perl -w -I../lib/ use PL::Tutu; PL::Tutu::compile_from_file(@ARGV);
El programa tutu
ilustra otra forma de conseguir que el intérprete
Perl busque por la librería que está siendo desarrollada, mediante el
uso de use lib
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ cat tutu #!/usr/bin/perl -w use lib ('../lib'); use PL::Tutu; &PL::Tutu::compile_from_file(@ARGV);
Una tercera forma (la que recomiendo):
$ export PERL5LIB=~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/lib $ perl -MPL::Tutu -e 'PL::Tutu::compile_from_file("test01.tutu")'
Ahora tenemos que añadir estos ficheros en MANIFEST
para que formen
parte del proyecto. En vez de eso lo que podemos hacer es crear un fichero
MANIFEST.SKIP
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ cat MANIFEST.SKIP \.o$ ^\.cvsignore$ /\.cvsignore$ \.cvsignore$ CVS/[^/]+$ \.svn\b ^Makefile$ /Makefile$ ^blib/ \.swp$ \.bak$ \.pdf$ \.ps$ \.sal$ pm_to_blib \.pdf$ \.tar.gz$ \.tgz$ ^META.yml$Ahora al hacer
make manifestse crea un fichero
MANIFEST
que contiene los caminos
relativos de todos los ficheros
en la jerarquía cuyos nombres no casan con una de las expresiones
regulares en MANIFEST.SKIP
.
Para saber mas sobre MANIFEST
léa
[4].
No recomiendo el uso de MANIFEST.SKIP
. Prefiero un control manual de los
ficheros que integran la aplicacion.
Es necesario indicarle a Perl que los ficheros añadidos son ejecutables.
Esto se hace mediante el parámetro EXE_FILES
de WriteMakefile
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ cat Makefile.PL use 5.008004; use ExtUtils::MakeMaker; # See lib/ExtUtils/MakeMaker.pm for details of how to influence # the contents of the Makefile that is written. WriteMakefile( NAME => 'PL::Tutu', VERSION_FROM => 'lib/PL/Tutu.pm', # finds $VERSION PREREQ_PM => {}, # e.g., Module::Name => 1.1 EXE_FILES => [ 'scripts/tutu.pl', 'scripts/tutu' ], ($] >= 5.005 ? ## Add these new keywords supported since 5.005 (ABSTRACT_FROM => 'lib/PL/Tutu.pm', # retrieve abstract from module AUTHOR => 'Lenguajes y Herramientas de Programacion <lhp@>') : ()), );Perl utilizará esa información durante la fase de instalación para instalar los ejecutables en el path de búsqueda.
A continuación hay que rehacer el Makefile
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ perl Makefile.PL Writing Makefile for PL::Tutu
Para crear una versión funcional hacemos make
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ make cp scripts/tutu blib/script/tutu /usr/bin/perl "-MExtUtils::MY" -e "MY->fixin(shift)" blib/script/tutu cp scripts/tutu.pl blib/script/tutu.pl /usr/bin/perl "-MExtUtils::MY" -e "MY->fixin(shift)" blib/script/tutu.pl Manifying blib/man3/PL::Tutu.3pm
Para crear el MANIFEST
hacemos make manifest
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ make manifest /usr/bin/perl "-MExtUtils::Manifest=mkmanifest" -e mkmanifest Added to MANIFEST: scripts/tutu
Comprobemos que el test de prueba generado automáticamente por
h2xs
se pasa correctamente:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ make test PERL_DL_NONLAZY=1 /usr/bin/perl "-MExtUtils::Command::MM" "-e" "test_harness(0, 'blib/lib', 'blib/arch')" t/*.t t/PL-Tutu....ok All tests successful. Files=1, Tests=1, 0 wallclock secs ( 0.08 cusr + 0.00 csys = 0.08 CPU)
Podemos ahora ejecutar los guiones:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ cd scripts/ lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ ls -l total 12 -rw-r--r-- 1 lhp lhp 15 2005-09-29 12:56 test01.tutu -rwxr-xr-x 1 lhp lhp 92 2005-09-29 13:29 tutu -rwxr-xr-x 1 lhp lhp 80 2005-09-29 12:58 tutu.pl lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ tutu test01.tutu test01.sal lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ ls -l total 12 -rw-r--r-- 1 lhp lhp 0 2005-09-29 13:53 test01.sal -rw-r--r-- 1 lhp lhp 15 2005-09-29 12:56 test01.tutu -rwxr-xr-x 1 lhp lhp 92 2005-09-29 13:29 tutu -rwxr-xr-x 1 lhp lhp 80 2005-09-29 12:58 tutu.pl
Veamos los contenidos del programa fuente test01.tutu
que usaremos para hacer una prueba:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu/scripts$ cat test01.tutu int a,b; a = 4
Para hacer una distribución instalable hacemos make dist
:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ make dist rm -rf PL-Tutu-0.01 /usr/bin/perl "-MExtUtils::Manifest=manicopy,maniread" \ -e "manicopy(maniread(),'PL-Tutu-0.01', 'best');" mkdir PL-Tutu-0.01 mkdir PL-Tutu-0.01/scripts mkdir PL-Tutu-0.01/lib mkdir PL-Tutu-0.01/lib/PL mkdir PL-Tutu-0.01/t tar cvf PL-Tutu-0.01.tar PL-Tutu-0.01 PL-Tutu-0.01/ PL-Tutu-0.01/scripts/ PL-Tutu-0.01/scripts/test01.tutu PL-Tutu-0.01/scripts/tutu PL-Tutu-0.01/scripts/tutu.pl PL-Tutu-0.01/META.yml PL-Tutu-0.01/Changes PL-Tutu-0.01/MANIFEST PL-Tutu-0.01/lib/ PL-Tutu-0.01/lib/PL/ PL-Tutu-0.01/lib/PL/Tutu.pm PL-Tutu-0.01/MANIFEST.SKIP PL-Tutu-0.01/t/ PL-Tutu-0.01/t/PL-Tutu.t PL-Tutu-0.01/Makefile.PL PL-Tutu-0.01/README rm -rf PL-Tutu-0.01 gzip --best PL-Tutu-0.01.tarDespués de esto tenemos en el directorio de trabajo el fichero
PL-Tutu-0.01.tar.gz
con la distribución:
lhp@nereida:~/Lperl/src/topdown/PL0506/02fases/PL-Tutu$ ls -ltr total 72 drwxr-xr-x 2 lhp lhp 4096 2005-09-29 12:01 t -rw-r--r-- 1 lhp lhp 1196 2005-09-29 12:01 README drwxr-xr-x 3 lhp lhp 4096 2005-09-29 12:01 lib -rw-r--r-- 1 lhp lhp 152 2005-09-29 12:01 Changes -rw-r--r-- 1 lhp lhp 167 2005-09-29 13:23 MANIFEST.SKIP -rw-r--r-- 1 lhp lhp 0 2005-09-29 13:23 pm_to_blib drwxr-xr-x 6 lhp lhp 4096 2005-09-29 13:23 blib -rw-r--r-- 1 lhp lhp 113 2005-09-29 13:23 MANIFEST.bak drwxr-xr-x 2 lhp lhp 4096 2005-09-29 13:29 scripts -rw-r--r-- 1 lhp lhp 616 2005-09-29 13:49 Makefile.PL -rw-r--r-- 1 lhp lhp 20509 2005-09-29 13:51 Makefile -rw-r--r-- 1 lhp lhp 3654 2005-09-29 16:34 PL-Tutu-0.01.tar.gz -rw-r--r-- 1 lhp lhp 298 2005-09-29 16:34 META.yml -rw-r--r-- 1 lhp lhp 205 2005-09-29 16:34 MANIFEST