

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.tar
Despué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

