xref: /netbsd-src/external/gpl2/gettext/dist/gettext-tools/src/x-csharp.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
1*946379e7Schristos /* xgettext C# backend.
2*946379e7Schristos    Copyright (C) 2003, 2005-2006 Free Software Foundation, Inc.
3*946379e7Schristos    Written by Bruno Haible <bruno@clisp.org>, 2003.
4*946379e7Schristos 
5*946379e7Schristos    This program is free software; you can redistribute it and/or modify
6*946379e7Schristos    it under the terms of the GNU General Public License as published by
7*946379e7Schristos    the Free Software Foundation; either version 2, or (at your option)
8*946379e7Schristos    any later version.
9*946379e7Schristos 
10*946379e7Schristos    This program is distributed in the hope that it will be useful,
11*946379e7Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*946379e7Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*946379e7Schristos    GNU General Public License for more details.
14*946379e7Schristos 
15*946379e7Schristos    You should have received a copy of the GNU General Public License
16*946379e7Schristos    along with this program; if not, write to the Free Software Foundation,
17*946379e7Schristos    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
18*946379e7Schristos 
19*946379e7Schristos #ifdef HAVE_CONFIG_H
20*946379e7Schristos # include "config.h"
21*946379e7Schristos #endif
22*946379e7Schristos 
23*946379e7Schristos #include <errno.h>
24*946379e7Schristos #include <stdbool.h>
25*946379e7Schristos #include <stdio.h>
26*946379e7Schristos #include <stdlib.h>
27*946379e7Schristos #include <string.h>
28*946379e7Schristos 
29*946379e7Schristos #include "message.h"
30*946379e7Schristos #include "xgettext.h"
31*946379e7Schristos #include "x-csharp.h"
32*946379e7Schristos #include "c-ctype.h"
33*946379e7Schristos #include "error.h"
34*946379e7Schristos #include "error-progname.h"
35*946379e7Schristos #include "xalloc.h"
36*946379e7Schristos #include "xerror.h"
37*946379e7Schristos #include "xvasprintf.h"
38*946379e7Schristos #include "exit.h"
39*946379e7Schristos #include "hash.h"
40*946379e7Schristos #include "po-charset.h"
41*946379e7Schristos #include "utf8-ucs4.h"
42*946379e7Schristos #include "ucs4-utf8.h"
43*946379e7Schristos #include "gettext.h"
44*946379e7Schristos 
45*946379e7Schristos #define _(s) gettext(s)
46*946379e7Schristos 
47*946379e7Schristos #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
48*946379e7Schristos 
49*946379e7Schristos 
50*946379e7Schristos /* The C# syntax is defined in ECMA-334, second edition.  */
51*946379e7Schristos 
52*946379e7Schristos 
53*946379e7Schristos /* ====================== Keyword set customization.  ====================== */
54*946379e7Schristos 
55*946379e7Schristos /* If true extract all strings.  */
56*946379e7Schristos static bool extract_all = false;
57*946379e7Schristos 
58*946379e7Schristos static hash_table keywords;
59*946379e7Schristos static bool default_keywords = true;
60*946379e7Schristos 
61*946379e7Schristos 
62*946379e7Schristos void
x_csharp_extract_all()63*946379e7Schristos x_csharp_extract_all ()
64*946379e7Schristos {
65*946379e7Schristos   extract_all = true;
66*946379e7Schristos }
67*946379e7Schristos 
68*946379e7Schristos 
69*946379e7Schristos /* Processes a --keyword option.
70*946379e7Schristos    Non-ASCII function names can be used if given in UTF-8 encoding.  */
71*946379e7Schristos void
x_csharp_keyword(const char * name)72*946379e7Schristos x_csharp_keyword (const char *name)
73*946379e7Schristos {
74*946379e7Schristos   if (name == NULL)
75*946379e7Schristos     default_keywords = false;
76*946379e7Schristos   else
77*946379e7Schristos     {
78*946379e7Schristos       const char *end;
79*946379e7Schristos       struct callshape shape;
80*946379e7Schristos       const char *colon;
81*946379e7Schristos 
82*946379e7Schristos       if (keywords.table == NULL)
83*946379e7Schristos 	hash_init (&keywords, 100);
84*946379e7Schristos 
85*946379e7Schristos       split_keywordspec (name, &end, &shape);
86*946379e7Schristos 
87*946379e7Schristos       /* The characters between name and end should form a valid C#
88*946379e7Schristos 	 identifier sequence with dots.
89*946379e7Schristos 	 A colon means an invalid parse in split_keywordspec().  */
90*946379e7Schristos       colon = strchr (name, ':');
91*946379e7Schristos       if (colon == NULL || colon >= end)
92*946379e7Schristos 	insert_keyword_callshape (&keywords, name, end - name, &shape);
93*946379e7Schristos     }
94*946379e7Schristos }
95*946379e7Schristos 
96*946379e7Schristos /* Finish initializing the keywords hash table.
97*946379e7Schristos    Called after argument processing, before each file is processed.  */
98*946379e7Schristos static void
init_keywords()99*946379e7Schristos init_keywords ()
100*946379e7Schristos {
101*946379e7Schristos   if (default_keywords)
102*946379e7Schristos     {
103*946379e7Schristos       /* When adding new keywords here, also update the documentation in
104*946379e7Schristos 	 xgettext.texi!  */
105*946379e7Schristos       x_csharp_keyword ("GetString");	/* Resource{Manager,Set}.GetString */
106*946379e7Schristos       x_csharp_keyword ("GetPluralString:1,2");	/* GettextResource{Manager,Set}.GetPluralString */
107*946379e7Schristos       default_keywords = false;
108*946379e7Schristos     }
109*946379e7Schristos }
110*946379e7Schristos 
111*946379e7Schristos void
init_flag_table_csharp()112*946379e7Schristos init_flag_table_csharp ()
113*946379e7Schristos {
114*946379e7Schristos   xgettext_record_flag ("GetString:1:pass-csharp-format");
115*946379e7Schristos   xgettext_record_flag ("GetPluralString:1:pass-csharp-format");
116*946379e7Schristos   xgettext_record_flag ("GetPluralString:2:pass-csharp-format");
117*946379e7Schristos   xgettext_record_flag ("String.Format:1:csharp-format");
118*946379e7Schristos }
119*946379e7Schristos 
120*946379e7Schristos 
121*946379e7Schristos /* ======================== Reading of characters.  ======================== */
122*946379e7Schristos 
123*946379e7Schristos /* Real filename, used in error messages about the input file.  */
124*946379e7Schristos static const char *real_file_name;
125*946379e7Schristos 
126*946379e7Schristos /* Logical filename and line number, used to label the extracted messages.  */
127*946379e7Schristos static char *logical_file_name;
128*946379e7Schristos static int line_number;
129*946379e7Schristos 
130*946379e7Schristos /* The input file stream.  */
131*946379e7Schristos static FILE *fp;
132*946379e7Schristos 
133*946379e7Schristos 
134*946379e7Schristos /* Phase 1: line_number handling.  */
135*946379e7Schristos 
136*946379e7Schristos /* Maximum used, roughly a safer MB_LEN_MAX.  */
137*946379e7Schristos #define MAX_PHASE1_PUSHBACK 16
138*946379e7Schristos static unsigned char phase1_pushback[MAX_PHASE1_PUSHBACK];
139*946379e7Schristos static int phase1_pushback_length;
140*946379e7Schristos 
141*946379e7Schristos /* Read the next single byte from the input file.  */
142*946379e7Schristos static int
phase1_getc()143*946379e7Schristos phase1_getc ()
144*946379e7Schristos {
145*946379e7Schristos   int c;
146*946379e7Schristos 
147*946379e7Schristos   if (phase1_pushback_length)
148*946379e7Schristos     {
149*946379e7Schristos       c = phase1_pushback[--phase1_pushback_length];
150*946379e7Schristos       if (c == '\n')
151*946379e7Schristos 	++line_number;
152*946379e7Schristos       return c;
153*946379e7Schristos     }
154*946379e7Schristos 
155*946379e7Schristos   c = getc (fp);
156*946379e7Schristos   if (c == EOF)
157*946379e7Schristos     {
158*946379e7Schristos       if (ferror (fp))
159*946379e7Schristos 	error (EXIT_FAILURE, errno, _("error while reading \"%s\""),
160*946379e7Schristos 	       real_file_name);
161*946379e7Schristos       return EOF;
162*946379e7Schristos     }
163*946379e7Schristos 
164*946379e7Schristos   if (c == '\n')
165*946379e7Schristos     ++line_number;
166*946379e7Schristos   return c;
167*946379e7Schristos }
168*946379e7Schristos 
169*946379e7Schristos /* Supports MAX_PHASE1_PUSHBACK characters of pushback.  */
170*946379e7Schristos static void
phase1_ungetc(int c)171*946379e7Schristos phase1_ungetc (int c)
172*946379e7Schristos {
173*946379e7Schristos   if (c != EOF)
174*946379e7Schristos     {
175*946379e7Schristos       if (c == '\n')
176*946379e7Schristos 	--line_number;
177*946379e7Schristos       if (phase1_pushback_length == SIZEOF (phase1_pushback))
178*946379e7Schristos 	abort ();
179*946379e7Schristos       phase1_pushback[phase1_pushback_length++] = c;
180*946379e7Schristos     }
181*946379e7Schristos }
182*946379e7Schristos 
183*946379e7Schristos 
184*946379e7Schristos /* Phase 2: Conversion to Unicode.
185*946379e7Schristos    This is done early because ECMA-334 section 9.1. says that the source is
186*946379e7Schristos    "an ordered sequence of Unicode characters", and because the recognition
187*946379e7Schristos    of the line terminators (ECMA-334 section 9.3.1) is hardly possible without
188*946379e7Schristos    prior conversion to Unicode.  */
189*946379e7Schristos 
190*946379e7Schristos /* End-of-file indicator for functions returning an UCS-4 character.  */
191*946379e7Schristos #define UEOF -1
192*946379e7Schristos 
193*946379e7Schristos /* Newline Unicode character.  */
194*946379e7Schristos #define UNL 0x000a
195*946379e7Schristos 
196*946379e7Schristos static int phase2_pushback[1];
197*946379e7Schristos static int phase2_pushback_length;
198*946379e7Schristos 
199*946379e7Schristos /* Read the next Unicode UCS-4 character from the input file.  */
200*946379e7Schristos static int
phase2_getc()201*946379e7Schristos phase2_getc ()
202*946379e7Schristos {
203*946379e7Schristos   if (phase2_pushback_length)
204*946379e7Schristos     return phase2_pushback[--phase2_pushback_length];
205*946379e7Schristos 
206*946379e7Schristos   if (xgettext_current_source_encoding == po_charset_ascii)
207*946379e7Schristos     {
208*946379e7Schristos       int c = phase1_getc ();
209*946379e7Schristos       if (c == EOF)
210*946379e7Schristos 	return UEOF;
211*946379e7Schristos       if (!c_isascii (c))
212*946379e7Schristos 	{
213*946379e7Schristos 	  char buffer[21];
214*946379e7Schristos 	  sprintf (buffer, ":%ld", (long) line_number);
215*946379e7Schristos 	  multiline_error (xstrdup (""),
216*946379e7Schristos 			   xasprintf (_("\
217*946379e7Schristos Non-ASCII string at %s%s.\n\
218*946379e7Schristos Please specify the source encoding through --from-code.\n"),
219*946379e7Schristos 			   real_file_name, buffer));
220*946379e7Schristos 	  exit (EXIT_FAILURE);
221*946379e7Schristos 	}
222*946379e7Schristos       return c;
223*946379e7Schristos     }
224*946379e7Schristos   else if (xgettext_current_source_encoding != po_charset_utf8)
225*946379e7Schristos     {
226*946379e7Schristos #if HAVE_ICONV
227*946379e7Schristos       /* Use iconv on an increasing number of bytes.  Read only as many bytes
228*946379e7Schristos 	 through phase1_getc as needed.  This is needed to give reasonable
229*946379e7Schristos 	 interactive behaviour when fp is connected to an interactive tty.  */
230*946379e7Schristos       unsigned char buf[MAX_PHASE1_PUSHBACK];
231*946379e7Schristos       size_t bufcount;
232*946379e7Schristos       int c = phase1_getc ();
233*946379e7Schristos       if (c == EOF)
234*946379e7Schristos 	return UEOF;
235*946379e7Schristos       buf[0] = (unsigned char) c;
236*946379e7Schristos       bufcount = 1;
237*946379e7Schristos 
238*946379e7Schristos       for (;;)
239*946379e7Schristos 	{
240*946379e7Schristos 	  unsigned char scratchbuf[6];
241*946379e7Schristos 	  const char *inptr = (const char *) &buf[0];
242*946379e7Schristos 	  size_t insize = bufcount;
243*946379e7Schristos 	  char *outptr = (char *) &scratchbuf[0];
244*946379e7Schristos 	  size_t outsize = sizeof (scratchbuf);
245*946379e7Schristos 
246*946379e7Schristos 	  size_t res = iconv (xgettext_current_source_iconv,
247*946379e7Schristos 			      (ICONV_CONST char **) &inptr, &insize,
248*946379e7Schristos 			      &outptr, &outsize);
249*946379e7Schristos 	  /* We expect that a character has been produced if and only if
250*946379e7Schristos 	     some input bytes have been consumed.  */
251*946379e7Schristos 	  if ((insize < bufcount) != (outsize < sizeof (scratchbuf)))
252*946379e7Schristos 	    abort ();
253*946379e7Schristos 	  if (outsize == sizeof (scratchbuf))
254*946379e7Schristos 	    {
255*946379e7Schristos 	      /* No character has been produced.  Must be an error.  */
256*946379e7Schristos 	      if (res != (size_t)(-1))
257*946379e7Schristos 		abort ();
258*946379e7Schristos 
259*946379e7Schristos 	      if (errno == EILSEQ)
260*946379e7Schristos 		{
261*946379e7Schristos 		  /* An invalid multibyte sequence was encountered.  */
262*946379e7Schristos 		  multiline_error (xstrdup (""),
263*946379e7Schristos 				   xasprintf (_("\
264*946379e7Schristos %s:%d: Invalid multibyte sequence.\n\
265*946379e7Schristos Please specify the correct source encoding through --from-code.\n"),
266*946379e7Schristos 				   real_file_name, line_number));
267*946379e7Schristos 		  exit (EXIT_FAILURE);
268*946379e7Schristos 		}
269*946379e7Schristos 	      else if (errno == EINVAL)
270*946379e7Schristos 		{
271*946379e7Schristos 		  /* An incomplete multibyte character.  */
272*946379e7Schristos 		  int c;
273*946379e7Schristos 
274*946379e7Schristos 		  if (bufcount == MAX_PHASE1_PUSHBACK)
275*946379e7Schristos 		    {
276*946379e7Schristos 		      /* An overlong incomplete multibyte sequence was
277*946379e7Schristos 			 encountered.  */
278*946379e7Schristos 		      multiline_error (xstrdup (""),
279*946379e7Schristos 				       xasprintf (_("\
280*946379e7Schristos %s:%d: Long incomplete multibyte sequence.\n\
281*946379e7Schristos Please specify the correct source encoding through --from-code.\n"),
282*946379e7Schristos 				       real_file_name, line_number));
283*946379e7Schristos 		      exit (EXIT_FAILURE);
284*946379e7Schristos 		    }
285*946379e7Schristos 
286*946379e7Schristos 		  /* Read one more byte and retry iconv.  */
287*946379e7Schristos 		  c = phase1_getc ();
288*946379e7Schristos 		  if (c == EOF)
289*946379e7Schristos 		    {
290*946379e7Schristos 		      multiline_error (xstrdup (""),
291*946379e7Schristos 				       xasprintf (_("\
292*946379e7Schristos %s:%d: Incomplete multibyte sequence at end of file.\n\
293*946379e7Schristos Please specify the correct source encoding through --from-code.\n"),
294*946379e7Schristos 				       real_file_name, line_number));
295*946379e7Schristos 		      exit (EXIT_FAILURE);
296*946379e7Schristos 		    }
297*946379e7Schristos 		  if (c == '\n')
298*946379e7Schristos 		    {
299*946379e7Schristos 		      multiline_error (xstrdup (""),
300*946379e7Schristos 				       xasprintf (_("\
301*946379e7Schristos %s:%d: Incomplete multibyte sequence at end of line.\n\
302*946379e7Schristos Please specify the correct source encoding through --from-code.\n"),
303*946379e7Schristos 				       real_file_name, line_number - 1));
304*946379e7Schristos 		      exit (EXIT_FAILURE);
305*946379e7Schristos 		    }
306*946379e7Schristos 		  buf[bufcount++] = (unsigned char) c;
307*946379e7Schristos 		}
308*946379e7Schristos 	      else
309*946379e7Schristos 		error (EXIT_FAILURE, errno, _("%s:%d: iconv failure"),
310*946379e7Schristos 		       real_file_name, line_number);
311*946379e7Schristos 	    }
312*946379e7Schristos 	  else
313*946379e7Schristos 	    {
314*946379e7Schristos 	      size_t outbytes = sizeof (scratchbuf) - outsize;
315*946379e7Schristos 	      size_t bytes = bufcount - insize;
316*946379e7Schristos 	      unsigned int uc;
317*946379e7Schristos 
318*946379e7Schristos 	      /* We expect that one character has been produced.  */
319*946379e7Schristos 	      if (bytes == 0)
320*946379e7Schristos 		abort ();
321*946379e7Schristos 	      if (outbytes == 0)
322*946379e7Schristos 		abort ();
323*946379e7Schristos 	      /* Push back the unused bytes.  */
324*946379e7Schristos 	      while (insize > 0)
325*946379e7Schristos 		phase1_ungetc (buf[--insize]);
326*946379e7Schristos 	      /* Convert the character from UTF-8 to UCS-4.  */
327*946379e7Schristos 	      if (u8_mbtouc (&uc, scratchbuf, outbytes) < outbytes)
328*946379e7Schristos 		{
329*946379e7Schristos 		  /* scratchbuf contains an out-of-range Unicode character
330*946379e7Schristos 		     (> 0x10ffff).  */
331*946379e7Schristos 		  multiline_error (xstrdup (""),
332*946379e7Schristos 				   xasprintf (_("\
333*946379e7Schristos %s:%d: Invalid multibyte sequence.\n\
334*946379e7Schristos Please specify the source encoding through --from-code.\n"),
335*946379e7Schristos 				   real_file_name, line_number));
336*946379e7Schristos 		  exit (EXIT_FAILURE);
337*946379e7Schristos 		}
338*946379e7Schristos 	      return uc;
339*946379e7Schristos 	    }
340*946379e7Schristos 	}
341*946379e7Schristos #else
342*946379e7Schristos       /* If we don't have iconv(), the only supported values for
343*946379e7Schristos 	 xgettext_global_source_encoding and thus also for
344*946379e7Schristos 	 xgettext_current_source_encoding are ASCII and UTF-8.  */
345*946379e7Schristos       abort ();
346*946379e7Schristos #endif
347*946379e7Schristos     }
348*946379e7Schristos   else
349*946379e7Schristos     {
350*946379e7Schristos       /* Read an UTF-8 encoded character.  */
351*946379e7Schristos       unsigned char buf[6];
352*946379e7Schristos       unsigned int count;
353*946379e7Schristos       int c;
354*946379e7Schristos       unsigned int uc;
355*946379e7Schristos 
356*946379e7Schristos       c = phase1_getc ();
357*946379e7Schristos       if (c == EOF)
358*946379e7Schristos 	return UEOF;
359*946379e7Schristos       buf[0] = c;
360*946379e7Schristos       count = 1;
361*946379e7Schristos 
362*946379e7Schristos       if (buf[0] >= 0xc0)
363*946379e7Schristos 	{
364*946379e7Schristos 	  c = phase1_getc ();
365*946379e7Schristos 	  if (c == EOF)
366*946379e7Schristos 	    return UEOF;
367*946379e7Schristos 	  buf[1] = c;
368*946379e7Schristos 	  count = 2;
369*946379e7Schristos 	}
370*946379e7Schristos 
371*946379e7Schristos       if (buf[0] >= 0xe0
372*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40))
373*946379e7Schristos 	{
374*946379e7Schristos 	  c = phase1_getc ();
375*946379e7Schristos 	  if (c == EOF)
376*946379e7Schristos 	    return UEOF;
377*946379e7Schristos 	  buf[2] = c;
378*946379e7Schristos 	  count = 3;
379*946379e7Schristos 	}
380*946379e7Schristos 
381*946379e7Schristos       if (buf[0] >= 0xf0
382*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
383*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40))
384*946379e7Schristos 	{
385*946379e7Schristos 	  c = phase1_getc ();
386*946379e7Schristos 	  if (c == EOF)
387*946379e7Schristos 	    return UEOF;
388*946379e7Schristos 	  buf[3] = c;
389*946379e7Schristos 	  count = 4;
390*946379e7Schristos 	}
391*946379e7Schristos 
392*946379e7Schristos       if (buf[0] >= 0xf8
393*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
394*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40)
395*946379e7Schristos 	  && ((buf[3] ^ 0x80) < 0x40))
396*946379e7Schristos 	{
397*946379e7Schristos 	  c = phase1_getc ();
398*946379e7Schristos 	  if (c == EOF)
399*946379e7Schristos 	    return UEOF;
400*946379e7Schristos 	  buf[4] = c;
401*946379e7Schristos 	  count = 5;
402*946379e7Schristos 	}
403*946379e7Schristos 
404*946379e7Schristos       if (buf[0] >= 0xfc
405*946379e7Schristos 	  && ((buf[1] ^ 0x80) < 0x40)
406*946379e7Schristos 	  && ((buf[2] ^ 0x80) < 0x40)
407*946379e7Schristos 	  && ((buf[3] ^ 0x80) < 0x40)
408*946379e7Schristos 	  && ((buf[4] ^ 0x80) < 0x40))
409*946379e7Schristos 	{
410*946379e7Schristos 	  c = phase1_getc ();
411*946379e7Schristos 	  if (c == EOF)
412*946379e7Schristos 	    return UEOF;
413*946379e7Schristos 	  buf[5] = c;
414*946379e7Schristos 	  count = 6;
415*946379e7Schristos 	}
416*946379e7Schristos 
417*946379e7Schristos       u8_mbtouc (&uc, buf, count);
418*946379e7Schristos       return uc;
419*946379e7Schristos     }
420*946379e7Schristos }
421*946379e7Schristos 
422*946379e7Schristos /* Supports only one pushback character.  */
423*946379e7Schristos static void
phase2_ungetc(int c)424*946379e7Schristos phase2_ungetc (int c)
425*946379e7Schristos {
426*946379e7Schristos   if (c != UEOF)
427*946379e7Schristos     {
428*946379e7Schristos       if (phase2_pushback_length == SIZEOF (phase2_pushback))
429*946379e7Schristos 	abort ();
430*946379e7Schristos       phase2_pushback[phase2_pushback_length++] = c;
431*946379e7Schristos     }
432*946379e7Schristos }
433*946379e7Schristos 
434*946379e7Schristos 
435*946379e7Schristos /* Phase 3: Convert all line terminators to LF.
436*946379e7Schristos    See ECMA-334 section 9.3.1.  */
437*946379e7Schristos 
438*946379e7Schristos /* Line number defined in terms of phase3.  */
439*946379e7Schristos static int logical_line_number;
440*946379e7Schristos 
441*946379e7Schristos static int phase3_pushback[9];
442*946379e7Schristos static int phase3_pushback_length;
443*946379e7Schristos 
444*946379e7Schristos /* Read the next Unicode UCS-4 character from the input file, mapping
445*946379e7Schristos    all line terminators to U+000A, and dropping U+001A at the end of file.  */
446*946379e7Schristos static int
phase3_getc()447*946379e7Schristos phase3_getc ()
448*946379e7Schristos {
449*946379e7Schristos   int c;
450*946379e7Schristos 
451*946379e7Schristos   if (phase3_pushback_length)
452*946379e7Schristos     {
453*946379e7Schristos       c = phase3_pushback[--phase3_pushback_length];
454*946379e7Schristos       if (c == UNL)
455*946379e7Schristos 	++logical_line_number;
456*946379e7Schristos       return c;
457*946379e7Schristos     }
458*946379e7Schristos 
459*946379e7Schristos   c = phase2_getc ();
460*946379e7Schristos 
461*946379e7Schristos   if (c == 0x000d)
462*946379e7Schristos     {
463*946379e7Schristos       int c1 = phase2_getc ();
464*946379e7Schristos 
465*946379e7Schristos       if (c1 != UEOF && c1 != 0x000a)
466*946379e7Schristos 	phase2_ungetc (c1);
467*946379e7Schristos 
468*946379e7Schristos       /* Seen line terminator CR or CR/LF.  */
469*946379e7Schristos       ++logical_line_number;
470*946379e7Schristos       return UNL;
471*946379e7Schristos     }
472*946379e7Schristos 
473*946379e7Schristos   if (c == 0x0085 || c == 0x2028 || c == 0x2029)
474*946379e7Schristos     {
475*946379e7Schristos       /* Seen Unicode word processor newline.  */
476*946379e7Schristos       ++logical_line_number;
477*946379e7Schristos       return UNL;
478*946379e7Schristos     }
479*946379e7Schristos 
480*946379e7Schristos   if (c == 0x001a)
481*946379e7Schristos     {
482*946379e7Schristos       int c1 = phase2_getc ();
483*946379e7Schristos 
484*946379e7Schristos       if (c1 == UEOF)
485*946379e7Schristos 	/* Seen U+001A right before the end of file.  */
486*946379e7Schristos 	return UEOF;
487*946379e7Schristos 
488*946379e7Schristos       phase2_ungetc (c1);
489*946379e7Schristos     }
490*946379e7Schristos 
491*946379e7Schristos   if (c == UNL)
492*946379e7Schristos     ++logical_line_number;
493*946379e7Schristos   return c;
494*946379e7Schristos }
495*946379e7Schristos 
496*946379e7Schristos /* Supports 9 characters of pushback.  */
497*946379e7Schristos static void
phase3_ungetc(int c)498*946379e7Schristos phase3_ungetc (int c)
499*946379e7Schristos {
500*946379e7Schristos   if (c != UEOF)
501*946379e7Schristos     {
502*946379e7Schristos       if (c == UNL)
503*946379e7Schristos 	--logical_line_number;
504*946379e7Schristos       if (phase3_pushback_length == SIZEOF (phase3_pushback))
505*946379e7Schristos 	abort ();
506*946379e7Schristos       phase3_pushback[phase3_pushback_length++] = c;
507*946379e7Schristos     }
508*946379e7Schristos }
509*946379e7Schristos 
510*946379e7Schristos 
511*946379e7Schristos /* ========================= Accumulating strings.  ======================== */
512*946379e7Schristos 
513*946379e7Schristos /* A string buffer type that allows appending Unicode characters.
514*946379e7Schristos    Returns the entire string in UTF-8 encoding.  */
515*946379e7Schristos 
516*946379e7Schristos struct string_buffer
517*946379e7Schristos {
518*946379e7Schristos   /* The part of the string that has already been converted to UTF-8.  */
519*946379e7Schristos   char *utf8_buffer;
520*946379e7Schristos   size_t utf8_buflen;
521*946379e7Schristos   size_t utf8_allocated;
522*946379e7Schristos };
523*946379e7Schristos 
524*946379e7Schristos /* Initialize a 'struct string_buffer' to empty.  */
525*946379e7Schristos static inline void
init_string_buffer(struct string_buffer * bp)526*946379e7Schristos init_string_buffer (struct string_buffer *bp)
527*946379e7Schristos {
528*946379e7Schristos   bp->utf8_buffer = NULL;
529*946379e7Schristos   bp->utf8_buflen = 0;
530*946379e7Schristos   bp->utf8_allocated = 0;
531*946379e7Schristos }
532*946379e7Schristos 
533*946379e7Schristos /* Auxiliary function: Ensure count more bytes are available in bp->utf8.  */
534*946379e7Schristos static inline void
string_buffer_append_unicode_grow(struct string_buffer * bp,size_t count)535*946379e7Schristos string_buffer_append_unicode_grow (struct string_buffer *bp, size_t count)
536*946379e7Schristos {
537*946379e7Schristos   if (bp->utf8_buflen + count > bp->utf8_allocated)
538*946379e7Schristos     {
539*946379e7Schristos       size_t new_allocated = 2 * bp->utf8_allocated + 10;
540*946379e7Schristos       if (new_allocated < bp->utf8_buflen + count)
541*946379e7Schristos 	new_allocated = bp->utf8_buflen + count;
542*946379e7Schristos       bp->utf8_allocated = new_allocated;
543*946379e7Schristos       bp->utf8_buffer = xrealloc (bp->utf8_buffer, new_allocated);
544*946379e7Schristos     }
545*946379e7Schristos }
546*946379e7Schristos 
547*946379e7Schristos /* Auxiliary function: Append a Unicode character to bp->utf8.
548*946379e7Schristos    uc must be < 0x110000.  */
549*946379e7Schristos static inline void
string_buffer_append_unicode(struct string_buffer * bp,unsigned int uc)550*946379e7Schristos string_buffer_append_unicode (struct string_buffer *bp, unsigned int uc)
551*946379e7Schristos {
552*946379e7Schristos   unsigned char utf8buf[6];
553*946379e7Schristos   int count = u8_uctomb (utf8buf, uc, 6);
554*946379e7Schristos 
555*946379e7Schristos   if (count < 0)
556*946379e7Schristos     /* The caller should have ensured that uc is not out-of-range.  */
557*946379e7Schristos     abort ();
558*946379e7Schristos 
559*946379e7Schristos   string_buffer_append_unicode_grow (bp, count);
560*946379e7Schristos   memcpy (bp->utf8_buffer + bp->utf8_buflen, utf8buf, count);
561*946379e7Schristos   bp->utf8_buflen += count;
562*946379e7Schristos }
563*946379e7Schristos 
564*946379e7Schristos /* Return the string buffer's contents.  */
565*946379e7Schristos static char *
string_buffer_result(struct string_buffer * bp)566*946379e7Schristos string_buffer_result (struct string_buffer *bp)
567*946379e7Schristos {
568*946379e7Schristos   /* NUL-terminate it.  */
569*946379e7Schristos   string_buffer_append_unicode_grow (bp, 1);
570*946379e7Schristos   bp->utf8_buffer[bp->utf8_buflen] = '\0';
571*946379e7Schristos   /* Return it.  */
572*946379e7Schristos   return bp->utf8_buffer;
573*946379e7Schristos }
574*946379e7Schristos 
575*946379e7Schristos /* Free the memory pointed to by a 'struct string_buffer'.  */
576*946379e7Schristos static inline void
free_string_buffer(struct string_buffer * bp)577*946379e7Schristos free_string_buffer (struct string_buffer *bp)
578*946379e7Schristos {
579*946379e7Schristos   free (bp->utf8_buffer);
580*946379e7Schristos }
581*946379e7Schristos 
582*946379e7Schristos 
583*946379e7Schristos /* ======================== Accumulating comments.  ======================== */
584*946379e7Schristos 
585*946379e7Schristos 
586*946379e7Schristos /* Accumulating a single comment line.  */
587*946379e7Schristos 
588*946379e7Schristos static struct string_buffer comment_buffer;
589*946379e7Schristos 
590*946379e7Schristos static inline void
comment_start()591*946379e7Schristos comment_start ()
592*946379e7Schristos {
593*946379e7Schristos   comment_buffer.utf8_buflen = 0;
594*946379e7Schristos }
595*946379e7Schristos 
596*946379e7Schristos static inline bool
comment_at_start()597*946379e7Schristos comment_at_start ()
598*946379e7Schristos {
599*946379e7Schristos   return (comment_buffer.utf8_buflen == 0);
600*946379e7Schristos }
601*946379e7Schristos 
602*946379e7Schristos static inline void
comment_add(int c)603*946379e7Schristos comment_add (int c)
604*946379e7Schristos {
605*946379e7Schristos   string_buffer_append_unicode (&comment_buffer, c);
606*946379e7Schristos }
607*946379e7Schristos 
608*946379e7Schristos static inline void
comment_line_end(size_t chars_to_remove)609*946379e7Schristos comment_line_end (size_t chars_to_remove)
610*946379e7Schristos {
611*946379e7Schristos   char *buffer = string_buffer_result (&comment_buffer);
612*946379e7Schristos   size_t buflen = strlen (buffer);
613*946379e7Schristos 
614*946379e7Schristos   buflen -= chars_to_remove;
615*946379e7Schristos   while (buflen >= 1
616*946379e7Schristos 	 && (buffer[buflen - 1] == ' ' || buffer[buflen - 1] == '\t'))
617*946379e7Schristos     --buflen;
618*946379e7Schristos   buffer[buflen] = '\0';
619*946379e7Schristos   savable_comment_add (buffer);
620*946379e7Schristos }
621*946379e7Schristos 
622*946379e7Schristos 
623*946379e7Schristos /* These are for tracking whether comments count as immediately before
624*946379e7Schristos    keyword.  */
625*946379e7Schristos static int last_comment_line;
626*946379e7Schristos static int last_non_comment_line;
627*946379e7Schristos 
628*946379e7Schristos 
629*946379e7Schristos /* Phase 4: Replace each comment that is not inside a character constant or
630*946379e7Schristos    string literal with a space or newline character.
631*946379e7Schristos    See ECMA-334 section 9.3.2.  */
632*946379e7Schristos 
633*946379e7Schristos static int
phase4_getc()634*946379e7Schristos phase4_getc ()
635*946379e7Schristos {
636*946379e7Schristos   int c0;
637*946379e7Schristos   int c;
638*946379e7Schristos   bool last_was_star;
639*946379e7Schristos 
640*946379e7Schristos   c0 = phase3_getc ();
641*946379e7Schristos   if (c0 != '/')
642*946379e7Schristos     return c0;
643*946379e7Schristos   c = phase3_getc ();
644*946379e7Schristos   switch (c)
645*946379e7Schristos     {
646*946379e7Schristos     default:
647*946379e7Schristos       phase3_ungetc (c);
648*946379e7Schristos       return c0;
649*946379e7Schristos 
650*946379e7Schristos     case '*':
651*946379e7Schristos       /* C style comment.  */
652*946379e7Schristos       comment_start ();
653*946379e7Schristos       last_was_star = false;
654*946379e7Schristos       for (;;)
655*946379e7Schristos 	{
656*946379e7Schristos 	  c = phase3_getc ();
657*946379e7Schristos 	  if (c == UEOF)
658*946379e7Schristos 	    break;
659*946379e7Schristos 	  /* We skip all leading white space, but not EOLs.  */
660*946379e7Schristos 	  if (!(comment_at_start () && (c == ' ' || c == '\t')))
661*946379e7Schristos 	    comment_add (c);
662*946379e7Schristos 	  switch (c)
663*946379e7Schristos 	    {
664*946379e7Schristos 	    case UNL:
665*946379e7Schristos 	      comment_line_end (1);
666*946379e7Schristos 	      comment_start ();
667*946379e7Schristos 	      last_was_star = false;
668*946379e7Schristos 	      continue;
669*946379e7Schristos 
670*946379e7Schristos 	    case '*':
671*946379e7Schristos 	      last_was_star = true;
672*946379e7Schristos 	      continue;
673*946379e7Schristos 
674*946379e7Schristos 	    case '/':
675*946379e7Schristos 	      if (last_was_star)
676*946379e7Schristos 		{
677*946379e7Schristos 		  comment_line_end (2);
678*946379e7Schristos 		  break;
679*946379e7Schristos 		}
680*946379e7Schristos 	      /* FALLTHROUGH */
681*946379e7Schristos 
682*946379e7Schristos 	    default:
683*946379e7Schristos 	      last_was_star = false;
684*946379e7Schristos 	      continue;
685*946379e7Schristos 	    }
686*946379e7Schristos 	  break;
687*946379e7Schristos 	}
688*946379e7Schristos       last_comment_line = logical_line_number;
689*946379e7Schristos       return ' ';
690*946379e7Schristos 
691*946379e7Schristos     case '/':
692*946379e7Schristos       /* C++ style comment.  */
693*946379e7Schristos       last_comment_line = logical_line_number;
694*946379e7Schristos       comment_start ();
695*946379e7Schristos       for (;;)
696*946379e7Schristos 	{
697*946379e7Schristos 	  c = phase3_getc ();
698*946379e7Schristos 	  if (c == UNL || c == UEOF)
699*946379e7Schristos 	    break;
700*946379e7Schristos 	  /* We skip all leading white space, but not EOLs.  */
701*946379e7Schristos 	  if (!(comment_at_start () && (c == ' ' || c == '\t')))
702*946379e7Schristos 	    comment_add (c);
703*946379e7Schristos 	}
704*946379e7Schristos       phase3_ungetc (c); /* push back the newline, to decrement logical_line_number */
705*946379e7Schristos       comment_line_end (0);
706*946379e7Schristos       phase3_getc (); /* read the newline again */
707*946379e7Schristos       return UNL;
708*946379e7Schristos     }
709*946379e7Schristos }
710*946379e7Schristos 
711*946379e7Schristos /* Supports only one pushback character.  */
712*946379e7Schristos static void
phase4_ungetc(int c)713*946379e7Schristos phase4_ungetc (int c)
714*946379e7Schristos {
715*946379e7Schristos   phase3_ungetc (c);
716*946379e7Schristos }
717*946379e7Schristos 
718*946379e7Schristos 
719*946379e7Schristos /* ======================= Character classification.  ====================== */
720*946379e7Schristos 
721*946379e7Schristos 
722*946379e7Schristos /* Return true if a given character is white space.
723*946379e7Schristos    See ECMA-334 section 9.3.3.  */
724*946379e7Schristos static bool
is_whitespace(int c)725*946379e7Schristos is_whitespace (int c)
726*946379e7Schristos {
727*946379e7Schristos   /* Unicode character class Zs, as of Unicode 4.0.  */
728*946379e7Schristos   /* grep '^[^;]*;[^;]*;Zs;' UnicodeData-4.0.0.txt */
729*946379e7Schristos   switch (c >> 8)
730*946379e7Schristos     {
731*946379e7Schristos     case 0x00:
732*946379e7Schristos       return (c == 0x0020 || c == 0x00a0);
733*946379e7Schristos     case 0x16:
734*946379e7Schristos       return (c == 0x1680);
735*946379e7Schristos     case 0x18:
736*946379e7Schristos       return (c == 0x180e);
737*946379e7Schristos     case 0x20:
738*946379e7Schristos       return ((c >= 0x2000 && c <= 0x200b) || c == 0x202f || c == 0x205f);
739*946379e7Schristos     case 0x30:
740*946379e7Schristos       return (c == 0x3000);
741*946379e7Schristos     default:
742*946379e7Schristos       return false;
743*946379e7Schristos     }
744*946379e7Schristos }
745*946379e7Schristos 
746*946379e7Schristos 
747*946379e7Schristos /* C# allows identifiers containing many Unicode characters.  We recognize
748*946379e7Schristos    them; to use an identifier with Unicode characters in a --keyword option,
749*946379e7Schristos    it must be specified in UTF-8.  */
750*946379e7Schristos 
751*946379e7Schristos static inline int
bitmap_lookup(const void * table,unsigned int uc)752*946379e7Schristos bitmap_lookup (const void *table, unsigned int uc)
753*946379e7Schristos {
754*946379e7Schristos   unsigned int index1 = uc >> 16;
755*946379e7Schristos   if (index1 < ((const int *) table)[0])
756*946379e7Schristos     {
757*946379e7Schristos       int lookup1 = ((const int *) table)[1 + index1];
758*946379e7Schristos       if (lookup1 >= 0)
759*946379e7Schristos 	{
760*946379e7Schristos 	  unsigned int index2 = (uc >> 9) & 0x7f;
761*946379e7Schristos 	  int lookup2 = ((const int *) table)[lookup1 + index2];
762*946379e7Schristos 	  if (lookup2 >= 0)
763*946379e7Schristos 	    {
764*946379e7Schristos 	      unsigned int index3 = (uc >> 5) & 0xf;
765*946379e7Schristos 	      unsigned int lookup3 = ((const int *) table)[lookup2 + index3];
766*946379e7Schristos 
767*946379e7Schristos 	      return (lookup3 >> (uc & 0x1f)) & 1;
768*946379e7Schristos 	    }
769*946379e7Schristos 	}
770*946379e7Schristos     }
771*946379e7Schristos   return 0;
772*946379e7Schristos }
773*946379e7Schristos 
774*946379e7Schristos /* Unicode character classes Lu, Ll, Lt, Lm, Lo, Nl, as of Unicode 4.0,
775*946379e7Schristos    plus the underscore.  */
776*946379e7Schristos static const
777*946379e7Schristos struct
778*946379e7Schristos   {
779*946379e7Schristos     int header[1];
780*946379e7Schristos     int level1[3];
781*946379e7Schristos     int level2[3 << 7];
782*946379e7Schristos     /*unsigned*/ int level3[34 << 4];
783*946379e7Schristos   }
784*946379e7Schristos table_identifier_start =
785*946379e7Schristos {
786*946379e7Schristos   { 3 },
787*946379e7Schristos   {     4,   132,   260 },
788*946379e7Schristos   {
789*946379e7Schristos       388,   404,   420,   436,   452,   468,   484,   500,
790*946379e7Schristos       516,   532,   548,   564,   580,    -1,   596,   612,
791*946379e7Schristos       628,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
792*946379e7Schristos       644,    -1,   660,   660,   660,   660,   660,   660,
793*946379e7Schristos       660,   660,   660,   660,   660,   660,   676,   660,
794*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
795*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
796*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
797*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
798*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   692,
799*946379e7Schristos       660,   660,   708,    -1,    -1,    -1,   660,   660,
800*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
801*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
802*946379e7Schristos       660,   660,   660,   724,    -1,    -1,    -1,    -1,
803*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
804*946379e7Schristos        -1,    -1,    -1,    -1,   740,   756,   772,   788,
805*946379e7Schristos       804,   820,   836,    -1,   852,    -1,    -1,    -1,
806*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
807*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
808*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
809*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
810*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
811*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
812*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
813*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
814*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
815*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
816*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
817*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
818*946379e7Schristos        -1,    -1,   868,   884,    -1,    -1,    -1,    -1,
819*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
820*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
821*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
822*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
823*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
824*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
825*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
826*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
827*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
828*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
829*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
830*946379e7Schristos       660,   660,   660,   660,   660,   660,   660,   660,
831*946379e7Schristos       660,   660,   660,   900,    -1,    -1,    -1,    -1,
832*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
833*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
834*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
835*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
836*946379e7Schristos        -1,    -1,    -1,    -1,   660,   916,    -1,    -1
837*946379e7Schristos   },
838*946379e7Schristos   {
839*946379e7Schristos     0x00000000, 0x00000000, 0x87FFFFFE, 0x07FFFFFE,
840*946379e7Schristos     0x00000000, 0x04200400, 0xFF7FFFFF, 0xFF7FFFFF,
841*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
842*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
843*946379e7Schristos     0xFFFFFFFF, 0x007FFFFF, 0xFFFF0000, 0xFFFFFFFF,
844*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x0003FFC3, 0x0000401F,
845*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x04000000,
846*946379e7Schristos     0xFFFFD740, 0xFFFFFFFB, 0xFFFF7FFF, 0x0FBFFFFF,
847*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
848*946379e7Schristos     0xFFFFFC03, 0xFFFFFFFF, 0xFFFF7FFF, 0x033FFFFF,
849*946379e7Schristos     0x0000FFFF, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
850*946379e7Schristos     0x000000FF, 0x00000000, 0xFFFF0000, 0x000707FF,
851*946379e7Schristos     0x00000000, 0x07FFFFFE, 0x000007FF, 0xFFFEC000,
852*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x002FFFFF, 0x9C00C060,
853*946379e7Schristos     0xFFFD0000, 0x0000FFFF, 0x0000E000, 0x00000000,
854*946379e7Schristos     0xFFFFFFFF, 0x0002003F, 0x00000000, 0x00000000,
855*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
856*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
857*946379e7Schristos     0xFFFFFFF0, 0x23FFFFFF, 0xFF010000, 0x00000003,
858*946379e7Schristos     0xFFF99FE0, 0x23C5FDFF, 0xB0000000, 0x00030003,
859*946379e7Schristos     0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
860*946379e7Schristos     0xFFFBBFE0, 0x23EDFDFF, 0x00010000, 0x00000003,
861*946379e7Schristos     0xFFF99FE0, 0x23EDFDFF, 0xB0000000, 0x00020003,
862*946379e7Schristos     0xD63DC7E8, 0x03BFC718, 0x00000000, 0x00000000,
863*946379e7Schristos     0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
864*946379e7Schristos     0xFFFDDFE0, 0x23EFFDFF, 0x40000000, 0x00000003,
865*946379e7Schristos     0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
866*946379e7Schristos     0xFC7FFFE0, 0x2FFBFFFF, 0x0000007F, 0x00000000,
867*946379e7Schristos     0xFFFFFFFE, 0x000DFFFF, 0x0000007F, 0x00000000,
868*946379e7Schristos     0xFEF02596, 0x200DECAE, 0x3000005F, 0x00000000,
869*946379e7Schristos     0x00000001, 0x00000000, 0xFFFFFEFF, 0x000007FF,
870*946379e7Schristos     0x00000F00, 0x00000000, 0x00000000, 0x00000000,
871*946379e7Schristos     0xFFFFFFFF, 0x000006FB, 0x003F0000, 0x00000000,
872*946379e7Schristos     0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x01FFFFFF,
873*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x83FFFFFF, 0xFFFFFFFF,
874*946379e7Schristos     0xFFFFFFFF, 0xFFFFFF07, 0xFFFFFFFF, 0x03FFFFFF,
875*946379e7Schristos     0xFFFFFF7F, 0xFFFFFFFF, 0x3D7F3D7F, 0xFFFFFFFF,
876*946379e7Schristos     0xFFFF3D7F, 0x7F3D7FFF, 0xFF7F7F3D, 0xFFFF7FFF,
877*946379e7Schristos     0x7F3D7FFF, 0xFFFFFFFF, 0x07FFFF7F, 0x00000000,
878*946379e7Schristos     0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x001FFFFF,
879*946379e7Schristos     0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
880*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
881*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
882*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
883*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x007F9FFF,
884*946379e7Schristos     0x07FFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x0001C7FF,
885*946379e7Schristos     0x0003DFFF, 0x0003FFFF, 0x0003FFFF, 0x0001DFFF,
886*946379e7Schristos     0xFFFFFFFF, 0x000FFFFF, 0x10800000, 0x00000000,
887*946379e7Schristos     0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00FFFFFF,
888*946379e7Schristos     0xFFFFFFFF, 0x000001FF, 0x00000000, 0x00000000,
889*946379e7Schristos     0x1FFFFFFF, 0x00000000, 0xFFFF0000, 0x001F3FFF,
890*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
891*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
892*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
893*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000FFF,
894*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
895*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
896*946379e7Schristos     0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
897*946379e7Schristos     0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
898*946379e7Schristos     0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
899*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x80020000,
900*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
901*946379e7Schristos     0x3E2FFC84, 0xE3FBBD50, 0x000003E0, 0xFFFFFFFF,
902*946379e7Schristos     0x0000000F, 0x00000000, 0x00000000, 0x00000000,
903*946379e7Schristos     0x000000E0, 0x1F3E03FE, 0xFFFFFFFE, 0xFFFFFFFF,
904*946379e7Schristos     0xE07FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xF7FFFFFF,
905*946379e7Schristos     0xFFFFFFE0, 0xFFFE1FFF, 0xFFFFFFFF, 0xFFFFFFFF,
906*946379e7Schristos     0x00007FFF, 0x00FFFFFF, 0x00000000, 0xFFFF0000,
907*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
908*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
909*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
910*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
911*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
912*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
913*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
914*946379e7Schristos     0xFFFFFFFF, 0x003FFFFF, 0x00000000, 0x00000000,
915*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
916*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
917*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
918*946379e7Schristos     0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
919*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
920*946379e7Schristos     0x00001FFF, 0x00000000, 0x00000000, 0x00000000,
921*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
922*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
923*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
924*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
925*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
926*946379e7Schristos     0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
927*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
928*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
929*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
930*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
931*946379e7Schristos     0xFFFFFFFF, 0xFFFF3FFF, 0xFFFFFFFF, 0x000007FF,
932*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
933*946379e7Schristos     0xA0F8007F, 0x5F7FFDFF, 0xFFFFFFDB, 0xFFFFFFFF,
934*946379e7Schristos     0xFFFFFFFF, 0x0003FFFF, 0xFFF80000, 0xFFFFFFFF,
935*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
936*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
937*946379e7Schristos     0xFFFFFFFF, 0x3FFFFFFF, 0xFFFF0000, 0xFFFFFFFF,
938*946379e7Schristos     0xFFFCFFFF, 0xFFFFFFFF, 0x000000FF, 0x0FFF0000,
939*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0xFFDF0000,
940*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x1FFFFFFF,
941*946379e7Schristos     0x00000000, 0x07FFFFFE, 0x07FFFFFE, 0xFFFFFFC0,
942*946379e7Schristos     0xFFFFFFFF, 0x7FFFFFFF, 0x1CFCFCFC, 0x00000000,
943*946379e7Schristos     0xFFFFEFFF, 0xB7FFFF7F, 0x3FFF3FFF, 0x00000000,
944*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x07FFFFFF,
945*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
946*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
947*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
948*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
949*946379e7Schristos     0x7FFFFFFF, 0xFFFF0000, 0x000007FF, 0x00000000,
950*946379e7Schristos     0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
951*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
952*946379e7Schristos     0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
953*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
954*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
955*946379e7Schristos     0xFFFFFD3F, 0x91BFFFFF, 0x00000000, 0x00000000,
956*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
957*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
958*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
959*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFDFFFFF, 0xFFFFFFFF,
960*946379e7Schristos     0xDFFFFFFF, 0xEBFFDE64, 0xFFFFFFEF, 0xFFFFFFFF,
961*946379e7Schristos     0xDFDFE7BF, 0x7BFFFFFF, 0xFFFDFC5F, 0xFFFFFFFF,
962*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
963*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
964*946379e7Schristos     0xFFFFFFFF, 0xFFFFFF0F, 0xF7FFFFFD, 0xF7FFFFFF,
965*946379e7Schristos     0xFFDFFFFF, 0xFFDFFFFF, 0xFFFF7FFF, 0xFFFF7FFF,
966*946379e7Schristos     0xFFFFFDFF, 0xFFFFFDFF, 0x000003F7, 0x00000000,
967*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
968*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x007FFFFF, 0x00000000,
969*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
970*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
971*946379e7Schristos     0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
972*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
973*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
974*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000
975*946379e7Schristos   }
976*946379e7Schristos };
977*946379e7Schristos 
978*946379e7Schristos /* Unicode character classes Lu, Ll, Lt, Lm, Lo, Nl, Nd, Pc, Mn, Mc, Cf,
979*946379e7Schristos    as of Unicode 4.0.  */
980*946379e7Schristos static const
981*946379e7Schristos struct
982*946379e7Schristos   {
983*946379e7Schristos     int header[1];
984*946379e7Schristos     int level1[15];
985*946379e7Schristos     int level2[4 << 7];
986*946379e7Schristos     /*unsigned*/ int level3[36 << 4];
987*946379e7Schristos   }
988*946379e7Schristos table_identifier_part =
989*946379e7Schristos {
990*946379e7Schristos   { 15 },
991*946379e7Schristos   {
992*946379e7Schristos        16,   144,   272,    -1,    -1,    -1,    -1,    -1,
993*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,   400
994*946379e7Schristos   },
995*946379e7Schristos   {
996*946379e7Schristos       528,   544,   560,   576,   592,   608,   624,   640,
997*946379e7Schristos       656,   672,   688,   704,   720,    -1,   736,   752,
998*946379e7Schristos       768,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
999*946379e7Schristos       784,    -1,   800,   800,   800,   800,   800,   800,
1000*946379e7Schristos       800,   800,   800,   800,   800,   800,   816,   800,
1001*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1002*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1003*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1004*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1005*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   832,
1006*946379e7Schristos       800,   800,   848,    -1,    -1,    -1,   800,   800,
1007*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1008*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1009*946379e7Schristos       800,   800,   800,   864,    -1,    -1,    -1,    -1,
1010*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1011*946379e7Schristos        -1,    -1,    -1,    -1,   880,   896,   912,   928,
1012*946379e7Schristos       944,   960,   976,    -1,   992,    -1,    -1,    -1,
1013*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1014*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1015*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1016*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1017*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1018*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1019*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1020*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1021*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1022*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1023*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1024*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1025*946379e7Schristos      1008,    -1,  1024,  1040,    -1,    -1,    -1,    -1,
1026*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1027*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1028*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1029*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1030*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1031*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1032*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1033*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1034*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1035*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1036*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1037*946379e7Schristos       800,   800,   800,   800,   800,   800,   800,   800,
1038*946379e7Schristos       800,   800,   800,  1056,    -1,    -1,    -1,    -1,
1039*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1040*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1041*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1042*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1043*946379e7Schristos        -1,    -1,    -1,    -1,   800,  1072,    -1,    -1,
1044*946379e7Schristos      1088,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1045*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1046*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1047*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1048*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1049*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1050*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1051*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1052*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1053*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1054*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1055*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1056*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1057*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1058*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
1059*946379e7Schristos        -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1
1060*946379e7Schristos   },
1061*946379e7Schristos   {
1062*946379e7Schristos     0x00000000, 0x03FF0000, 0x87FFFFFE, 0x07FFFFFE,
1063*946379e7Schristos     0x00000000, 0x04202400, 0xFF7FFFFF, 0xFF7FFFFF,
1064*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1065*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1066*946379e7Schristos     0xFFFFFFFF, 0x007FFFFF, 0xFFFF0000, 0xFFFFFFFF,
1067*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x0003FFC3, 0x0000401F,
1068*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xE0FFFFFF, 0x0400FFFF,
1069*946379e7Schristos     0xFFFFD740, 0xFFFFFFFB, 0xFFFF7FFF, 0x0FBFFFFF,
1070*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1071*946379e7Schristos     0xFFFFFC7B, 0xFFFFFFFF, 0xFFFF7FFF, 0x033FFFFF,
1072*946379e7Schristos     0x0000FFFF, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
1073*946379e7Schristos     0xFFFE00FF, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
1074*946379e7Schristos     0x003F000F, 0x07FFFFFE, 0x01FFFFFF, 0xFFFFC3FF,
1075*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xBFEFFFFF, 0x9FFFFDFF,
1076*946379e7Schristos     0xFFFF8000, 0xFFFFFFFF, 0x0000E7FF, 0x00000000,
1077*946379e7Schristos     0xFFFFFFFF, 0x0003FFFF, 0x00000000, 0x00000000,
1078*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1079*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1080*946379e7Schristos     0xFFFFFFFE, 0xF3FFFFFF, 0xFF1F3FFF, 0x0000FFCF,
1081*946379e7Schristos     0xFFF99FEE, 0xF3C5FDFF, 0xB080399F, 0x0003FFCF,
1082*946379e7Schristos     0xFFF987EE, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
1083*946379e7Schristos     0xFFFBBFEE, 0xF3EDFDFF, 0x00013BBF, 0x0000FFCF,
1084*946379e7Schristos     0xFFF99FEE, 0xF3EDFDFF, 0xB0C0398F, 0x0002FFC3,
1085*946379e7Schristos     0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
1086*946379e7Schristos     0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
1087*946379e7Schristos     0xFFFDDFEC, 0xF3EFFDFF, 0x40603DDF, 0x0000FFC3,
1088*946379e7Schristos     0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
1089*946379e7Schristos     0xFC7FFFEC, 0x2FFBFFFF, 0xFF5F847F, 0x000C0000,
1090*946379e7Schristos     0xFFFFFFFE, 0x07FFFFFF, 0x03FF7FFF, 0x00000000,
1091*946379e7Schristos     0xFEF02596, 0x3BFFECAE, 0x33FF3F5F, 0x00000000,
1092*946379e7Schristos     0x03000001, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE07FF,
1093*946379e7Schristos     0xFEFF0FDF, 0x1FFFFFFF, 0x00000040, 0x00000000,
1094*946379e7Schristos     0xFFFFFFFF, 0x03C7F6FB, 0x03FF03FF, 0x00000000,
1095*946379e7Schristos     0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x01FFFFFF,
1096*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x83FFFFFF, 0xFFFFFFFF,
1097*946379e7Schristos     0xFFFFFFFF, 0xFFFFFF07, 0xFFFFFFFF, 0x03FFFFFF,
1098*946379e7Schristos     0xFFFFFF7F, 0xFFFFFFFF, 0x3D7F3D7F, 0xFFFFFFFF,
1099*946379e7Schristos     0xFFFF3D7F, 0x7F3D7FFF, 0xFF7F7F3D, 0xFFFF7FFF,
1100*946379e7Schristos     0x7F3D7FFF, 0xFFFFFFFF, 0x07FFFF7F, 0x0003FE00,
1101*946379e7Schristos     0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x001FFFFF,
1102*946379e7Schristos     0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1103*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1104*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1105*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1106*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x007F9FFF,
1107*946379e7Schristos     0x07FFFFFE, 0xFFFFFFFF, 0xFFFFFFFF, 0x0001C7FF,
1108*946379e7Schristos     0x001FDFFF, 0x001FFFFF, 0x000FFFFF, 0x000DDFFF,
1109*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x308FFFFF, 0x000003FF,
1110*946379e7Schristos     0x03FF3800, 0xFFFFFFFF, 0xFFFFFFFF, 0x00FFFFFF,
1111*946379e7Schristos     0xFFFFFFFF, 0x000003FF, 0x00000000, 0x00000000,
1112*946379e7Schristos     0x1FFFFFFF, 0x0FFF0FFF, 0xFFFFFFC0, 0x001F3FFF,
1113*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1114*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1115*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1116*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000FFF,
1117*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1118*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1119*946379e7Schristos     0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
1120*946379e7Schristos     0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
1121*946379e7Schristos     0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
1122*946379e7Schristos     0x0000F000, 0x80007C00, 0x00100001, 0x8002FC0F,
1123*946379e7Schristos     0x00000000, 0x00000000, 0x1FFF0000, 0x000007E2,
1124*946379e7Schristos     0x3E2FFC84, 0xE3FBBD50, 0x000003E0, 0xFFFFFFFF,
1125*946379e7Schristos     0x0000000F, 0x00000000, 0x00000000, 0x00000000,
1126*946379e7Schristos     0x000000E0, 0x1F3EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
1127*946379e7Schristos     0xE67FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0xFFFFFFFF,
1128*946379e7Schristos     0xFFFFFFE0, 0xFFFE1FFF, 0xFFFFFFFF, 0xFFFFFFFF,
1129*946379e7Schristos     0x00007FFF, 0x00FFFFFF, 0x00000000, 0xFFFF0000,
1130*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1131*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1132*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1133*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1134*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1135*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1136*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1137*946379e7Schristos     0xFFFFFFFF, 0x003FFFFF, 0x00000000, 0x00000000,
1138*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1139*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1140*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1141*946379e7Schristos     0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
1142*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1143*946379e7Schristos     0x00001FFF, 0x00000000, 0x00000000, 0x00000000,
1144*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1145*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1146*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1147*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1148*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1149*946379e7Schristos     0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
1150*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1151*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1152*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1153*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1154*946379e7Schristos     0xFFFFFFFF, 0xFFFF3FFF, 0xFFFFFFFF, 0x000007FF,
1155*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1156*946379e7Schristos     0xE0F8007F, 0x5F7FFDFF, 0xFFFFFFDB, 0xFFFFFFFF,
1157*946379e7Schristos     0xFFFFFFFF, 0x0003FFFF, 0xFFF80000, 0xFFFFFFFF,
1158*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1159*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1160*946379e7Schristos     0xFFFFFFFF, 0x3FFFFFFF, 0xFFFF0000, 0xFFFFFFFF,
1161*946379e7Schristos     0xFFFCFFFF, 0xFFFFFFFF, 0x000000FF, 0x0FFF0000,
1162*946379e7Schristos     0x0000FFFF, 0x0018000F, 0x0000E000, 0xFFDF0000,
1163*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x9FFFFFFF,
1164*946379e7Schristos     0x03FF0000, 0x87FFFFFE, 0x07FFFFFE, 0xFFFFFFE0,
1165*946379e7Schristos     0xFFFFFFFF, 0x7FFFFFFF, 0x1CFCFCFC, 0x0E000000,
1166*946379e7Schristos     0xFFFFEFFF, 0xB7FFFF7F, 0x3FFF3FFF, 0x00000000,
1167*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x07FFFFFF,
1168*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1169*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1170*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1171*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1172*946379e7Schristos     0x7FFFFFFF, 0xFFFF0000, 0x000007FF, 0x00000000,
1173*946379e7Schristos     0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
1174*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1175*946379e7Schristos     0x3FFFFFFF, 0x000003FF, 0x00000000, 0x00000000,
1176*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1177*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1178*946379e7Schristos     0xFFFFFD3F, 0x91BFFFFF, 0x00000000, 0x00000000,
1179*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1180*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1181*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1182*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1183*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1184*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0xFFFFE3E0,
1185*946379e7Schristos     0x00000FE7, 0x00003C00, 0x00000000, 0x00000000,
1186*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFDFFFFF, 0xFFFFFFFF,
1187*946379e7Schristos     0xDFFFFFFF, 0xEBFFDE64, 0xFFFFFFEF, 0xFFFFFFFF,
1188*946379e7Schristos     0xDFDFE7BF, 0x7BFFFFFF, 0xFFFDFC5F, 0xFFFFFFFF,
1189*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1190*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1191*946379e7Schristos     0xFFFFFFFF, 0xFFFFFF0F, 0xF7FFFFFD, 0xF7FFFFFF,
1192*946379e7Schristos     0xFFDFFFFF, 0xFFDFFFFF, 0xFFFF7FFF, 0xFFFF7FFF,
1193*946379e7Schristos     0xFFFFFDFF, 0xFFFFFDFF, 0xFFFFC3F7, 0xFFFFFFFF,
1194*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1195*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0x007FFFFF, 0x00000000,
1196*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1197*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1198*946379e7Schristos     0x3FFFFFFF, 0x00000000, 0x00000000, 0x00000000,
1199*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1200*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1201*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1202*946379e7Schristos     0x00000002, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1203*946379e7Schristos     0x00000000, 0x00000000, 0x00000000, 0x00000000,
1204*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
1205*946379e7Schristos     0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF
1206*946379e7Schristos   }
1207*946379e7Schristos };
1208*946379e7Schristos 
1209*946379e7Schristos /* Return true if a given character can occur as first character of an
1210*946379e7Schristos    identifier.  See ECMA-334 section 9.4.2.  */
1211*946379e7Schristos static bool
is_identifier_start(int c)1212*946379e7Schristos is_identifier_start (int c)
1213*946379e7Schristos {
1214*946379e7Schristos   return bitmap_lookup (&table_identifier_start, c);
1215*946379e7Schristos   /* In ASCII only this would be:
1216*946379e7Schristos      return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_');
1217*946379e7Schristos    */
1218*946379e7Schristos }
1219*946379e7Schristos 
1220*946379e7Schristos /* Return true if a given character can occur as character of an identifier.
1221*946379e7Schristos    See ECMA-334 section 9.4.2.  */
1222*946379e7Schristos static bool
is_identifier_part(int c)1223*946379e7Schristos is_identifier_part (int c)
1224*946379e7Schristos {
1225*946379e7Schristos   return bitmap_lookup (&table_identifier_part, c);
1226*946379e7Schristos   /* In ASCII only this would be:
1227*946379e7Schristos      return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
1228*946379e7Schristos              || (c >= '0' && c <= '9') || c == '_');
1229*946379e7Schristos    */
1230*946379e7Schristos }
1231*946379e7Schristos 
1232*946379e7Schristos static bool
is_any_character(int c)1233*946379e7Schristos is_any_character (int c)
1234*946379e7Schristos {
1235*946379e7Schristos   return true;
1236*946379e7Schristos }
1237*946379e7Schristos 
1238*946379e7Schristos 
1239*946379e7Schristos /* ======================= Preprocessor directives.  ======================= */
1240*946379e7Schristos 
1241*946379e7Schristos 
1242*946379e7Schristos /* Phase 5: Remove preprocessor lines.  See ECMA-334 section 9.5.
1243*946379e7Schristos    As a side effect, this also removes initial whitespace on every line;
1244*946379e7Schristos    this whitespace doesn't matter.  */
1245*946379e7Schristos 
1246*946379e7Schristos static int phase5_pushback[10];
1247*946379e7Schristos static int phase5_pushback_length;
1248*946379e7Schristos 
1249*946379e7Schristos static int
phase5_getc()1250*946379e7Schristos phase5_getc ()
1251*946379e7Schristos {
1252*946379e7Schristos   int c;
1253*946379e7Schristos 
1254*946379e7Schristos   if (phase5_pushback_length)
1255*946379e7Schristos     return phase5_pushback[--phase5_pushback_length];
1256*946379e7Schristos 
1257*946379e7Schristos   c = phase4_getc ();
1258*946379e7Schristos   if (c != UNL)
1259*946379e7Schristos     return c;
1260*946379e7Schristos 
1261*946379e7Schristos   do
1262*946379e7Schristos     c = phase3_getc ();
1263*946379e7Schristos   while (c != UEOF && is_whitespace (c));
1264*946379e7Schristos 
1265*946379e7Schristos   if (c == '#')
1266*946379e7Schristos     {
1267*946379e7Schristos       /* Ignore the entire line containing the preprocessor directive
1268*946379e7Schristos 	 (including the // comment if it contains one).  */
1269*946379e7Schristos       do
1270*946379e7Schristos 	c = phase3_getc ();
1271*946379e7Schristos       while (c != UEOF && c != UNL);
1272*946379e7Schristos       return c;
1273*946379e7Schristos     }
1274*946379e7Schristos   else
1275*946379e7Schristos     {
1276*946379e7Schristos       phase3_ungetc (c);
1277*946379e7Schristos       return UNL;
1278*946379e7Schristos     }
1279*946379e7Schristos }
1280*946379e7Schristos 
1281*946379e7Schristos #ifdef unused
1282*946379e7Schristos static void
phase5_ungetc(int c)1283*946379e7Schristos phase5_ungetc (int c)
1284*946379e7Schristos {
1285*946379e7Schristos   if (c != UEOF)
1286*946379e7Schristos     {
1287*946379e7Schristos       if (phase5_pushback_length == SIZEOF (phase5_pushback))
1288*946379e7Schristos 	abort ();
1289*946379e7Schristos       phase5_pushback[phase5_pushback_length++] = c;
1290*946379e7Schristos     }
1291*946379e7Schristos }
1292*946379e7Schristos #endif
1293*946379e7Schristos 
1294*946379e7Schristos 
1295*946379e7Schristos /* ========================== Reading of tokens.  ========================== */
1296*946379e7Schristos 
1297*946379e7Schristos enum token_type_ty
1298*946379e7Schristos {
1299*946379e7Schristos   token_type_eof,
1300*946379e7Schristos   token_type_lparen,		/* ( */
1301*946379e7Schristos   token_type_rparen,		/* ) */
1302*946379e7Schristos   token_type_lbrace,		/* { */
1303*946379e7Schristos   token_type_rbrace,		/* } */
1304*946379e7Schristos   token_type_comma,		/* , */
1305*946379e7Schristos   token_type_dot,		/* . */
1306*946379e7Schristos   token_type_string_literal,	/* "abc", @"abc" */
1307*946379e7Schristos   token_type_number,		/* 1.23 */
1308*946379e7Schristos   token_type_symbol,		/* identifier, keyword, null */
1309*946379e7Schristos   token_type_plus,		/* + */
1310*946379e7Schristos   token_type_other		/* character literal, misc. operator */
1311*946379e7Schristos };
1312*946379e7Schristos typedef enum token_type_ty token_type_ty;
1313*946379e7Schristos 
1314*946379e7Schristos typedef struct token_ty token_ty;
1315*946379e7Schristos struct token_ty
1316*946379e7Schristos {
1317*946379e7Schristos   token_type_ty type;
1318*946379e7Schristos   char *string;		/* for token_type_string_literal, token_type_symbol */
1319*946379e7Schristos   refcounted_string_list_ty *comment;	/* for token_type_string_literal */
1320*946379e7Schristos   int line_number;
1321*946379e7Schristos   int logical_line_number;
1322*946379e7Schristos };
1323*946379e7Schristos 
1324*946379e7Schristos 
1325*946379e7Schristos /* Free the memory pointed to by a 'struct token_ty'.  */
1326*946379e7Schristos static inline void
free_token(token_ty * tp)1327*946379e7Schristos free_token (token_ty *tp)
1328*946379e7Schristos {
1329*946379e7Schristos   if (tp->type == token_type_string_literal || tp->type == token_type_symbol)
1330*946379e7Schristos     free (tp->string);
1331*946379e7Schristos   if (tp->type == token_type_string_literal)
1332*946379e7Schristos     drop_reference (tp->comment);
1333*946379e7Schristos }
1334*946379e7Schristos 
1335*946379e7Schristos 
1336*946379e7Schristos /* Read a Unicode escape sequence outside string/character literals.
1337*946379e7Schristos    Reject Unicode escapes that don't fulfill the given predicate.
1338*946379e7Schristos    See ECMA-334 section 9.4.2.  */
1339*946379e7Schristos static int
do_getc_unicode_escaped(bool (* predicate)(int))1340*946379e7Schristos do_getc_unicode_escaped (bool (*predicate) (int))
1341*946379e7Schristos {
1342*946379e7Schristos   int c;
1343*946379e7Schristos 
1344*946379e7Schristos   /* Use phase 3, because phase 4 elides comments.  */
1345*946379e7Schristos   c = phase3_getc ();
1346*946379e7Schristos   if (c == UEOF)
1347*946379e7Schristos     return '\\';
1348*946379e7Schristos   if (c == 'u' || c == 'U')
1349*946379e7Schristos     {
1350*946379e7Schristos       unsigned char buf[8];
1351*946379e7Schristos       int expect;
1352*946379e7Schristos       unsigned int n;
1353*946379e7Schristos       int i;
1354*946379e7Schristos 
1355*946379e7Schristos       expect = (c == 'U' ? 8 : 4);
1356*946379e7Schristos       n = 0;
1357*946379e7Schristos       for (i = 0; i < expect; i++)
1358*946379e7Schristos 	{
1359*946379e7Schristos 	  int c1 = phase3_getc ();
1360*946379e7Schristos 
1361*946379e7Schristos 	  if (c1 >= '0' && c1 <= '9')
1362*946379e7Schristos 	    n = (n << 4) + (c1 - '0');
1363*946379e7Schristos 	  else if (c1 >= 'A' && c1 <= 'F')
1364*946379e7Schristos 	    n = (n << 4) + (c1 - 'A' + 10);
1365*946379e7Schristos 	  else if (c1 >= 'a' && c1 <= 'f')
1366*946379e7Schristos 	    n = (n << 4) + (c1 - 'a' + 10);
1367*946379e7Schristos 	  else
1368*946379e7Schristos 	    {
1369*946379e7Schristos 	      phase3_ungetc (c1);
1370*946379e7Schristos 	      while (--i >= 0)
1371*946379e7Schristos 		phase3_ungetc (buf[i]);
1372*946379e7Schristos 	      phase3_ungetc (c);
1373*946379e7Schristos 	      return '\\';
1374*946379e7Schristos 	    }
1375*946379e7Schristos 
1376*946379e7Schristos 	  buf[i] = c1;
1377*946379e7Schristos 	}
1378*946379e7Schristos 
1379*946379e7Schristos       if (n >= 0x110000)
1380*946379e7Schristos 	{
1381*946379e7Schristos 	  error_with_progname = false;
1382*946379e7Schristos 	  error (0, 0, _("%s:%d: warning: invalid Unicode character"),
1383*946379e7Schristos 		 logical_file_name, line_number);
1384*946379e7Schristos 	  error_with_progname = true;
1385*946379e7Schristos 	}
1386*946379e7Schristos       else if (predicate (n))
1387*946379e7Schristos 	return n;
1388*946379e7Schristos 
1389*946379e7Schristos       while (--i >= 0)
1390*946379e7Schristos 	phase3_ungetc (buf[i]);
1391*946379e7Schristos     }
1392*946379e7Schristos   phase3_ungetc (c);
1393*946379e7Schristos   return '\\';
1394*946379e7Schristos }
1395*946379e7Schristos 
1396*946379e7Schristos 
1397*946379e7Schristos /* Read an escape sequence inside a string literal or character literal.
1398*946379e7Schristos    See ECMA-334 sections 9.4.4.4., 9.4.4.5.  */
1399*946379e7Schristos static int
do_getc_escaped()1400*946379e7Schristos do_getc_escaped ()
1401*946379e7Schristos {
1402*946379e7Schristos   int c;
1403*946379e7Schristos   int n;
1404*946379e7Schristos   int i;
1405*946379e7Schristos 
1406*946379e7Schristos   /* Use phase 3, because phase 4 elides comments.  */
1407*946379e7Schristos   c = phase3_getc ();
1408*946379e7Schristos   if (c == UEOF)
1409*946379e7Schristos     return '\\';
1410*946379e7Schristos   switch (c)
1411*946379e7Schristos     {
1412*946379e7Schristos     case 'a':
1413*946379e7Schristos       return 0x0007;
1414*946379e7Schristos     case 'b':
1415*946379e7Schristos       return 0x0008;
1416*946379e7Schristos     case 't':
1417*946379e7Schristos       return 0x0009;
1418*946379e7Schristos     case 'n':
1419*946379e7Schristos       return 0x000a;
1420*946379e7Schristos     case 'v':
1421*946379e7Schristos       return 0x000b;
1422*946379e7Schristos     case 'f':
1423*946379e7Schristos       return 0x000c;
1424*946379e7Schristos     case 'r':
1425*946379e7Schristos       return 0x000d;
1426*946379e7Schristos     case '"':
1427*946379e7Schristos       return '"';
1428*946379e7Schristos     case '\'':
1429*946379e7Schristos       return '\'';
1430*946379e7Schristos     case '\\':
1431*946379e7Schristos       return '\\';
1432*946379e7Schristos     case '0':
1433*946379e7Schristos       return 0x0000;
1434*946379e7Schristos     case 'x':
1435*946379e7Schristos       c = phase3_getc ();
1436*946379e7Schristos       switch (c)
1437*946379e7Schristos 	{
1438*946379e7Schristos 	default:
1439*946379e7Schristos 	  phase3_ungetc (c);
1440*946379e7Schristos 	  phase3_ungetc ('x');
1441*946379e7Schristos 	  return '\\';
1442*946379e7Schristos 
1443*946379e7Schristos 	case '0': case '1': case '2': case '3': case '4':
1444*946379e7Schristos 	case '5': case '6': case '7': case '8': case '9':
1445*946379e7Schristos 	case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1446*946379e7Schristos 	case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1447*946379e7Schristos 	  break;
1448*946379e7Schristos 	}
1449*946379e7Schristos       n = 0;
1450*946379e7Schristos       for (i = 0;; i++)
1451*946379e7Schristos 	{
1452*946379e7Schristos 	  switch (c)
1453*946379e7Schristos 	    {
1454*946379e7Schristos 	    default:
1455*946379e7Schristos 	      phase3_ungetc (c);
1456*946379e7Schristos 	      return n;
1457*946379e7Schristos 	    case '0': case '1': case '2': case '3': case '4':
1458*946379e7Schristos 	    case '5': case '6': case '7': case '8': case '9':
1459*946379e7Schristos 	      n = n * 16 + c - '0';
1460*946379e7Schristos 	      break;
1461*946379e7Schristos 	    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
1462*946379e7Schristos 	      n = n * 16 + 10 + c - 'A';
1463*946379e7Schristos 	      break;
1464*946379e7Schristos 	    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
1465*946379e7Schristos 	      n = n * 16 + 10 + c - 'a';
1466*946379e7Schristos 	      break;
1467*946379e7Schristos 	    }
1468*946379e7Schristos 	  if (i == 3)
1469*946379e7Schristos 	    break;
1470*946379e7Schristos 	  c = phase3_getc ();
1471*946379e7Schristos 	}
1472*946379e7Schristos       return n;
1473*946379e7Schristos     case 'u': case 'U':
1474*946379e7Schristos       phase3_ungetc (c);
1475*946379e7Schristos       return do_getc_unicode_escaped (is_any_character);
1476*946379e7Schristos     default:
1477*946379e7Schristos       /* Invalid escape sequence.  */
1478*946379e7Schristos       phase3_ungetc (c);
1479*946379e7Schristos       return '\\';
1480*946379e7Schristos     }
1481*946379e7Schristos }
1482*946379e7Schristos 
1483*946379e7Schristos /* Read a regular string literal or character literal.
1484*946379e7Schristos    See ECMA-334 sections 9.4.4.4., 9.4.4.5.  */
1485*946379e7Schristos static void
accumulate_escaped(struct string_buffer * literal,int delimiter)1486*946379e7Schristos accumulate_escaped (struct string_buffer *literal, int delimiter)
1487*946379e7Schristos {
1488*946379e7Schristos   int c;
1489*946379e7Schristos 
1490*946379e7Schristos   for (;;)
1491*946379e7Schristos     {
1492*946379e7Schristos       /* Use phase 3, because phase 4 elides comments.  */
1493*946379e7Schristos       c = phase3_getc ();
1494*946379e7Schristos       if (c == UEOF || c == delimiter)
1495*946379e7Schristos 	break;
1496*946379e7Schristos       if (c == UNL)
1497*946379e7Schristos 	{
1498*946379e7Schristos 	  phase3_ungetc (c);
1499*946379e7Schristos 	  error_with_progname = false;
1500*946379e7Schristos 	  if (delimiter == '\'')
1501*946379e7Schristos 	    error (0, 0, _("%s:%d: warning: unterminated character constant"),
1502*946379e7Schristos 		   logical_file_name, line_number);
1503*946379e7Schristos 	  else
1504*946379e7Schristos 	    error (0, 0, _("%s:%d: warning: unterminated string constant"),
1505*946379e7Schristos 		   logical_file_name, line_number);
1506*946379e7Schristos 	  error_with_progname = true;
1507*946379e7Schristos 	  break;
1508*946379e7Schristos 	}
1509*946379e7Schristos       if (c == '\\')
1510*946379e7Schristos 	c = do_getc_escaped ();
1511*946379e7Schristos       string_buffer_append_unicode (literal, c);
1512*946379e7Schristos     }
1513*946379e7Schristos }
1514*946379e7Schristos 
1515*946379e7Schristos 
1516*946379e7Schristos /* Combine characters into tokens.  Discard whitespace.  */
1517*946379e7Schristos 
1518*946379e7Schristos /* Maximum used guaranteed to be < 4.  */
1519*946379e7Schristos static token_ty phase6_pushback[4];
1520*946379e7Schristos static int phase6_pushback_length;
1521*946379e7Schristos 
1522*946379e7Schristos static void
phase6_get(token_ty * tp)1523*946379e7Schristos phase6_get (token_ty *tp)
1524*946379e7Schristos {
1525*946379e7Schristos   int c;
1526*946379e7Schristos 
1527*946379e7Schristos   if (phase6_pushback_length)
1528*946379e7Schristos     {
1529*946379e7Schristos       *tp = phase6_pushback[--phase6_pushback_length];
1530*946379e7Schristos       return;
1531*946379e7Schristos     }
1532*946379e7Schristos   tp->string = NULL;
1533*946379e7Schristos 
1534*946379e7Schristos   for (;;)
1535*946379e7Schristos     {
1536*946379e7Schristos       tp->line_number = line_number;
1537*946379e7Schristos       tp->logical_line_number = logical_line_number;
1538*946379e7Schristos       c = phase5_getc ();
1539*946379e7Schristos 
1540*946379e7Schristos       if (c == UEOF)
1541*946379e7Schristos 	{
1542*946379e7Schristos 	  tp->type = token_type_eof;
1543*946379e7Schristos 	  return;
1544*946379e7Schristos 	}
1545*946379e7Schristos 
1546*946379e7Schristos       switch (c)
1547*946379e7Schristos 	{
1548*946379e7Schristos 	case UNL:
1549*946379e7Schristos 	  if (last_non_comment_line > last_comment_line)
1550*946379e7Schristos 	    savable_comment_reset ();
1551*946379e7Schristos 	  /* FALLTHROUGH */
1552*946379e7Schristos 	case ' ':
1553*946379e7Schristos 	case '\t':
1554*946379e7Schristos 	case '\f':
1555*946379e7Schristos 	  /* Ignore whitespace and comments.  */
1556*946379e7Schristos 	  continue;
1557*946379e7Schristos 	}
1558*946379e7Schristos 
1559*946379e7Schristos       last_non_comment_line = tp->logical_line_number;
1560*946379e7Schristos 
1561*946379e7Schristos       switch (c)
1562*946379e7Schristos 	{
1563*946379e7Schristos 	case '(':
1564*946379e7Schristos 	  tp->type = token_type_lparen;
1565*946379e7Schristos 	  return;
1566*946379e7Schristos 
1567*946379e7Schristos 	case ')':
1568*946379e7Schristos 	  tp->type = token_type_rparen;
1569*946379e7Schristos 	  return;
1570*946379e7Schristos 
1571*946379e7Schristos 	case '{':
1572*946379e7Schristos 	  tp->type = token_type_lbrace;
1573*946379e7Schristos 	  return;
1574*946379e7Schristos 
1575*946379e7Schristos 	case '}':
1576*946379e7Schristos 	  tp->type = token_type_rbrace;
1577*946379e7Schristos 	  return;
1578*946379e7Schristos 
1579*946379e7Schristos 	case ',':
1580*946379e7Schristos 	  tp->type = token_type_comma;
1581*946379e7Schristos 	  return;
1582*946379e7Schristos 
1583*946379e7Schristos 	case '.':
1584*946379e7Schristos 	  c = phase4_getc ();
1585*946379e7Schristos 	  if (!(c >= '0' && c <= '9'))
1586*946379e7Schristos 	    {
1587*946379e7Schristos 	      phase4_ungetc (c);
1588*946379e7Schristos 	      tp->type = token_type_dot;
1589*946379e7Schristos 	      return;
1590*946379e7Schristos 	    }
1591*946379e7Schristos 	  /* FALLTHROUGH */
1592*946379e7Schristos 
1593*946379e7Schristos 	case '0': case '1': case '2': case '3': case '4':
1594*946379e7Schristos 	case '5': case '6': case '7': case '8': case '9':
1595*946379e7Schristos 	  {
1596*946379e7Schristos 	    /* Don't need to verify the complicated syntax of integers and
1597*946379e7Schristos 	       floating-point numbers.  We assume a valid C# input.
1598*946379e7Schristos 	       The simplified syntax that we recognize as number is: any
1599*946379e7Schristos 	       sequence of alphanumeric characters, additionally '+' and '-'
1600*946379e7Schristos 	       immediately after 'e' or 'E' except in hexadecimal numbers.  */
1601*946379e7Schristos 	    bool hexadecimal = false;
1602*946379e7Schristos 
1603*946379e7Schristos 	    for (;;)
1604*946379e7Schristos 	      {
1605*946379e7Schristos 		c = phase4_getc ();
1606*946379e7Schristos 		if (c >= '0' && c <= '9')
1607*946379e7Schristos 		  continue;
1608*946379e7Schristos 		if ((c >= 'A' && c <= 'Z') || (c >= 'a' &&c <= 'z'))
1609*946379e7Schristos 		  {
1610*946379e7Schristos 		    if (c == 'X' || c == 'x')
1611*946379e7Schristos 		      hexadecimal = true;
1612*946379e7Schristos 		    if ((c == 'E' || c == 'e') && !hexadecimal)
1613*946379e7Schristos 		      {
1614*946379e7Schristos 			c = phase4_getc ();
1615*946379e7Schristos 			if (!(c == '+' || c == '-'))
1616*946379e7Schristos 			  phase4_ungetc (c);
1617*946379e7Schristos 		      }
1618*946379e7Schristos 		    continue;
1619*946379e7Schristos 		  }
1620*946379e7Schristos 		if (c == '.')
1621*946379e7Schristos 		  continue;
1622*946379e7Schristos 		break;
1623*946379e7Schristos 	      }
1624*946379e7Schristos 	    phase4_ungetc (c);
1625*946379e7Schristos 	    tp->type = token_type_number;
1626*946379e7Schristos 	    return;
1627*946379e7Schristos 	  }
1628*946379e7Schristos 
1629*946379e7Schristos 	case '"':
1630*946379e7Schristos 	  /* Regular string literal.  */
1631*946379e7Schristos 	  {
1632*946379e7Schristos 	    struct string_buffer literal;
1633*946379e7Schristos 
1634*946379e7Schristos 	    init_string_buffer (&literal);
1635*946379e7Schristos 	    accumulate_escaped (&literal, '"');
1636*946379e7Schristos 	    tp->string = xstrdup (string_buffer_result (&literal));
1637*946379e7Schristos 	    free_string_buffer (&literal);
1638*946379e7Schristos 	    tp->comment = add_reference (savable_comment);
1639*946379e7Schristos 	    tp->type = token_type_string_literal;
1640*946379e7Schristos 	    return;
1641*946379e7Schristos 	  }
1642*946379e7Schristos 
1643*946379e7Schristos 	case '\'':
1644*946379e7Schristos 	  /* Character literal.  */
1645*946379e7Schristos 	  {
1646*946379e7Schristos 	    struct string_buffer literal;
1647*946379e7Schristos 
1648*946379e7Schristos 	    init_string_buffer (&literal);
1649*946379e7Schristos 	    accumulate_escaped (&literal, '\'');
1650*946379e7Schristos 	    free_string_buffer (&literal);
1651*946379e7Schristos 	    tp->type = token_type_other;
1652*946379e7Schristos 	    return;
1653*946379e7Schristos 	  }
1654*946379e7Schristos 
1655*946379e7Schristos 	case '+':
1656*946379e7Schristos 	  c = phase4_getc ();
1657*946379e7Schristos 	  if (c == '+')
1658*946379e7Schristos 	    /* Operator ++ */
1659*946379e7Schristos 	    tp->type = token_type_other;
1660*946379e7Schristos 	  else if (c == '=')
1661*946379e7Schristos 	    /* Operator += */
1662*946379e7Schristos 	    tp->type = token_type_other;
1663*946379e7Schristos 	  else
1664*946379e7Schristos 	    {
1665*946379e7Schristos 	      /* Operator + */
1666*946379e7Schristos 	      phase4_ungetc (c);
1667*946379e7Schristos 	      tp->type = token_type_plus;
1668*946379e7Schristos 	    }
1669*946379e7Schristos 	  return;
1670*946379e7Schristos 
1671*946379e7Schristos 	case '@':
1672*946379e7Schristos 	  c = phase4_getc ();
1673*946379e7Schristos 	  if (c == '"')
1674*946379e7Schristos 	    {
1675*946379e7Schristos 	      /* Verbatim string literal.  */
1676*946379e7Schristos 	      struct string_buffer literal;
1677*946379e7Schristos 
1678*946379e7Schristos 	      init_string_buffer (&literal);
1679*946379e7Schristos 	      for (;;)
1680*946379e7Schristos 		{
1681*946379e7Schristos 		  /* Use phase 2, because phase 4 elides comments and phase 3
1682*946379e7Schristos 		     mixes up the newline characters.  */
1683*946379e7Schristos 		  c = phase2_getc ();
1684*946379e7Schristos 		  if (c == UEOF)
1685*946379e7Schristos 		    break;
1686*946379e7Schristos 		  if (c == '"')
1687*946379e7Schristos 		    {
1688*946379e7Schristos 		      c = phase2_getc ();
1689*946379e7Schristos 		      if (c != '"')
1690*946379e7Schristos 			{
1691*946379e7Schristos 			  phase2_ungetc (c);
1692*946379e7Schristos 			  break;
1693*946379e7Schristos 			}
1694*946379e7Schristos 		    }
1695*946379e7Schristos 		  /* No special treatment of newline and backslash here.  */
1696*946379e7Schristos 		  string_buffer_append_unicode (&literal, c);
1697*946379e7Schristos 		}
1698*946379e7Schristos 	      tp->string = xstrdup (string_buffer_result (&literal));
1699*946379e7Schristos 	      free_string_buffer (&literal);
1700*946379e7Schristos 	      tp->comment = add_reference (savable_comment);
1701*946379e7Schristos 	      tp->type = token_type_string_literal;
1702*946379e7Schristos 	      return;
1703*946379e7Schristos 	    }
1704*946379e7Schristos 	  /* FALLTHROUGH, so that @identifier is recognized.  */
1705*946379e7Schristos 
1706*946379e7Schristos 	default:
1707*946379e7Schristos 	  if (c == '\\')
1708*946379e7Schristos 	    c = do_getc_unicode_escaped (is_identifier_start);
1709*946379e7Schristos 	  if (is_identifier_start (c))
1710*946379e7Schristos 	    {
1711*946379e7Schristos 	      static struct string_buffer buffer;
1712*946379e7Schristos 	      buffer.utf8_buflen = 0;
1713*946379e7Schristos 	      for (;;)
1714*946379e7Schristos 		{
1715*946379e7Schristos 		  string_buffer_append_unicode (&buffer, c);
1716*946379e7Schristos 		  c = phase4_getc ();
1717*946379e7Schristos 		  if (c == '\\')
1718*946379e7Schristos 		    c = do_getc_unicode_escaped (is_identifier_part);
1719*946379e7Schristos 		  if (!is_identifier_part (c))
1720*946379e7Schristos 		    break;
1721*946379e7Schristos 		}
1722*946379e7Schristos 	      phase4_ungetc (c);
1723*946379e7Schristos 	      tp->string = xstrdup (string_buffer_result (&buffer));
1724*946379e7Schristos 	      tp->type = token_type_symbol;
1725*946379e7Schristos 	      return;
1726*946379e7Schristos 	    }
1727*946379e7Schristos 	  else
1728*946379e7Schristos 	    {
1729*946379e7Schristos 	      /* Misc. operator.  */
1730*946379e7Schristos 	      tp->type = token_type_other;
1731*946379e7Schristos 	      return;
1732*946379e7Schristos 	    }
1733*946379e7Schristos 	}
1734*946379e7Schristos     }
1735*946379e7Schristos }
1736*946379e7Schristos 
1737*946379e7Schristos /* Supports 3 tokens of pushback.  */
1738*946379e7Schristos static void
phase6_unget(token_ty * tp)1739*946379e7Schristos phase6_unget (token_ty *tp)
1740*946379e7Schristos {
1741*946379e7Schristos   if (tp->type != token_type_eof)
1742*946379e7Schristos     {
1743*946379e7Schristos       if (phase6_pushback_length == SIZEOF (phase6_pushback))
1744*946379e7Schristos 	abort ();
1745*946379e7Schristos       phase6_pushback[phase6_pushback_length++] = *tp;
1746*946379e7Schristos     }
1747*946379e7Schristos }
1748*946379e7Schristos 
1749*946379e7Schristos 
1750*946379e7Schristos /* Compile-time optimization of string literal concatenation.
1751*946379e7Schristos    Combine "string1" + ... + "stringN" to the concatenated string if
1752*946379e7Schristos      - the token after this expression is not '.' (because then the last
1753*946379e7Schristos        string could be part of a method call expression).  */
1754*946379e7Schristos 
1755*946379e7Schristos static token_ty phase7_pushback[2];
1756*946379e7Schristos static int phase7_pushback_length;
1757*946379e7Schristos 
1758*946379e7Schristos static void
phase7_get(token_ty * tp)1759*946379e7Schristos phase7_get (token_ty *tp)
1760*946379e7Schristos {
1761*946379e7Schristos   if (phase7_pushback_length)
1762*946379e7Schristos     {
1763*946379e7Schristos       *tp = phase7_pushback[--phase7_pushback_length];
1764*946379e7Schristos       return;
1765*946379e7Schristos     }
1766*946379e7Schristos 
1767*946379e7Schristos   phase6_get (tp);
1768*946379e7Schristos   if (tp->type == token_type_string_literal)
1769*946379e7Schristos     {
1770*946379e7Schristos       char *sum = tp->string;
1771*946379e7Schristos       size_t sum_len = strlen (sum);
1772*946379e7Schristos 
1773*946379e7Schristos       for (;;)
1774*946379e7Schristos 	{
1775*946379e7Schristos 	  token_ty token2;
1776*946379e7Schristos 
1777*946379e7Schristos 	  phase6_get (&token2);
1778*946379e7Schristos 	  if (token2.type == token_type_plus)
1779*946379e7Schristos 	    {
1780*946379e7Schristos 	      token_ty token3;
1781*946379e7Schristos 
1782*946379e7Schristos 	      phase6_get (&token3);
1783*946379e7Schristos 	      if (token3.type == token_type_string_literal)
1784*946379e7Schristos 		{
1785*946379e7Schristos 		  token_ty token_after;
1786*946379e7Schristos 
1787*946379e7Schristos 		  phase6_get (&token_after);
1788*946379e7Schristos 		  if (token_after.type != token_type_dot)
1789*946379e7Schristos 		    {
1790*946379e7Schristos 		      char *addend = token3.string;
1791*946379e7Schristos 		      size_t addend_len = strlen (addend);
1792*946379e7Schristos 
1793*946379e7Schristos 		      sum = (char *) xrealloc (sum, sum_len + addend_len + 1);
1794*946379e7Schristos 		      memcpy (sum + sum_len, addend, addend_len + 1);
1795*946379e7Schristos 		      sum_len += addend_len;
1796*946379e7Schristos 
1797*946379e7Schristos 		      phase6_unget (&token_after);
1798*946379e7Schristos 		      free_token (&token3);
1799*946379e7Schristos 		      free_token (&token2);
1800*946379e7Schristos 		      continue;
1801*946379e7Schristos 		    }
1802*946379e7Schristos 		  phase6_unget (&token_after);
1803*946379e7Schristos 		}
1804*946379e7Schristos 	      phase6_unget (&token3);
1805*946379e7Schristos 	    }
1806*946379e7Schristos 	  phase6_unget (&token2);
1807*946379e7Schristos 	  break;
1808*946379e7Schristos 	}
1809*946379e7Schristos       tp->string = sum;
1810*946379e7Schristos     }
1811*946379e7Schristos }
1812*946379e7Schristos 
1813*946379e7Schristos /* Supports 2 tokens of pushback.  */
1814*946379e7Schristos static void
phase7_unget(token_ty * tp)1815*946379e7Schristos phase7_unget (token_ty *tp)
1816*946379e7Schristos {
1817*946379e7Schristos   if (tp->type != token_type_eof)
1818*946379e7Schristos     {
1819*946379e7Schristos       if (phase7_pushback_length == SIZEOF (phase7_pushback))
1820*946379e7Schristos 	abort ();
1821*946379e7Schristos       phase7_pushback[phase7_pushback_length++] = *tp;
1822*946379e7Schristos     }
1823*946379e7Schristos }
1824*946379e7Schristos 
1825*946379e7Schristos 
1826*946379e7Schristos static void
x_csharp_lex(token_ty * tp)1827*946379e7Schristos x_csharp_lex (token_ty *tp)
1828*946379e7Schristos {
1829*946379e7Schristos   phase7_get (tp);
1830*946379e7Schristos }
1831*946379e7Schristos 
1832*946379e7Schristos /* Supports 2 tokens of pushback.  */
1833*946379e7Schristos static void
x_csharp_unlex(token_ty * tp)1834*946379e7Schristos x_csharp_unlex (token_ty *tp)
1835*946379e7Schristos {
1836*946379e7Schristos   phase7_unget (tp);
1837*946379e7Schristos }
1838*946379e7Schristos 
1839*946379e7Schristos 
1840*946379e7Schristos /* ========================= Extracting strings.  ========================== */
1841*946379e7Schristos 
1842*946379e7Schristos 
1843*946379e7Schristos /* Context lookup table.  */
1844*946379e7Schristos static flag_context_list_table_ty *flag_context_list_table;
1845*946379e7Schristos 
1846*946379e7Schristos 
1847*946379e7Schristos /* The file is broken into tokens.  Scan the token stream, looking for
1848*946379e7Schristos    a keyword, followed by a left paren, followed by a string.  When we
1849*946379e7Schristos    see this sequence, we have something to remember.  We assume we are
1850*946379e7Schristos    looking at a valid C or C++ program, and leave the complaints about
1851*946379e7Schristos    the grammar to the compiler.
1852*946379e7Schristos 
1853*946379e7Schristos      Normal handling: Look for
1854*946379e7Schristos        keyword ( ... msgid ... )
1855*946379e7Schristos      Plural handling: Look for
1856*946379e7Schristos        keyword ( ... msgid ... msgid_plural ... )
1857*946379e7Schristos 
1858*946379e7Schristos    We use recursion because the arguments before msgid or between msgid
1859*946379e7Schristos    and msgid_plural can contain subexpressions of the same form.  */
1860*946379e7Schristos 
1861*946379e7Schristos 
1862*946379e7Schristos /* Extract messages until the next balanced closing parenthesis or brace,
1863*946379e7Schristos    depending on TERMINATOR.
1864*946379e7Schristos    Extracted messages are added to MLP.
1865*946379e7Schristos    Return true upon eof, false upon closing parenthesis or brace.  */
1866*946379e7Schristos static bool
extract_parenthesized(message_list_ty * mlp,token_type_ty terminator,flag_context_ty outer_context,flag_context_list_iterator_ty context_iter,struct arglist_parser * argparser)1867*946379e7Schristos extract_parenthesized (message_list_ty *mlp, token_type_ty terminator,
1868*946379e7Schristos 		       flag_context_ty outer_context,
1869*946379e7Schristos 		       flag_context_list_iterator_ty context_iter,
1870*946379e7Schristos 		       struct arglist_parser *argparser)
1871*946379e7Schristos {
1872*946379e7Schristos   /* Current argument number.  */
1873*946379e7Schristos   int arg = 1;
1874*946379e7Schristos   /* 0 when no keyword has been seen.  1 right after a keyword is seen.  */
1875*946379e7Schristos   int state;
1876*946379e7Schristos   /* Parameters of the keyword just seen.  Defined only in state 1.  */
1877*946379e7Schristos   const struct callshapes *next_shapes = NULL;
1878*946379e7Schristos   /* Context iterator that will be used if the next token is a '('.  */
1879*946379e7Schristos   flag_context_list_iterator_ty next_context_iter =
1880*946379e7Schristos     passthrough_context_list_iterator;
1881*946379e7Schristos   /* Current context.  */
1882*946379e7Schristos   flag_context_ty inner_context =
1883*946379e7Schristos     inherited_context (outer_context,
1884*946379e7Schristos 		       flag_context_list_iterator_advance (&context_iter));
1885*946379e7Schristos 
1886*946379e7Schristos   /* Start state is 0.  */
1887*946379e7Schristos   state = 0;
1888*946379e7Schristos 
1889*946379e7Schristos   for (;;)
1890*946379e7Schristos     {
1891*946379e7Schristos       token_ty token;
1892*946379e7Schristos 
1893*946379e7Schristos       x_csharp_lex (&token);
1894*946379e7Schristos       switch (token.type)
1895*946379e7Schristos 	{
1896*946379e7Schristos 	case token_type_symbol:
1897*946379e7Schristos 	  {
1898*946379e7Schristos 	    /* Combine symbol1 . ... . symbolN to a single strings, so that
1899*946379e7Schristos 	       we can recognize static function calls like
1900*946379e7Schristos 	       GettextResource.gettext.  The information present for
1901*946379e7Schristos 	       symbolI.....symbolN has precedence over the information for
1902*946379e7Schristos 	       symbolJ.....symbolN with J > I.  */
1903*946379e7Schristos 	    char *sum = token.string;
1904*946379e7Schristos 	    size_t sum_len = strlen (sum);
1905*946379e7Schristos 	    const char *dottedname;
1906*946379e7Schristos 	    flag_context_list_ty *context_list;
1907*946379e7Schristos 
1908*946379e7Schristos 	    for (;;)
1909*946379e7Schristos 	      {
1910*946379e7Schristos 		token_ty token2;
1911*946379e7Schristos 
1912*946379e7Schristos 		x_csharp_lex (&token2);
1913*946379e7Schristos 		if (token2.type == token_type_dot)
1914*946379e7Schristos 		  {
1915*946379e7Schristos 		    token_ty token3;
1916*946379e7Schristos 
1917*946379e7Schristos 		    x_csharp_lex (&token3);
1918*946379e7Schristos 		    if (token3.type == token_type_symbol)
1919*946379e7Schristos 		      {
1920*946379e7Schristos 			char *addend = token3.string;
1921*946379e7Schristos 			size_t addend_len = strlen (addend);
1922*946379e7Schristos 
1923*946379e7Schristos 			sum =
1924*946379e7Schristos 			  (char *) xrealloc (sum, sum_len + 1 + addend_len + 1);
1925*946379e7Schristos 			sum[sum_len] = '.';
1926*946379e7Schristos 			memcpy (sum + sum_len + 1, addend, addend_len + 1);
1927*946379e7Schristos 			sum_len += 1 + addend_len;
1928*946379e7Schristos 
1929*946379e7Schristos 			free_token (&token3);
1930*946379e7Schristos 			free_token (&token2);
1931*946379e7Schristos 			continue;
1932*946379e7Schristos 		      }
1933*946379e7Schristos 		    x_csharp_unlex (&token3);
1934*946379e7Schristos 		  }
1935*946379e7Schristos 		x_csharp_unlex (&token2);
1936*946379e7Schristos 		break;
1937*946379e7Schristos 	      }
1938*946379e7Schristos 
1939*946379e7Schristos 	    for (dottedname = sum;;)
1940*946379e7Schristos 	      {
1941*946379e7Schristos 		void *keyword_value;
1942*946379e7Schristos 
1943*946379e7Schristos 		if (hash_find_entry (&keywords, dottedname, strlen (dottedname),
1944*946379e7Schristos 				     &keyword_value)
1945*946379e7Schristos 		    == 0)
1946*946379e7Schristos 		  {
1947*946379e7Schristos 		    next_shapes = (const struct callshapes *) keyword_value;
1948*946379e7Schristos 		    state = 1;
1949*946379e7Schristos 		    break;
1950*946379e7Schristos 		  }
1951*946379e7Schristos 
1952*946379e7Schristos 		dottedname = strchr (dottedname, '.');
1953*946379e7Schristos 		if (dottedname == NULL)
1954*946379e7Schristos 		  {
1955*946379e7Schristos 		    state = 0;
1956*946379e7Schristos 		    break;
1957*946379e7Schristos 		  }
1958*946379e7Schristos 		dottedname++;
1959*946379e7Schristos 	      }
1960*946379e7Schristos 
1961*946379e7Schristos 	    for (dottedname = sum;;)
1962*946379e7Schristos 	      {
1963*946379e7Schristos 		context_list =
1964*946379e7Schristos 		  flag_context_list_table_lookup (
1965*946379e7Schristos 		    flag_context_list_table,
1966*946379e7Schristos 		    dottedname, strlen (dottedname));
1967*946379e7Schristos 		if (context_list != NULL)
1968*946379e7Schristos 		  break;
1969*946379e7Schristos 
1970*946379e7Schristos 		dottedname = strchr (dottedname, '.');
1971*946379e7Schristos 		if (dottedname == NULL)
1972*946379e7Schristos 		  break;
1973*946379e7Schristos 		dottedname++;
1974*946379e7Schristos 	      }
1975*946379e7Schristos 	    next_context_iter = flag_context_list_iterator (context_list);
1976*946379e7Schristos 
1977*946379e7Schristos 	    free (sum);
1978*946379e7Schristos 	    continue;
1979*946379e7Schristos 	  }
1980*946379e7Schristos 
1981*946379e7Schristos 	case token_type_lparen:
1982*946379e7Schristos 	  if (extract_parenthesized (mlp, token_type_rparen,
1983*946379e7Schristos 				     inner_context, next_context_iter,
1984*946379e7Schristos 				     arglist_parser_alloc (mlp,
1985*946379e7Schristos 							   state ? next_shapes : NULL)))
1986*946379e7Schristos 	    {
1987*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
1988*946379e7Schristos 	      arglist_parser_done (argparser, arg);
1989*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
1990*946379e7Schristos 	      return true;
1991*946379e7Schristos 	    }
1992*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
1993*946379e7Schristos 	  state = 0;
1994*946379e7Schristos 	  continue;
1995*946379e7Schristos 
1996*946379e7Schristos 	case token_type_rparen:
1997*946379e7Schristos 	  if (terminator == token_type_rparen)
1998*946379e7Schristos 	    {
1999*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
2000*946379e7Schristos 	      arglist_parser_done (argparser, arg);
2001*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
2002*946379e7Schristos 	      return false;
2003*946379e7Schristos 	    }
2004*946379e7Schristos 	  if (terminator == token_type_rbrace)
2005*946379e7Schristos 	    {
2006*946379e7Schristos 	      error_with_progname = false;
2007*946379e7Schristos 	      error (0, 0,
2008*946379e7Schristos 		     _("%s:%d: warning: ')' found where '}' was expected"),
2009*946379e7Schristos 		     logical_file_name, token.line_number);
2010*946379e7Schristos 	      error_with_progname = true;
2011*946379e7Schristos 	    }
2012*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
2013*946379e7Schristos 	  state = 0;
2014*946379e7Schristos 	  continue;
2015*946379e7Schristos 
2016*946379e7Schristos 	case token_type_lbrace:
2017*946379e7Schristos 	  if (extract_parenthesized (mlp, token_type_rbrace,
2018*946379e7Schristos 				     null_context, null_context_list_iterator,
2019*946379e7Schristos 				     arglist_parser_alloc (mlp, NULL)))
2020*946379e7Schristos 	    {
2021*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
2022*946379e7Schristos 	      arglist_parser_done (argparser, arg);
2023*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
2024*946379e7Schristos 	      return true;
2025*946379e7Schristos 	    }
2026*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
2027*946379e7Schristos 	  state = 0;
2028*946379e7Schristos 	  continue;
2029*946379e7Schristos 
2030*946379e7Schristos 	case token_type_rbrace:
2031*946379e7Schristos 	  if (terminator == token_type_rbrace)
2032*946379e7Schristos 	    {
2033*946379e7Schristos 	      xgettext_current_source_encoding = po_charset_utf8;
2034*946379e7Schristos 	      arglist_parser_done (argparser, arg);
2035*946379e7Schristos 	      xgettext_current_source_encoding = xgettext_global_source_encoding;
2036*946379e7Schristos 	      return false;
2037*946379e7Schristos 	    }
2038*946379e7Schristos 	  if (terminator == token_type_rparen)
2039*946379e7Schristos 	    {
2040*946379e7Schristos 	      error_with_progname = false;
2041*946379e7Schristos 	      error (0, 0,
2042*946379e7Schristos 		     _("%s:%d: warning: '}' found where ')' was expected"),
2043*946379e7Schristos 		     logical_file_name, token.line_number);
2044*946379e7Schristos 	      error_with_progname = true;
2045*946379e7Schristos 	    }
2046*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
2047*946379e7Schristos 	  state = 0;
2048*946379e7Schristos 	  continue;
2049*946379e7Schristos 
2050*946379e7Schristos 	case token_type_comma:
2051*946379e7Schristos 	  arg++;
2052*946379e7Schristos 	  inner_context =
2053*946379e7Schristos 	    inherited_context (outer_context,
2054*946379e7Schristos 			       flag_context_list_iterator_advance (
2055*946379e7Schristos 				 &context_iter));
2056*946379e7Schristos 	  next_context_iter = passthrough_context_list_iterator;
2057*946379e7Schristos 	  state = 0;
2058*946379e7Schristos 	  continue;
2059*946379e7Schristos 
2060*946379e7Schristos 	case token_type_string_literal:
2061*946379e7Schristos 	  {
2062*946379e7Schristos 	    lex_pos_ty pos;
2063*946379e7Schristos 	    pos.file_name = logical_file_name;
2064*946379e7Schristos 	    pos.line_number = token.line_number;
2065*946379e7Schristos 
2066*946379e7Schristos 	    xgettext_current_source_encoding = po_charset_utf8;
2067*946379e7Schristos 	    if (extract_all)
2068*946379e7Schristos 	      remember_a_message (mlp, NULL, token.string, inner_context,
2069*946379e7Schristos 				  &pos, token.comment);
2070*946379e7Schristos 	    else
2071*946379e7Schristos 	      arglist_parser_remember (argparser, arg, token.string,
2072*946379e7Schristos 				       inner_context,
2073*946379e7Schristos 				       pos.file_name, pos.line_number,
2074*946379e7Schristos 				       token.comment);
2075*946379e7Schristos 	    xgettext_current_source_encoding = xgettext_global_source_encoding;
2076*946379e7Schristos 	  }
2077*946379e7Schristos 	  drop_reference (token.comment);
2078*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
2079*946379e7Schristos 	  state = 0;
2080*946379e7Schristos 	  continue;
2081*946379e7Schristos 
2082*946379e7Schristos 	case token_type_eof:
2083*946379e7Schristos 	  xgettext_current_source_encoding = po_charset_utf8;
2084*946379e7Schristos 	  arglist_parser_done (argparser, arg);
2085*946379e7Schristos 	  xgettext_current_source_encoding = xgettext_global_source_encoding;
2086*946379e7Schristos 	  return true;
2087*946379e7Schristos 
2088*946379e7Schristos 	case token_type_dot:
2089*946379e7Schristos 	case token_type_number:
2090*946379e7Schristos 	case token_type_plus:
2091*946379e7Schristos 	case token_type_other:
2092*946379e7Schristos 	  next_context_iter = null_context_list_iterator;
2093*946379e7Schristos 	  state = 0;
2094*946379e7Schristos 	  continue;
2095*946379e7Schristos 
2096*946379e7Schristos 	default:
2097*946379e7Schristos 	  abort ();
2098*946379e7Schristos 	}
2099*946379e7Schristos     }
2100*946379e7Schristos }
2101*946379e7Schristos 
2102*946379e7Schristos 
2103*946379e7Schristos void
extract_csharp(FILE * f,const char * real_filename,const char * logical_filename,flag_context_list_table_ty * flag_table,msgdomain_list_ty * mdlp)2104*946379e7Schristos extract_csharp (FILE *f,
2105*946379e7Schristos 		const char *real_filename, const char *logical_filename,
2106*946379e7Schristos 		flag_context_list_table_ty *flag_table,
2107*946379e7Schristos 		msgdomain_list_ty *mdlp)
2108*946379e7Schristos {
2109*946379e7Schristos   message_list_ty *mlp = mdlp->item[0]->messages;
2110*946379e7Schristos 
2111*946379e7Schristos   fp = f;
2112*946379e7Schristos   real_file_name = real_filename;
2113*946379e7Schristos   logical_file_name = xstrdup (logical_filename);
2114*946379e7Schristos   line_number = 1;
2115*946379e7Schristos 
2116*946379e7Schristos   logical_line_number = 1;
2117*946379e7Schristos   last_comment_line = -1;
2118*946379e7Schristos   last_non_comment_line = -1;
2119*946379e7Schristos 
2120*946379e7Schristos   flag_context_list_table = flag_table;
2121*946379e7Schristos 
2122*946379e7Schristos   init_keywords ();
2123*946379e7Schristos 
2124*946379e7Schristos   /* Eat tokens until eof is seen.  When extract_parenthesized returns
2125*946379e7Schristos      due to an unbalanced closing parenthesis, just restart it.  */
2126*946379e7Schristos   while (!extract_parenthesized (mlp, token_type_eof,
2127*946379e7Schristos 				 null_context, null_context_list_iterator,
2128*946379e7Schristos 				 arglist_parser_alloc (mlp, NULL)))
2129*946379e7Schristos     ;
2130*946379e7Schristos 
2131*946379e7Schristos   fp = NULL;
2132*946379e7Schristos   real_file_name = NULL;
2133*946379e7Schristos   logical_file_name = NULL;
2134*946379e7Schristos   line_number = 0;
2135*946379e7Schristos }
2136