1#! /bin/sh
2
3#
4# runlex.sh
5# Script to run Lex/Flex.
6# First argument is the (quoted) name of the command; if it's null, that
7# means that neither Flex nor Lex was found, so we report an error and
8# quit.
9#
10
11#
12# Get the name of the command to run, and then shift to get the arguments.
13#
14if [ $# -eq 0 ]
15then
16	echo "Usage: runlex <lex/flex command to run> [ arguments ]" 1>&2
17	exit 1
18fi
19LEX="$1"
20shift
21
22#
23# Check whether we have Lex or Flex.
24#
25if [ -z "${LEX}" ]
26then
27	echo "Neither lex nor flex was found" 1>&2
28	exit 1
29fi
30
31#
32# Process the flags.  We don't use getopt because we don't want to
33# embed complete knowledge of what options are supported by Lex/Flex.
34#
35flags=""
36outfile=lex.yy.c
37while [ $# -ne 0 ]
38do
39	case "$1" in
40
41	-o*)
42		#
43		# Set the output file name.
44		#
45		outfile=`echo "$1" | sed 's/-o\(.*\)/\1/'`
46		;;
47
48	-*)
49		#
50		# Add this to the list of flags.
51		#
52		flags="$flags $1"
53		;;
54
55	--|*)
56		#
57		# End of flags.
58		#
59		break
60		;;
61	esac
62	shift
63done
64
65#
66# Is it Lex, or is it Flex?
67#
68if [ "${LEX}" = flex ]
69then
70	#
71	# It's Flex.
72	#
73	have_flex=yes
74
75	#
76	# Does it support the --noFUNCTION options?  If so, we pass
77	# --nounput, as at least some versions that support those
78	# options don't support disabling yyunput by defining
79	# YY_NO_UNPUT.
80	#
81	if flex --help | egrep noFUNCTION >/dev/null
82	then
83		flags="$flags --nounput"
84
85		#
86		# Does it support -R, for generating reentrant scanners?
87		# If so, we're not currently using that feature, but
88		# it'll generate some unused functions anyway - and there
89		# won't be any header file declaring them, so there'll be
90		# defined-but-not-declared warnings.  Therefore, we use
91		# --noFUNCTION options to suppress generating those
92		# functions.
93		#
94		if flex --help | egrep reentrant >/dev/null
95		then
96			flags="$flags --noyyget_lineno --noyyget_in --noyyget_out --noyyget_leng --noyyget_text --noyyset_lineno --noyyset_in --noyyset_out"
97		fi
98	fi
99else
100	#
101	# It's Lex.
102	#
103	have_flex=no
104fi
105
106#
107# OK, run it.
108# If it's lex, it doesn't support -o, so we just write to
109# lex.yy.c and, if it succeeds, rename it to the right name,
110# otherwise we remove lex.yy.c.
111# If it's flex, it supports -o, so we use that - flex with -P doesn't
112# write to lex.yy.c, it writes to a lex.{prefix from -P}.c.
113#
114if [ $have_flex = yes ]
115then
116	${LEX} $flags -o"$outfile" "$@"
117
118	#
119	# Did it succeed?
120	#
121	status=$?
122	if [ $status -ne 0 ]
123	then
124		#
125		# No.  Exit with the failing exit status.
126		#
127		exit $status
128	fi
129
130	#
131	# Flex has the annoying habit of stripping all but the last
132	# component of the "-o" flag argument and using that as the
133	# place to put the output.  This gets in the way of building
134	# in a directory different from the source directory.  Try
135	# to work around this.
136	#
137	# Is the outfile where we think it is?
138	#
139	outfile_base=`basename "$outfile"`
140	if [ "$outfile_base" != "$outfile" -a \( ! -r "$outfile" \) -a -r "$outfile_base" ]
141	then
142		#
143		# No, it's not, but it is in the current directory.  Put it
144		# where it's supposed to be.
145		#
146		mv "$outfile_base" "$outfile"
147
148		#
149		# Did that succeed?
150		#
151		status=$?
152		if [ $status -ne 0 ]
153		then
154			#
155			# No.  Exit with the failing exit status.
156			#
157			exit $status
158		fi
159	fi
160else
161	${LEX} $flags "$@"
162
163	#
164	# Did it succeed?
165	#
166	status=$?
167	if [ $status -ne 0 ]
168	then
169		#
170		# No.  Get rid of any lex.yy.c file we generated, and
171		# exit with the failing exit status.
172		#
173		rm -f lex.yy.c
174		exit $status
175	fi
176
177	#
178	# OK, rename lex.yy.c to the right output file.
179	#
180	mv lex.yy.c "$outfile"
181
182	#
183	# Did that succeed?
184	#
185	status=$?
186	if [ $status -ne 0 ]
187	then
188		#
189		# No.  Get rid of any lex.yy.c file we generated, and
190		# exit with the failing exit status.
191		#
192		rm -f lex.yy.c
193		exit $status
194	fi
195fi
196
197#
198# OK, now let's generate a header file declaring the relevant functions
199# defined by the .c file; if the .c file is .../foo.c, the header file
200# will be .../foo.h.
201#
202# This works around some other Flex suckage, wherein it doesn't declare
203# the lex routine before defining it, causing compiler warnings.
204# XXX - newer versions of Flex support --header-file=, to generate the
205# appropriate header file.  With those versions, we should use that option.
206#
207
208#
209# Get the name of the prefix; scan the source files for a %option prefix
210# line.  We use the last one.
211#
212prefix=`sed -n 's/%option[ 	][ 	]*prefix="\(.*\)".*/\1/p' "$@" | tail -1`
213if [ ! -z "$prefix" ]
214then
215	prefixline="#define yylex ${prefix}lex"
216fi
217
218#
219# Construct the name of the header file.
220#
221header_file=`dirname "$outfile"`/`basename "$outfile" .c`.h
222
223#
224# Spew out the declaration.
225#
226cat <<EOF >$header_file
227/* This is generated by runlex.sh.  Do not edit it. */
228$prefixline
229#ifndef YY_DECL
230#define YY_DECL int yylex(void)
231#endif
232YY_DECL;
233EOF
234