1#!/usr/bin/perl
2#
3# yapp -- Front end to the Parse::Yapp module
4#
5# (c) Copyright 1998-2001 Francois Desarmenien, all rights reserved.
6# (see the pod text in Parse::Yapp module for use and distribution rights)
7#
8#
9
10=head1 NAME
11
12yapp - A perl frontend to the Parse::Yapp module
13
14
15=head1 SYNOPSYS
16
17yapp [options] I<grammar>[.yp]
18
19yapp I<-V>
20
21yapp I<-h>
22
23
24=head1 DESCRIPTION
25
26yapp is a frontend to the Parse::Yapp module, which lets you compile
27Parse::Yapp grammar input files into Perl LALR(1) OO parser modules.
28
29
30=head1 OPTIONS
31
32Options, as of today, are all optionals :-)
33
34=over 4
35
36=item I<-v>
37
38Creates a file F<grammar>.output describing your parser. It will
39show you a summary of conflicts, rules, the DFA (Deterministic
40Finite Automaton) states and overall usage of the parser.
41
42=item I<-s>
43
44Create a standalone module in which the driver is included.
45Note that if you have more than one parser module called from
46a program, to have it standalone, you need this option only
47for one of your parser module.
48
49=item I<-n>
50
51Disable source file line numbering embedded in your parser module.
52I don't know why one should need it, but it's there.
53
54=item I<-m module>
55
56Gives your parser module the package name (or name space or module name or
57class name or whatever-you-call-it) of F<module>.  It defaults to F<grammar>
58
59=item I<-o outfile>
60
61The compiled output file will be named F<outfile> for your parser module.
62It defaults to F<grammar>.pm or, if you specified the option
63I<-m A::Module::Name> (see below), to F<Name.pm>.
64
65=item I<-t filename>
66
67The I<-t filename> option allows you to specify a file which should be 
68used as template for generating the parser output.  The default is to 
69use the internal template defined in F<Parse::Yapp::Output.pm>.
70For how to write your own template and which substitutions are available,
71have a look to the module F<Parse::Yapp::Output.pm> : it should be obvious. 
72
73=item I<-b shebang>
74
75If you work on systems that understand so called I<shebangs>, and your
76generated parser is directly an executable script, you can specifie one
77with the I<-b> option, ie:
78
79    yapp -b '/usr/local/bin/perl -w' -o myscript.pl myscript.yp
80
81This will output a file called F<myscript.pl> whose very first line is:
82
83    #!/usr/local/bin/perl -w
84
85The argument is mandatory, but if you specify an empty string, the value
86of I<$Config{perlpath}> will be used instead.
87
88=item I<grammar>
89
90The input grammar file. If no suffix is given, and the file does not exists,
91an attempt to open the file with a suffix of  F<.yp> is tried before exiting.
92
93=item I<-V>
94
95Display current version of Parse::Yapp and gracefully exits.
96
97=item I<-h>
98
99Display the usage screen.
100
101=back
102
103=head1 BUGS
104
105None known now :-)
106
107=head1 AUTHOR
108
109Francois Desarmenien <francois@fdesar.net>
110
111=head1 COPYRIGHT
112
113(c) Copyright 1998-1999 Francois Desarmenien, all rights reserved.
114See Parse::Yapp(3) for legal use and distribution rights
115
116=head1 SEE ALSO
117
118Parse::Yapp(3) Perl(1) yacc(1) bison(1)
119
120
121=cut
122
123require 5.004;
124
125use File::Basename;
126use Getopt::Std;
127use Config;
128use Parse::Yapp;
129
130use strict;
131
132use vars qw ( $opt_n $opt_m $opt_V $opt_v $opt_o $opt_h $opt_s $opt_t $opt_b);
133
134sub Usage {
135	my($prog)=(fileparse($0,'\..*'))[0];
136	die <<EOF;
137
138Usage:	$prog [options] grammar[.yp]
139  or	$prog -V
140  or	$prog -h
141
142    -m module   Give your parser module the name <module>
143                default is <grammar>
144    -v          Create a file <grammar>.output describing your parser
145    -s          Create a standalone module in which the driver is included
146    -n          Disable source file line numbering embedded in your parser
147    -o outfile  Create the file <outfile> for your parser module
148                Default is <grammar>.pm or, if -m A::Module::Name is
149                specified, Name.pm
150    -t filename Uses the file <filename> as a template for creating the parser
151                module file.  Default is to use internal template defined
152                in Parse::Yapp::Output
153    -b shebang  Adds '#!<shebang>' as the very first line of the output file
154
155    grammar     The grammar file. If no suffix is given, and the file
156                does not exists, .yp is added
157
158    -V          Display current version of Parse::Yapp and gracefully exits
159    -h          Display this help screen
160
161EOF
162}
163
164my($nbargs)=@ARGV;
165
166	getopts('Vhvsnb:m:t:o:')
167or	Usage;
168
169   (  ($opt_V and $nbargs > 1)
170    or $opt_h)
171and Usage;
172
173	$opt_V
174and do {
175
176    @ARGV == 0 or  Usage;
177
178    print "This is Parse::Yapp version $Parse::Yapp::Driver::VERSION.\n";
179    exit(0);
180
181};
182
183
184# -t <filename> ($opt_t) option allows a file to be specified which 
185# contains a 'template' to be used when generating the parser; 
186# if defined, we open and read the file.   
187
188	$opt_t
189and do {
190    local $/ = undef;
191    local *TFILE;
192    open(TFILE, $opt_t)
193	or die "Cannot open template file $opt_t: $!\n";
194    $opt_t = <TFILE>;
195    close(TFILE);
196};
197
198    @ARGV == 1
199or  Usage;
200
201my($filename)=$ARGV[0];
202my($base,$path,$sfx)=fileparse($filename,'\..*');
203
204	-r "$filename"
205or	do {
206		$sfx eq '.yp'
207	or	$filename.='.yp';
208
209		-r "$filename"
210	or	die "Cannot open $filename for reading.\n";
211};
212
213my($parser)=new Parse::Yapp(inputfile => $filename);
214
215my($warnings)=$parser->Warnings();
216
217	$warnings
218and	print STDERR $warnings;
219
220	$opt_v
221and	do {
222	my($output)="$path$base.output";
223	my($tmp);
224
225		open(OUT,">$output")
226	or	die "Cannot create $base.output for writing.\n";
227
228		$tmp=$parser->Warnings()
229	and	print	OUT "Warnings:\n---------\n$tmp\n";
230		$tmp=$parser->Conflicts()
231	and	print	OUT "Conflicts:\n----------\n$tmp\n";
232	print	OUT "Rules:\n------\n";
233	print	OUT $parser->ShowRules()."\n";
234	print	OUT "States:\n-------\n";
235	print	OUT $parser->ShowDfa()."\n";
236	print	OUT "Summary:\n--------\n";
237	print	OUT $parser->Summary();
238
239	close(OUT);
240};
241
242my($outfile)="$path$base.pm";
243my($package)="$base";
244
245	$opt_m
246and	do {
247    $package=$opt_m;
248    $package=~/^(?:(?:[^:]|:(?!:))*::)*(.*)$/;
249    $outfile="$1.pm";
250};
251
252	$opt_o
253and	$outfile=$opt_o;
254
255$opt_s = $opt_s ? 1 : 0;
256
257$opt_n = $opt_n ? 0 : 1;
258
259	open(OUT,">$outfile")
260or	die "Cannot open $outfile for writing.\n";
261
262    defined($opt_b)
263and do {
264        $opt_b
265    or  $opt_b = $Config{perlpath};
266    print OUT "#!$opt_b\n";
267};
268
269print OUT $parser->Output(classname  => $package,
270                          standalone => $opt_s,
271                          linenumbers => $opt_n,
272                          template    => $opt_t,
273                         );
274
275
276close(OUT);
277
278