Some variables are ordinal.
[pspp] / src / language / lexer / segment.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2010, 2011, 2013, 2016 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "language/lexer/segment.h"
20
21 #include <limits.h>
22 #include <unistr.h>
23
24 #include "data/identifier.h"
25 #include "language/lexer/command-name.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/cast.h"
28
29 #include "gl/c-ctype.h"
30 #include "gl/c-strcase.h"
31
32 enum segmenter_state
33   {
34     S_SHBANG,
35     S_GENERAL,
36     S_COMMENT_1,
37     S_COMMENT_2,
38     S_DOCUMENT_1,
39     S_DOCUMENT_2,
40     S_DOCUMENT_3,
41     S_FILE_LABEL_1,
42     S_FILE_LABEL_2,
43     S_FILE_LABEL_3,
44     S_DO_REPEAT_1,
45     S_DO_REPEAT_2,
46     S_DO_REPEAT_3,
47     S_DEFINE_1,
48     S_DEFINE_2,
49     S_DEFINE_3,
50     S_DEFINE_4,
51     S_DEFINE_5,
52     S_BEGIN_DATA_1,
53     S_BEGIN_DATA_2,
54     S_BEGIN_DATA_3,
55     S_BEGIN_DATA_4,
56   };
57
58 #define SS_START_OF_LINE (1u << 0)
59 #define SS_START_OF_COMMAND (1u << 1)
60
61 static int segmenter_detect_command_name__ (const char *input,
62                                             size_t n, bool eof, int ofs);
63
64 static int
65 segmenter_u8_to_uc__ (ucs4_t *puc, const char *input_, size_t n, bool eof,
66                       size_t ofs)
67 {
68   const uint8_t *input = CHAR_CAST (const uint8_t *, input_);
69   int mblen;
70
71   assert (n > ofs);
72
73   input += ofs;
74   n -= ofs;
75
76   mblen = u8_mbtoucr (puc, input, n);
77   if (mblen >= 0)
78     return mblen;
79   else if (mblen != -2)
80     return u8_mbtouc (puc, input, n);
81   else if (eof)
82     {
83       *puc = 0xfffd;
84       return n;
85     }
86   else
87     return -1;
88 }
89
90 static int
91 segmenter_parse_shbang__ (struct segmenter *s, const char *input, size_t n,
92                           bool eof, enum segment_type *type)
93 {
94   if (input[0] == '#')
95     {
96       if (n >= 2)
97         {
98           if (input[1] == '!')
99             {
100               for (int ofs = 2; ; ofs++)
101                 {
102                   if (ofs >= n)
103                     {
104                       if (!eof)
105                         return -1;
106                     }
107                   else if (input[ofs] == '\n')
108                     {
109                       if (input[ofs - 1] == '\r')
110                         ofs--;
111                     }
112                   else
113                     continue;
114
115                   s->state = S_GENERAL;
116                   s->substate = SS_START_OF_COMMAND;
117                   *type = SEG_SHBANG;
118                   return ofs;
119                 }
120             }
121         }
122       else if (!eof)
123         return -1;
124     }
125
126   s->state = S_GENERAL;
127   s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
128   return segmenter_push (s, input, n, eof, type);
129 }
130
131 static int
132 segmenter_parse_digraph__ (const char *seconds, struct segmenter *s,
133                            const char *input, size_t n, bool eof,
134                            enum segment_type *type)
135 {
136   assert (s->state == S_GENERAL);
137
138   *type = SEG_PUNCT;
139   s->substate = 0;
140   return (n < 2
141           ? (eof ? 1 : -1)
142           : (strchr (seconds, input[1]) != NULL ? 2 : 1));
143 }
144
145 static int
146 skip_comment (const char *input, size_t n, bool eof, size_t ofs)
147 {
148   for (; ofs < n; ofs++)
149     {
150       if (input[ofs] == '\n')
151         return ofs;
152       else if (input[ofs] == '*')
153         {
154           if (ofs + 1 >= n)
155             return eof ? ofs + 1 : -1;
156           else if (input[ofs + 1] == '/')
157             return ofs + 2;
158         }
159     }
160   return eof ? ofs : -1;
161 }
162
163 static int
164 skip_spaces_and_comments (const char *input, size_t n, bool eof, int ofs)
165 {
166   while (ofs < n)
167     {
168       ucs4_t uc;
169       int mblen;
170
171       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
172       if (mblen < 0)
173         return -1;
174
175       if (uc == '/')
176         {
177           if (ofs + 1 >= n)
178             return eof ? ofs : -1;
179           else if (input[ofs + 1] != '*')
180             return ofs;
181
182           ofs = skip_comment (input, n, eof, ofs + 2);
183           if (ofs < 0)
184             return -1;
185         }
186       else if (lex_uc_is_space (uc) && uc != '\n')
187         ofs += mblen;
188       else
189         return ofs;
190     }
191
192   return eof ? ofs : -1;
193 }
194
195 static int
196 is_end_of_line (const char *input, size_t n, bool eof, int ofs)
197 {
198   if (ofs >= n)
199     return eof ? 1 : -1;
200   else if (input[ofs] == '\n')
201     return 1;
202   else if (input[ofs] == '\r')
203     {
204       if (ofs + 1 >= n)
205         return eof ? 1 : -1;
206       return input[ofs + 1] == '\n';
207     }
208   else
209     return 0;
210 }
211
212 static int
213 at_end_of_line (const char *input, size_t n, bool eof, int ofs)
214 {
215   ofs = skip_spaces_and_comments (input, n, eof, ofs);
216   if (ofs < 0)
217     return -1;
218
219   return is_end_of_line (input, n, eof, ofs);
220 }
221
222 static bool
223 is_all_spaces (const char *input_, size_t n)
224 {
225   const uint8_t *input = CHAR_CAST (const uint8_t *, input_);
226
227   int mblen;
228   for (int ofs = 0; ofs < n; ofs += mblen)
229     {
230       ucs4_t uc;
231       mblen = u8_mbtouc (&uc, input + ofs, n - ofs);
232       if (!lex_uc_is_space (uc))
233         return false;
234     }
235   return true;
236 }
237
238 static int
239 segmenter_parse_newline__ (const char *input, size_t n, bool eof,
240                            enum segment_type *type)
241 {
242   int ofs;
243
244   if (input[0] == '\n')
245     ofs = 1;
246   else
247     {
248       if (n < 2)
249         {
250           assert (!eof);
251           return -1;
252         }
253
254       assert (input[0] == '\r');
255       assert (input[1] == '\n');
256       ofs = 2;
257     }
258
259   *type = SEG_NEWLINE;
260   return ofs;
261 }
262
263 static int
264 skip_spaces (const char *input, size_t n, bool eof, size_t ofs)
265 {
266   while (ofs < n)
267     {
268       ucs4_t uc;
269       int mblen;
270
271       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
272       if (mblen < 0)
273         return -1;
274
275       if (!lex_uc_is_space (uc) || uc == '\n')
276         return ofs;
277
278       ofs += mblen;
279     }
280
281   return eof ? ofs : -1;
282 }
283
284 static int
285 skip_digits (const char *input, size_t n, bool eof, int ofs)
286 {
287   for (; ofs < n; ofs++)
288     if (!c_isdigit (input[ofs]))
289       return ofs;
290   return eof ? ofs : -1;
291 }
292
293 static int
294 segmenter_parse_number__ (struct segmenter *s, const char *input, size_t n,
295                           bool eof, enum segment_type *type, int ofs)
296 {
297   assert (s->state == S_GENERAL);
298
299   ofs = skip_digits (input, n, eof, ofs);
300   if (ofs < 0)
301     return -1;
302
303   if (ofs >= n)
304     {
305       if (!eof)
306         return -1;
307       goto number;
308     }
309   if (input[ofs] == '.')
310     {
311       if (ofs + 1 >= n)
312         {
313           if (!eof)
314             return -1;
315           goto number;
316         }
317
318       ofs = skip_digits (input, n, eof, ofs + 1);
319       if (ofs < 0)
320         return -1;
321       else if (ofs >= n)
322         goto number;
323     }
324
325   if (input[ofs] == 'e' || input[ofs] == 'E')
326     {
327       ofs++;
328       if (ofs >= n)
329         {
330           if (!eof)
331             return -1;
332           goto expected_exponent;
333         }
334
335       if (input[ofs] == '+' || input[ofs] == '-')
336         {
337           ofs++;
338           if (ofs >= n)
339             {
340               if (!eof)
341                 return -1;
342               goto expected_exponent;
343             }
344         }
345
346       if (!c_isdigit (input[ofs]))
347         goto expected_exponent;
348
349       ofs = skip_digits (input, n, eof, ofs);
350       if (ofs < 0)
351         return -1;
352     }
353
354   if (input[ofs - 1] == '.')
355     {
356       int eol = at_end_of_line (input, n, eof, ofs);
357       if (eol < 0)
358         return -1;
359       else if (eol)
360         ofs--;
361     }
362
363 number:
364   *type = SEG_NUMBER;
365   s->substate = 0;
366   return ofs;
367
368 expected_exponent:
369   *type = SEG_EXPECTED_EXPONENT;
370   s->substate = 0;
371   return ofs;
372 }
373
374 static bool
375 is_reserved_word (const char *s, int n)
376 {
377   char s0, s1, s2, s3;
378
379   s0 = c_toupper (s[0]);
380   switch (n)
381     {
382     case 2:
383       s1 = c_toupper (s[1]);
384       return ((s0 == 'B' && s1 == 'Y')
385               || (s0 == 'E' && s1 == 'Q')
386               || (s0 == 'G' && (s1 == 'E' || s1 == 'T'))
387               || (s0 == 'L' && (s1 == 'E' || s1 == 'T'))
388               || (s0 == 'N' && s1 == 'E')
389               || (s0 == 'O' && s1 == 'R')
390               || (s0 == 'T' && s1 == 'O'));
391
392     case 3:
393       s1 = c_toupper (s[1]);
394       s2 = c_toupper (s[2]);
395       return ((s0 == 'A' && ((s1 == 'L' && s2 == 'L')
396                              || (s1 == 'N' && s2 == 'D')))
397               || (s0 == 'N' && s1 == 'O' && s2 == 'T'));
398
399     case 4:
400       s1 = c_toupper (s[1]);
401       s2 = c_toupper (s[2]);
402       s3 = c_toupper (s[3]);
403       return s0 == 'W' && s1 == 'I' && s2 == 'T' && s3 == 'H';
404
405     default:
406       return false;
407     }
408 }
409
410 static int
411 segmenter_parse_comment_1__ (struct segmenter *s,
412                              const char *input, size_t n, bool eof,
413                              enum segment_type *type)
414 {
415   int endcmd;
416   int ofs;
417
418   endcmd = -2;
419   ofs = 0;
420   while (ofs < n)
421     {
422       ucs4_t uc;
423       int mblen;
424
425       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
426       if (mblen < 0)
427         return -1;
428
429       switch (uc)
430         {
431         case '.':
432           endcmd = ofs;
433           break;
434
435         case '\n':
436           if (ofs > 1 && input[ofs - 1] == '\r')
437             ofs--;
438           if (endcmd == -2)
439             {
440               /* Blank line ends comment command. */
441               s->state = S_GENERAL;
442               s->substate = SS_START_OF_COMMAND;
443               *type = SEG_SEPARATE_COMMANDS;
444               return ofs;
445             }
446           else if (endcmd >= 0)
447             {
448               /* '.' at end of line ends comment command. */
449               s->state = S_GENERAL;
450               s->substate = 0;
451               *type = SEG_COMMENT_COMMAND;
452               return endcmd;
453             }
454           else
455             {
456               /* Comment continues onto next line. */
457               *type = SEG_COMMENT_COMMAND;
458               s->state = S_COMMENT_2;
459               return ofs;
460             }
461           NOT_REACHED ();
462
463         default:
464           if (!lex_uc_is_space (uc))
465             endcmd = -1;
466           break;
467         }
468
469       ofs += mblen;
470     }
471
472   if (eof)
473     {
474       /* End of file. */
475       s->state = S_GENERAL;
476       s->substate = SS_START_OF_COMMAND;
477       *type = SEG_SEPARATE_COMMANDS;
478       return ofs;
479     }
480
481   return -1;
482 }
483
484 static int
485 segmenter_parse_comment_2__ (struct segmenter *s, const char *input,
486                              size_t n, bool eof, enum segment_type *type)
487 {
488   int ofs = segmenter_parse_newline__ (input, n, eof, type);
489   if (ofs < 0)
490     return -1;
491
492   int new_cmd;
493   if (ofs >= n)
494     {
495       if (!eof)
496         return -1;
497       new_cmd = false;
498     }
499   else
500     {
501       ucs4_t uc;
502       int mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
503       if (mblen < 0)
504         return -1;
505
506       if (uc == '+' || uc == '-' || uc == '.')
507         new_cmd = true;
508       else if (!lex_uc_is_space (uc))
509         switch (s->mode)
510           {
511           case SEG_MODE_INTERACTIVE:
512             new_cmd = false;
513             break;
514
515           case SEG_MODE_BATCH:
516             new_cmd = true;
517             break;
518
519           case SEG_MODE_AUTO:
520             new_cmd = segmenter_detect_command_name__ (input, n, eof, ofs);
521             if (new_cmd < 0)
522               return -1;
523             break;
524
525           default:
526             NOT_REACHED ();
527           }
528       else
529         new_cmd = false;
530     }
531
532   if (new_cmd)
533     {
534       s->state = S_GENERAL;
535       s->substate = SS_START_OF_LINE | SS_START_OF_COMMAND;
536     }
537   else
538     s->state = S_COMMENT_1;
539   return ofs;
540 }
541
542 static int
543 segmenter_parse_document_1__ (struct segmenter *s, const char *input, size_t n,
544                               bool eof, enum segment_type *type)
545 {
546   bool end_cmd;
547   int ofs;
548
549   end_cmd = false;
550   ofs = 0;
551   while (ofs < n)
552     {
553       ucs4_t uc;
554       int mblen;
555
556       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
557       if (mblen < 0)
558         return -1;
559
560       switch (uc)
561         {
562         case '.':
563           end_cmd = true;
564           break;
565
566         case '\n':
567           if (ofs > 1 && input[ofs - 1] == '\r')
568             ofs--;
569
570           *type = SEG_DOCUMENT;
571           s->state = end_cmd ? S_DOCUMENT_3 : S_DOCUMENT_2;
572           return ofs;
573
574         default:
575           if (!lex_uc_is_space (uc))
576             end_cmd = false;
577           break;
578         }
579
580       ofs += mblen;
581     }
582   if (eof)
583     {
584       *type = SEG_DOCUMENT;
585       s->state = S_DOCUMENT_3;
586       return ofs;
587     }
588   return -1;
589 }
590
591 static int
592 segmenter_parse_document_2__ (struct segmenter *s, const char *input, size_t n,
593                               bool eof, enum segment_type *type)
594 {
595   int ofs;
596
597   ofs = segmenter_parse_newline__ (input, n, eof, type);
598   if (ofs < 0)
599     return -1;
600
601   s->state = S_DOCUMENT_1;
602   return ofs;
603 }
604
605 static int
606 segmenter_parse_document_3__ (struct segmenter *s, enum segment_type *type)
607 {
608   *type = SEG_END_COMMAND;
609   s->state = S_GENERAL;
610   s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
611   return 0;
612 }
613
614 static int
615 segmenter_unquoted (const char *input, size_t n, bool eof, int ofs)
616
617 {
618   ofs = skip_spaces_and_comments (input, n, eof, ofs);
619   if (ofs < 0)
620     return -1;
621   else if (ofs < n)
622     {
623       char c = input[ofs];
624       return c != '\'' && c != '"' && c != '\n';
625     }
626   else
627     {
628       assert (eof);
629       return 0;
630     }
631 }
632
633 static int
634 next_id_in_command (const struct segmenter *s, const char *input, size_t n,
635                     bool eof, int ofs, char id[], size_t id_size)
636 {
637   struct segmenter sub;
638
639   assert (id_size > 0);
640
641   sub.mode = s->mode;
642   sub.state = S_GENERAL;
643   sub.substate = 0;
644   for (;;)
645     {
646       enum segment_type type;
647       int retval;
648
649       retval = segmenter_push (&sub, input + ofs, n - ofs, eof, &type);
650       if (retval < 0)
651         {
652           id[0] = '\0';
653           return -1;
654         }
655
656       switch (type)
657         {
658         case SEG_SHBANG:
659         case SEG_SPACES:
660         case SEG_COMMENT:
661         case SEG_NEWLINE:
662           break;
663
664         case SEG_IDENTIFIER:
665           if (retval < id_size)
666             {
667               memcpy (id, input + ofs, retval);
668               id[retval] = '\0';
669               return ofs + retval;
670             }
671           /* fall through */
672
673         case SEG_NUMBER:
674         case SEG_QUOTED_STRING:
675         case SEG_HEX_STRING:
676         case SEG_UNICODE_STRING:
677         case SEG_UNQUOTED_STRING:
678         case SEG_RESERVED_WORD:
679         case SEG_PUNCT:
680         case SEG_COMMENT_COMMAND:
681         case SEG_DO_REPEAT_COMMAND:
682         case SEG_INLINE_DATA:
683         case SEG_MACRO_ID:
684         case SEG_MACRO_NAME:
685         case SEG_MACRO_BODY:
686         case SEG_START_DOCUMENT:
687         case SEG_DOCUMENT:
688         case SEG_START_COMMAND:
689         case SEG_SEPARATE_COMMANDS:
690         case SEG_END_COMMAND:
691         case SEG_END:
692         case SEG_EXPECTED_QUOTE:
693         case SEG_EXPECTED_EXPONENT:
694         case SEG_UNEXPECTED_CHAR:
695           id[0] = '\0';
696           return ofs + retval;
697         }
698       ofs += retval;
699     }
700 }
701
702 /* Called when INPUT begins with a character that can start off an ID token. */
703 static int
704 segmenter_parse_id__ (struct segmenter *s, const char *input, size_t n,
705                       bool eof, enum segment_type *type)
706 {
707   ucs4_t uc;
708   int ofs;
709
710   assert (n > 0);
711   assert (s->state == S_GENERAL);
712
713   ofs = u8_mbtouc (&uc, CHAR_CAST (const uint8_t *, input), n);
714   for (;;)
715     {
716       int mblen;
717
718       if (ofs >= n)
719         {
720           if (eof)
721             break;
722           return -1;
723         }
724
725       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
726       if (mblen < 0)
727         return -1;
728       else if (!lex_uc_is_idn (uc))
729         break;
730
731       ofs += mblen;
732     }
733
734   if (input[ofs - 1] == '.')
735     {
736       int eol = at_end_of_line (input, n, eof, ofs);
737       if (eol < 0)
738         return -1;
739       else if (eol)
740         ofs--;
741     }
742
743   *type = (is_reserved_word (input, ofs) ? SEG_RESERVED_WORD
744            : input[0] == '!' ? SEG_MACRO_ID
745            : SEG_IDENTIFIER);
746
747   if (s->substate & SS_START_OF_COMMAND)
748     {
749       struct substring word = ss_buffer (input, ofs);
750
751       if (lex_id_match_n (ss_cstr ("COMMENT"), word, 4))
752         {
753           s->state = S_COMMENT_1;
754           return segmenter_parse_comment_1__ (s, input, n, eof, type);
755         }
756       else if (lex_id_match (ss_cstr ("DOCUMENT"), word))
757         {
758           s->state = S_DOCUMENT_1;
759           *type = SEG_START_DOCUMENT;
760           return 0;
761         }
762       else if (lex_id_match_n (ss_cstr ("DEFINE"), word, 6))
763         {
764           s->state = S_DEFINE_1;
765           return ofs;
766         }
767       else if (lex_id_match (ss_cstr ("FILE"), word))
768         {
769           char id[16];
770
771           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
772             return -1;
773           else if (lex_id_match (ss_cstr ("LABEL"), ss_cstr (id)))
774             {
775               s->state = S_FILE_LABEL_1;
776               s->substate = 0;
777               return ofs;
778             }
779         }
780       else if (lex_id_match (ss_cstr ("DO"), word))
781         {
782           char id[16];
783
784           if (next_id_in_command (s, input, n, eof, ofs, id, sizeof id) < 0)
785             return -1;
786           else if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
787             {
788               s->state = S_DO_REPEAT_1;
789               s->substate = 0;
790               return ofs;
791             }
792         }
793       else if (lex_id_match (ss_cstr ("BEGIN"), word))
794         {
795           char id[16];
796           int ofs2;
797
798           ofs2 = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
799           if (ofs2 < 0)
800             return -1;
801           else if (lex_id_match (ss_cstr ("DATA"), ss_cstr (id)))
802             {
803               int eol;
804
805               ofs2 = skip_spaces_and_comments (input, n, eof, ofs2);
806               if (ofs2 < 0)
807                 return -1;
808
809               if (ofs2 >= n)
810                 assert (eof);
811               else if (input[ofs2] == '.')
812                 {
813                   ofs2 = skip_spaces_and_comments (input, n, eof, ofs2 + 1);
814                   if (ofs2 < 0)
815                     return -1;
816                 }
817
818               eol = is_end_of_line (input, n, eof, ofs2);
819               if (eol < 0)
820                 return -1;
821               else if (eol)
822                 {
823                   if (memchr (input, '\n', ofs2))
824                     s->state = S_BEGIN_DATA_1;
825                   else
826                     s->state = S_BEGIN_DATA_2;
827                   s->substate = 0;
828                   return ofs;
829                 }
830             }
831         }
832     }
833
834   s->substate = 0;
835   return ofs;
836 }
837
838 static int
839 segmenter_parse_string__ (enum segment_type string_type,
840                           int ofs, struct segmenter *s,
841                           const char *input, size_t n, bool eof,
842                           enum segment_type *type)
843 {
844   int quote = input[ofs];
845
846   ofs++;
847   while (ofs < n)
848     if (input[ofs] == quote)
849       {
850         ofs++;
851         if (ofs < n)
852           {
853             if (input[ofs] == quote)
854               {
855                 ofs++;
856                 continue;
857               }
858           }
859         else if (!eof)
860           return -1;
861
862         *type = string_type;
863         s->substate = 0;
864         return ofs;
865       }
866     else if (input[ofs] == '\n')
867       goto expected_quote;
868     else
869       ofs++;
870
871   if (eof)
872     goto expected_quote;
873
874   return -1;
875
876 expected_quote:
877   *type = SEG_EXPECTED_QUOTE;
878   s->substate = 0;
879   return ofs;
880 }
881
882 static int
883 segmenter_maybe_parse_string__ (enum segment_type string_type,
884                                 struct segmenter *s,
885                                 const char *input, size_t n, bool eof,
886                                 enum segment_type *type)
887 {
888   if (n < 2)
889     {
890       if (!eof)
891         return -1;
892     }
893   else if (input[1] == '\'' || input[1] == '"')
894     return segmenter_parse_string__ (string_type, 1, s, input, n, eof, type);
895
896   return segmenter_parse_id__ (s, input, n, eof, type);
897 }
898
899 static int
900 segmenter_parse_mid_command__ (struct segmenter *s,
901                                const char *input, size_t n, bool eof,
902                                enum segment_type *type)
903 {
904   ucs4_t uc;
905   int mblen;
906   int ofs;
907
908   assert (s->state == S_GENERAL);
909   assert (!(s->substate & SS_START_OF_LINE));
910
911   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
912   if (mblen < 0)
913     return -1;
914
915   switch (uc)
916     {
917     case '\n':
918       s->substate |= SS_START_OF_LINE;
919       *type = SEG_NEWLINE;
920       return 1;
921
922     case '/':
923       if (n < 2)
924         {
925           if (!eof)
926             return -1;
927         }
928       else if (input[1] == '*')
929         {
930           ofs = skip_comment (input, n, eof, 2);
931           if (ofs < 0)
932             return -1;
933
934           *type = SEG_COMMENT;
935           return ofs;
936         }
937
938       s->substate = 0;
939       *type = SEG_PUNCT;
940       return 1;
941
942     case '-':
943       ofs = skip_spaces (input, n, eof, 1);
944       if (ofs < 0)
945         return -1;
946       else if (ofs < n && c_isdigit (input[ofs]))
947         return segmenter_parse_number__ (s, input, n, eof, type, ofs);
948       else if (ofs < n && input[ofs] == '.')
949         {
950           if (ofs + 1 >= n)
951             {
952               if (!eof)
953                 return -1;
954             }
955           else if (c_isdigit (input[ofs + 1]))
956             return segmenter_parse_number__ (s, input, n, eof, type, ofs);
957         }
958       /* Fall through. */
959     case '(': case ')': case '{': case ',': case '=': case ';': case ':':
960     case '[': case ']': case '}': case '&': case '|': case '+':
961       *type = SEG_PUNCT;
962       s->substate = 0;
963       return 1;
964
965     case '*':
966       if (s->substate & SS_START_OF_COMMAND)
967         {
968           /* '*' at the beginning of a command begins a comment. */
969           s->state = S_COMMENT_1;
970           return segmenter_parse_comment_1__ (s, input, n, eof, type);
971         }
972       else
973         return segmenter_parse_digraph__ ("*", s, input, n, eof, type);
974
975     case '<':
976       return segmenter_parse_digraph__ ("=>", s, input, n, eof, type);
977
978     case '>':
979       return segmenter_parse_digraph__ ("=", s, input, n, eof, type);
980
981     case '~':
982       return segmenter_parse_digraph__ ("=", s, input, n, eof, type);
983
984     case '.':
985       if (n < 2)
986         {
987           if (!eof)
988             return -1;
989         }
990       else if (c_isdigit (input[1]))
991         return segmenter_parse_number__ (s, input, n, eof, type, 0);
992
993       int eol = at_end_of_line (input, n, eof, 1);
994       if (eol < 0)
995         return -1;
996
997       if (eol)
998         {
999           *type = SEG_END_COMMAND;
1000           s->substate = SS_START_OF_COMMAND;
1001         }
1002       else
1003         *type = SEG_PUNCT;
1004       return 1;
1005
1006     case '0': case '1': case '2': case '3': case '4':
1007     case '5': case '6': case '7': case '8': case '9':
1008       return segmenter_parse_number__ (s, input, n, eof, type, 0);
1009
1010     case 'u': case 'U':
1011       return segmenter_maybe_parse_string__ (SEG_UNICODE_STRING,
1012                                              s, input, n, eof, type);
1013
1014     case 'x': case 'X':
1015       return segmenter_maybe_parse_string__ (SEG_HEX_STRING,
1016                                              s, input, n, eof, type);
1017
1018     case '\'': case '"':
1019       return segmenter_parse_string__ (SEG_QUOTED_STRING, 0,
1020                                        s, input, n, eof, type);
1021
1022     case '!':
1023       if (n < 2)
1024         {
1025           if (!eof)
1026             return -1;
1027           *type = SEG_PUNCT;
1028           return 1;
1029         }
1030       else if (input[1] == '*')
1031         {
1032           *type = SEG_MACRO_ID;
1033           return 2;
1034         }
1035       else
1036         return segmenter_parse_id__ (s, input, n, eof, type);
1037
1038     default:
1039       if (lex_uc_is_space (uc))
1040         {
1041           ofs = skip_spaces (input, n, eof, mblen);
1042           if (ofs < 0)
1043             return -1;
1044
1045           if (ofs < n && input[ofs - 1] == '\r' && input[ofs] == '\n')
1046             {
1047               if (ofs == 1)
1048                 {
1049                   s->substate |= SS_START_OF_LINE;
1050                   *type = SEG_NEWLINE;
1051                   return 2;
1052                 }
1053               else
1054                 ofs--;
1055             }
1056           *type = SEG_SPACES;
1057           return ofs;
1058         }
1059       else if (lex_uc_is_id1 (uc))
1060         return segmenter_parse_id__ (s, input, n, eof, type);
1061       else if (uc > 32 && uc < 127 && uc != '\\' && uc != '^')
1062         {
1063           *type = SEG_PUNCT;
1064           s->substate = 0;
1065           return 1;
1066         }
1067       else
1068         {
1069           *type = SEG_UNEXPECTED_CHAR;
1070           s->substate = 0;
1071           return mblen;
1072         }
1073     }
1074 }
1075
1076 static int
1077 compare_commands (const void *a_, const void *b_)
1078 {
1079   const char *const *ap = a_;
1080   const char *const *bp = b_;
1081   const char *a = *ap;
1082   const char *b = *bp;
1083
1084   return c_strcasecmp (a, b);
1085 }
1086
1087 static const char **
1088 segmenter_get_command_name_candidates (unsigned char first)
1089 {
1090 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) NAME,
1091 #define UNIMPL_CMD(NAME, DESCRIPTION) NAME,
1092   static const char *commands[] =
1093     {
1094 #include "language/command.def"
1095       ""
1096     };
1097   static size_t n_commands = (sizeof commands / sizeof *commands) - 1;
1098 #undef DEF_CMD
1099 #undef UNIMPL_CMD
1100
1101   static bool inited;
1102
1103   static const char **cindex[UCHAR_MAX + 1];
1104
1105   if (!inited)
1106     {
1107       size_t i;
1108
1109       inited = true;
1110
1111       qsort (commands, n_commands, sizeof *commands, compare_commands);
1112       for (i = 0; i < n_commands; i++)
1113         {
1114           unsigned char c = c_toupper (commands[i][0]);
1115           if (cindex[c] == NULL)
1116             cindex[c] = &commands[i];
1117         }
1118       for (i = 0; i <= UCHAR_MAX; i++)
1119         if (cindex[i] == NULL)
1120           cindex[i] = &commands[n_commands];
1121     }
1122
1123   return cindex[c_toupper (first)];
1124 }
1125
1126 static int
1127 segmenter_detect_command_name__ (const char *input, size_t n, bool eof,
1128                                  int ofs)
1129 {
1130   const char **commands;
1131
1132   input += ofs;
1133   n -= ofs;
1134   ofs = 0;
1135   for (;;)
1136     {
1137       ucs4_t uc;
1138       int mblen;
1139
1140       if (ofs >= n)
1141         {
1142           if (eof)
1143             break;
1144           return -1;
1145         }
1146
1147       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1148       if (mblen < 0)
1149         return -1;
1150
1151       if (uc == '\n'
1152           || !(lex_uc_is_space (uc) || lex_uc_is_idn (uc) || uc == '-'))
1153         break;
1154
1155       ofs += mblen;
1156     }
1157   if (!ofs)
1158     return 0;
1159
1160   if (input[ofs - 1] == '.')
1161     ofs--;
1162
1163   for (commands = segmenter_get_command_name_candidates (input[0]);
1164        c_toupper (input[0]) == c_toupper ((*commands)[0]);
1165        commands++)
1166     {
1167       int missing_words;
1168       bool exact;
1169
1170       if (command_match (ss_cstr (*commands), ss_buffer (input, ofs),
1171                          &exact, &missing_words)
1172           && missing_words <= 0)
1173         return 1;
1174     }
1175
1176   return 0;
1177 }
1178
1179 static int
1180 is_start_of_string__ (const char *input, size_t n, bool eof, int ofs)
1181 {
1182   if (ofs >= n)
1183     return eof ? 0 : -1;
1184
1185   int c = input[ofs];
1186   if (c == 'x' || c == 'X' || c == 'u' || c == 'U')
1187     {
1188       if (ofs + 1 >= n)
1189         return eof ? 0 : -1;
1190
1191       return input[ofs + 1] == '\'' || input[ofs + 1] == '"';
1192     }
1193   else
1194     return c == '\'' || c == '"' || c == '\n';
1195 }
1196
1197 static int
1198 segmenter_parse_start_of_line__ (struct segmenter *s,
1199                                  const char *input, size_t n, bool eof,
1200                                  enum segment_type *type)
1201 {
1202   ucs4_t uc;
1203   int mblen;
1204   int ofs;
1205
1206   assert (s->state == S_GENERAL);
1207   assert (s->substate & SS_START_OF_LINE);
1208
1209   mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, 0);
1210   if (mblen < 0)
1211     return -1;
1212
1213   switch (uc)
1214     {
1215     case '+':
1216       ofs = skip_spaces_and_comments (input, n, eof, 1);
1217       if (ofs < 0)
1218         return -1;
1219       else
1220         {
1221           int is_string = is_start_of_string__ (input, n, eof, ofs);
1222           if (is_string < 0)
1223             return -1;
1224           else if (is_string)
1225             {
1226               /* This is punctuation that may separate pieces of a string. */
1227               *type = SEG_PUNCT;
1228               s->substate = 0;
1229               return 1;
1230             }
1231         }
1232       /* Fall through. */
1233
1234     case '-':
1235     case '.':
1236       *type = SEG_START_COMMAND;
1237       s->substate = SS_START_OF_COMMAND;
1238       return 1;
1239
1240     default:
1241       if (lex_uc_is_space (uc))
1242         {
1243           int eol = at_end_of_line (input, n, eof, 0);
1244           if (eol < 0)
1245             return -1;
1246           else if (eol)
1247             {
1248               s->substate = SS_START_OF_COMMAND;
1249               *type = SEG_SEPARATE_COMMANDS;
1250               return 0;
1251             }
1252           break;
1253         }
1254
1255       if (s->mode == SEG_MODE_INTERACTIVE || s->substate & SS_START_OF_COMMAND)
1256         break;
1257       else if (s->mode == SEG_MODE_AUTO)
1258         {
1259           int cmd = segmenter_detect_command_name__ (input, n, eof, 0);
1260           if (cmd < 0)
1261             return -1;
1262           else if (cmd == 0)
1263             break;
1264         }
1265       else
1266         assert (s->mode == SEG_MODE_BATCH);
1267
1268       s->substate = SS_START_OF_COMMAND;
1269       *type = SEG_START_COMMAND;
1270       return 0;
1271     }
1272
1273   s->substate = SS_START_OF_COMMAND;
1274   return segmenter_parse_mid_command__ (s, input, n, eof, type);
1275 }
1276
1277 static int
1278 segmenter_parse_file_label_1__ (struct segmenter *s,
1279                                 const char *input, size_t n, bool eof,
1280                                 enum segment_type *type)
1281 {
1282   struct segmenter sub;
1283   int ofs;
1284
1285   sub = *s;
1286   sub.state = S_GENERAL;
1287   ofs = segmenter_push (&sub, input, n, eof, type);
1288
1289   if (ofs < 0)
1290     return -1;
1291   else if (*type == SEG_IDENTIFIER)
1292     {
1293       int result;
1294
1295       assert (lex_id_match (ss_cstr ("LABEL"),
1296                             ss_buffer ((char *) input, ofs)));
1297       result = segmenter_unquoted (input, n, eof, ofs);
1298       if (result < 0)
1299         return -1;
1300       else
1301         {
1302           if (result)
1303             s->state = S_FILE_LABEL_2;
1304           else
1305             *s = sub;
1306           return ofs;
1307         }
1308     }
1309   else
1310     {
1311       s->substate = sub.substate;
1312       return ofs;
1313     }
1314 }
1315
1316 static int
1317 segmenter_parse_file_label_2__ (struct segmenter *s,
1318                                 const char *input, size_t n, bool eof,
1319                                 enum segment_type *type)
1320 {
1321   int ofs;
1322
1323   ofs = skip_spaces (input, n, eof, 0);
1324   if (ofs < 0)
1325     return -1;
1326   s->state = S_FILE_LABEL_3;
1327   *type = SEG_SPACES;
1328   return ofs;
1329 }
1330
1331 static int
1332 segmenter_parse_file_label_3__ (struct segmenter *s,
1333                                 const char *input, size_t n, bool eof,
1334                                 enum segment_type *type)
1335 {
1336   int endcmd;
1337   int ofs;
1338
1339   endcmd = -1;
1340   ofs = 0;
1341   while (ofs < n)
1342     {
1343       ucs4_t uc;
1344       int mblen;
1345
1346       mblen = segmenter_u8_to_uc__ (&uc, input, n, eof, ofs);
1347       if (mblen < 0)
1348         return -1;
1349
1350       switch (uc)
1351         {
1352         case '\n':
1353           goto end_of_line;
1354
1355         case '.':
1356           endcmd = ofs;
1357           break;
1358
1359         default:
1360           if (!lex_uc_is_space (uc))
1361             endcmd = -1;
1362           break;
1363         }
1364
1365       ofs += mblen;
1366     }
1367
1368   if (eof)
1369     {
1370     end_of_line:
1371       s->state = S_GENERAL;
1372       s->substate = 0;
1373       *type = SEG_UNQUOTED_STRING;
1374       return endcmd >= 0 ? endcmd : ofs;
1375     }
1376
1377   return -1;
1378 }
1379
1380 static int
1381 segmenter_subparse (struct segmenter *s,
1382                     const char *input, size_t n, bool eof,
1383                     enum segment_type *type)
1384 {
1385   struct segmenter sub;
1386   int ofs;
1387
1388   sub.mode = s->mode;
1389   sub.state = S_GENERAL;
1390   sub.substate = s->substate;
1391   ofs = segmenter_push (&sub, input, n, eof, type);
1392   s->substate = sub.substate;
1393   return ofs;
1394 }
1395
1396 /* We are segmenting a DO REPEAT command, currently reading the syntax that
1397    defines the stand-in variables (the head) before the lines of syntax to be
1398    repeated (the body). */
1399 static int
1400 segmenter_parse_do_repeat_1__ (struct segmenter *s,
1401                                const char *input, size_t n, bool eof,
1402                                enum segment_type *type)
1403 {
1404   int ofs = segmenter_subparse (s, input, n, eof, type);
1405   if (ofs < 0)
1406     return -1;
1407
1408   if (*type == SEG_SEPARATE_COMMANDS)
1409     {
1410       /* We reached a blank line that separates the head from the body. */
1411       s->state = S_DO_REPEAT_2;
1412     }
1413   else if (*type == SEG_END_COMMAND || *type == SEG_START_COMMAND)
1414     {
1415       /* We reached the body. */
1416       s->state = S_DO_REPEAT_3;
1417       s->substate = 1;
1418     }
1419
1420   return ofs;
1421 }
1422
1423 /* We are segmenting a DO REPEAT command, currently reading a blank line that
1424    separates the head from the body. */
1425 static int
1426 segmenter_parse_do_repeat_2__ (struct segmenter *s,
1427                                const char *input, size_t n, bool eof,
1428                                enum segment_type *type)
1429 {
1430   int ofs = segmenter_subparse (s, input, n, eof, type);
1431   if (ofs < 0)
1432     return -1;
1433
1434   if (*type == SEG_NEWLINE)
1435     {
1436       /* We reached the body. */
1437       s->state = S_DO_REPEAT_3;
1438       s->substate = 1;
1439     }
1440
1441   return ofs;
1442 }
1443
1444 static bool
1445 check_repeat_command (struct segmenter *s,
1446                       const char *input, size_t n, bool eof)
1447 {
1448   int direction;
1449   char id[16];
1450   int ofs;
1451
1452   ofs = 0;
1453   if (input[ofs] == '+' || input[ofs] == '-')
1454     ofs++;
1455
1456   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1457   if (ofs < 0)
1458     return false;
1459   else if (lex_id_match (ss_cstr ("DO"), ss_cstr (id)))
1460     direction = 1;
1461   else if (lex_id_match (ss_cstr ("END"), ss_cstr (id)))
1462     direction = -1;
1463   else
1464     return true;
1465
1466   ofs = next_id_in_command (s, input, n, eof, ofs, id, sizeof id);
1467   if (ofs < 0)
1468     return false;
1469
1470   if (lex_id_match (ss_cstr ("REPEAT"), ss_cstr (id)))
1471     s->substate += direction;
1472   return true;
1473 }
1474
1475 static int
1476 segmenter_parse_full_line__ (const char *input, size_t n, bool eof,
1477                              enum segment_type *type)
1478 {
1479   const char *newline = memchr (input, '\n', n);
1480   if (!newline)
1481     return eof ? n : -1;
1482
1483   ptrdiff_t ofs = newline - input;
1484   if (ofs == 0 || (ofs == 1 && input[0] == '\r'))
1485     {
1486       *type = SEG_NEWLINE;
1487       return ofs + 1;
1488     }
1489   else
1490     return ofs - (input[ofs - 1] == '\r');
1491 }
1492
1493 /* We are in the body of DO REPEAT, segmenting the lines of syntax that are to
1494    be repeated.  Report each line of syntax as a single SEG_DO_REPEAT_COMMAND.
1495
1496    DO REPEAT can be nested, so we look for DO REPEAT...END REPEAT blocks inside
1497    the lines we're segmenting.  s->substate counts the nesting level, starting
1498    at 1. */
1499 static int
1500 segmenter_parse_do_repeat_3__ (struct segmenter *s,
1501                                const char *input, size_t n, bool eof,
1502                                enum segment_type *type)
1503 {
1504   int ofs;
1505
1506   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1507   if (ofs < 0 || (ofs > 0 && input[ofs - 1] == '\n'))
1508     return ofs;
1509   else if (!check_repeat_command (s, input, n, eof) && !eof)
1510     return -1;
1511   else if (s->substate == 0)
1512     {
1513       /* Nesting level dropped to 0, so we've finished reading the DO REPEAT
1514          body. */
1515       s->state = S_GENERAL;
1516       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1517       return segmenter_push (s, input, n, eof, type);
1518     }
1519   else
1520     {
1521       *type = SEG_DO_REPEAT_COMMAND;
1522       return ofs;
1523     }
1524 }
1525
1526 /* We are segmenting a DEFINE command, which consists of:
1527
1528   - The DEFINE keyword.
1529
1530   - An identifier.  We transform this into SEG_MACRO_NAME instead of
1531     SEG_IDENTIFIER or SEG_MACRO_NAME because this identifier must never be
1532     macro-expanded.
1533
1534   - Anything but "(".
1535
1536   - "(" followed by a sequence of tokens possibly including balanced parentheses
1537     up to a final ")".
1538
1539   - A sequence of any number of lines, one string per line, ending with
1540     "!ENDDEFINE".  The first line is usually blank (that is, a newline follows
1541     the "(").  The last line usually just has "!ENDDEFINE." on it, but it can
1542     start with other tokens.  The whole DEFINE...!ENDDEFINE can be on a single
1543     line, even.
1544    */
1545 static int
1546 segmenter_parse_define_1_2__ (struct segmenter *s,
1547                               const char *input, size_t n, bool eof,
1548                               enum segment_type *type)
1549 {
1550   int ofs = segmenter_subparse (s, input, n, eof, type);
1551   if (ofs < 0)
1552     return -1;
1553
1554   if (s->state == S_DEFINE_1
1555       && (*type == SEG_IDENTIFIER || *type == SEG_MACRO_ID))
1556     {
1557       *type = SEG_MACRO_NAME;
1558       s->state = S_DEFINE_2;
1559     }
1560   else if (*type == SEG_SEPARATE_COMMANDS
1561       || *type == SEG_END_COMMAND
1562       || *type == SEG_START_COMMAND)
1563     {
1564       /* The DEFINE command is malformed because we reached its end without
1565          ever hitting a "(" token.  Transition back to general parsing. */
1566       s->state = S_GENERAL;
1567       return ofs;
1568     }
1569   else if (*type == SEG_PUNCT && input[0] == '(')
1570     {
1571       s->state = S_DEFINE_3;
1572       s->nest = 1;
1573       return ofs;
1574     }
1575
1576   return ofs;
1577 }
1578
1579 static int
1580 segmenter_parse_define_3__ (struct segmenter *s,
1581                             const char *input, size_t n, bool eof,
1582                             enum segment_type *type)
1583 {
1584   int ofs = segmenter_subparse (s, input, n, eof, type);
1585   if (ofs < 0)
1586     return -1;
1587
1588   if (*type == SEG_SEPARATE_COMMANDS
1589       || *type == SEG_END_COMMAND
1590       || *type == SEG_START_COMMAND)
1591     {
1592       /* The DEFINE command is malformed because we reached its end before
1593          closing the set of parentheses.  Transition back to general
1594          parsing. */
1595       s->state = S_GENERAL;
1596       return ofs;
1597     }
1598   else if (*type == SEG_PUNCT && input[0] == '(')
1599     {
1600       s->nest++;
1601       return ofs;
1602     }
1603   else if (*type == SEG_PUNCT && input[0] == ')')
1604     {
1605       s->nest--;
1606       if (!s->nest)
1607         {
1608           s->state = S_DEFINE_4;
1609           s->substate = 0;
1610         }
1611       return ofs;
1612     }
1613
1614   return ofs;
1615 }
1616
1617 static size_t
1618 find_enddefine (struct substring input)
1619 {
1620   size_t n = input.length;
1621   const struct substring enddefine = ss_cstr ("!ENDDEFINE");
1622   for (int ofs = 0;;)
1623     {
1624       /* Skip !ENDDEFINE in comment. */
1625       ofs = skip_spaces_and_comments (input.string, n, true, ofs);
1626       if (ofs + enddefine.length > n)
1627         return SIZE_MAX;
1628
1629       char c = input.string[ofs];
1630       if (c == '!'
1631                && ss_equals_case (ss_substr (input, ofs, enddefine.length),
1632                                   enddefine))
1633         return ofs;
1634       else if (c == '\'' || c == '"')
1635         {
1636           /* Skip quoted !ENDDEFINE. */
1637           ofs++;
1638           for (;;)
1639             {
1640               if (ofs >= n)
1641                 return SIZE_MAX;
1642               else if (input.string[ofs++] == c)
1643                 break;
1644             }
1645         }
1646       else
1647         ofs++;
1648     }
1649 }
1650
1651 /* We are in the body of a macro definition, looking for additional lines of
1652    the body or !ENDDEFINE. */
1653 static int
1654 segmenter_parse_define_4__ (struct segmenter *s,
1655                             const char *input, size_t n, bool eof,
1656                             enum segment_type *type)
1657 {
1658   /* Gather a whole line. */
1659   const char *newline = memchr (input, '\n', n);
1660   int ofs = (newline ? newline - input - (newline > input && newline[-1] == '\r')
1661              : eof ? n
1662              : -1);
1663   if (ofs < 0)
1664     return -1;
1665
1666   /* Does the line contain !ENDDEFINE? */
1667   size_t end = find_enddefine (ss_buffer (input, ofs));
1668   if (end == SIZE_MAX)
1669     {
1670       /* No !ENDDEFINE.  We have a full line of macro body.
1671
1672          The line might be blank, whether completely empty or just spaces and
1673          comments.  That's OK: we need to report blank lines because they can
1674          have significance.
1675
1676          However, if the first line of the macro body (the same line as the
1677          closing parenthesis in the argument definition) is blank, we just
1678          report it as spaces because it's not significant. */
1679       *type = (s->substate == 0 && is_all_spaces (input, ofs)
1680                ? SEG_SPACES : SEG_MACRO_BODY);
1681       s->state = S_DEFINE_5;
1682       s->substate = 1;
1683       return ofs;
1684     }
1685   else
1686     {
1687       /* Macro ends at the !ENDDEFINE on this line. */
1688       s->state = S_GENERAL;
1689       s->substate = 0;
1690       if (!end)
1691         {
1692           /* Line starts with !ENDDEFINE. */
1693           return segmenter_push (s, input, n, eof, type);
1694         }
1695       else
1696         {
1697           if (is_all_spaces (input, end))
1698             {
1699               /* Line starts with spaces followed by !ENDDEFINE. */
1700               *type = SEG_SPACES;
1701             }
1702           else
1703             {
1704               /* Line starts with some content followed by !ENDDEFINE. */
1705               *type = SEG_MACRO_BODY;
1706             }
1707           return end;
1708         }
1709     }
1710 }
1711
1712 static int
1713 segmenter_parse_define_5__ (struct segmenter *s,
1714                             const char *input, size_t n, bool eof,
1715                             enum segment_type *type)
1716 {
1717   int ofs = segmenter_parse_newline__ (input, n, eof, type);
1718   if (ofs < 0)
1719     return -1;
1720
1721   s->state = S_DEFINE_4;
1722   return ofs;
1723 }
1724
1725 static int
1726 segmenter_parse_begin_data_1__ (struct segmenter *s,
1727                                 const char *input, size_t n, bool eof,
1728                                 enum segment_type *type)
1729 {
1730   int ofs = segmenter_subparse (s, input, n, eof, type);
1731   if (ofs < 0)
1732     return -1;
1733
1734   if (*type == SEG_NEWLINE)
1735     s->state = S_BEGIN_DATA_2;
1736
1737   return ofs;
1738 }
1739
1740 static int
1741 segmenter_parse_begin_data_2__ (struct segmenter *s,
1742                                 const char *input, size_t n, bool eof,
1743                                 enum segment_type *type)
1744 {
1745   int ofs = segmenter_subparse (s, input, n, eof, type);
1746   if (ofs < 0)
1747     return -1;
1748
1749   if (*type == SEG_NEWLINE)
1750     s->state = S_BEGIN_DATA_3;
1751
1752   return ofs;
1753 }
1754
1755 static bool
1756 is_end_data (const char *input, size_t n)
1757 {
1758   const uint8_t *u_input = CHAR_CAST (const uint8_t *, input);
1759   bool endcmd;
1760   ucs4_t uc;
1761   int mblen;
1762   int ofs;
1763
1764   if (n < 4 || c_strncasecmp (input, "END", 3))
1765     return false;
1766
1767   ofs = 3;
1768   mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1769   if (!lex_uc_is_space (uc))
1770     return false;
1771   ofs += mblen;
1772
1773   if (n - ofs < 4 || c_strncasecmp (input + ofs, "DATA", 4))
1774     return false;
1775   ofs += 4;
1776
1777   endcmd = false;
1778   while (ofs < n)
1779     {
1780       mblen = u8_mbtouc (&uc, u_input + ofs, n - ofs);
1781       if (uc == '.')
1782         {
1783           if (endcmd)
1784             return false;
1785           endcmd = true;
1786         }
1787       else if (!lex_uc_is_space (uc))
1788         return false;
1789       ofs += mblen;
1790     }
1791
1792   return true;
1793 }
1794
1795 static int
1796 segmenter_parse_begin_data_3__ (struct segmenter *s,
1797                                 const char *input, size_t n, bool eof,
1798                                 enum segment_type *type)
1799 {
1800   int ofs;
1801
1802   ofs = segmenter_parse_full_line__ (input, n, eof, type);
1803   if (ofs < 0)
1804     return -1;
1805   else if (is_end_data (input, ofs))
1806     {
1807       s->state = S_GENERAL;
1808       s->substate = SS_START_OF_COMMAND | SS_START_OF_LINE;
1809       return segmenter_push (s, input, n, eof, type);
1810     }
1811   else
1812     {
1813       *type = SEG_INLINE_DATA;
1814       s->state = S_BEGIN_DATA_4;
1815       return input[ofs - 1] == '\n' ? 0 : ofs;
1816     }
1817 }
1818
1819 static int
1820 segmenter_parse_begin_data_4__ (struct segmenter *s,
1821                                 const char *input, size_t n, bool eof,
1822                                 enum segment_type *type)
1823 {
1824   int ofs;
1825
1826   ofs = segmenter_parse_newline__ (input, n, eof, type);
1827   if (ofs < 0)
1828     return -1;
1829
1830   s->state = S_BEGIN_DATA_3;
1831   return ofs;
1832 }
1833
1834 /* Returns the name of segment TYPE as a string.  The caller must not modify
1835    or free the returned string.
1836
1837    This is useful only for debugging and testing. */
1838 const char *
1839 segment_type_to_string (enum segment_type type)
1840 {
1841   switch (type)
1842     {
1843 #define SEG_TYPE(NAME) case SEG_##NAME: return #NAME;
1844       SEG_TYPES
1845 #undef SEG_TYPE
1846     default:
1847       return "unknown segment type";
1848     }
1849 }
1850
1851 /* Returns a segmenter with the given syntax MODE.
1852
1853    If IS_SNIPPET is false, then the segmenter will parse as if it's being given
1854    a whole file.  This means, for example, that it will interpret - or + at the
1855    beginning of the syntax as a separator between commands (since - or + at the
1856    beginning of a line has this meaning).
1857
1858    If IS_SNIPPET is true, then the segmenter will parse as if it's being given
1859    an isolated piece of syntax.  This means that, for example, that it will
1860    interpret - or + at the beginning of the syntax as an operator token or (if
1861    followed by a digit) as part of a number.
1862
1863    A segmenter does not contain any external references, so nothing needs to be
1864    done to destroy one.  For the same reason, segmenters may be copied with
1865    plain struct assignment (or memcpy). */
1866 struct segmenter
1867 segmenter_init (enum segmenter_mode mode, bool is_snippet)
1868 {
1869   return (struct segmenter) {
1870     .state = is_snippet ? S_GENERAL : S_SHBANG,
1871     .mode = mode,
1872   };
1873 }
1874
1875 /* Returns the mode passed to segmenter_init() for S. */
1876 enum segmenter_mode
1877 segmenter_get_mode (const struct segmenter *s)
1878 {
1879   return s->mode;
1880 }
1881
1882 /* Attempts to label a prefix of S's remaining input with a segment type.  The
1883    caller supplies the first N bytes of the remaining input as INPUT, which
1884    must be a UTF-8 encoded string.  If EOF is true, then the N bytes supplied
1885    are the entire (remainder) of the input; if EOF is false, then further input
1886    is potentially available.
1887
1888    The input may contain '\n' or '\r\n' line ends in any combination.
1889
1890    If successful, returns the number of bytes in the segment at the beginning
1891    of INPUT (between 0 and N, inclusive) and stores the type of that segment
1892    into *TYPE.  The next call to segmenter_push() should not include those
1893    bytes as part of INPUT, because they have (figuratively) been consumed by
1894    the segmenter.
1895
1896    Segments can have zero length, including segment types SEG_END,
1897    SEG_SEPARATE_COMMANDS, SEG_START_DOCUMENT, SEG_INLINE_DATA, and SEG_SPACES.
1898
1899    Failure occurs only if the segment type of the N bytes in INPUT cannot yet
1900    be determined.  In this case segmenter_push() returns -1.  If more input is
1901    available, the caller should obtain some more, then call again with a larger
1902    N.  If this is not enough, the process might need to repeat again and agin.
1903    If input is exhausted, then the caller may call again setting EOF to true.
1904    segmenter_push() will never return -1 when EOF is true.
1905
1906    The caller must not, in a sequence of calls, supply contradictory input.
1907    That is, bytes provided as part of INPUT in one call, but not consumed, must
1908    not be provided with *different* values on subsequent calls.  This is
1909    because segmenter_push() must often make decisions based on looking ahead
1910    beyond the bytes that it consumes. */
1911 int
1912 segmenter_push (struct segmenter *s, const char *input, size_t n, bool eof,
1913                 enum segment_type *type)
1914 {
1915   if (!n)
1916     {
1917       if (eof)
1918         {
1919           *type = SEG_END;
1920           return 0;
1921         }
1922       else
1923         return -1;
1924     }
1925
1926   switch (s->state)
1927     {
1928     case S_SHBANG:
1929       return segmenter_parse_shbang__ (s, input, n, eof, type);
1930
1931     case S_GENERAL:
1932       return (s->substate & SS_START_OF_LINE
1933               ? segmenter_parse_start_of_line__ (s, input, n, eof, type)
1934               : segmenter_parse_mid_command__ (s, input, n, eof, type));
1935
1936     case S_COMMENT_1:
1937       return segmenter_parse_comment_1__ (s, input, n, eof, type);
1938     case S_COMMENT_2:
1939       return segmenter_parse_comment_2__ (s, input, n, eof, type);
1940
1941     case S_DOCUMENT_1:
1942       return segmenter_parse_document_1__ (s, input, n, eof, type);
1943     case S_DOCUMENT_2:
1944       return segmenter_parse_document_2__ (s, input, n, eof, type);
1945     case S_DOCUMENT_3:
1946       return segmenter_parse_document_3__ (s, type);
1947
1948     case S_FILE_LABEL_1:
1949       return segmenter_parse_file_label_1__ (s, input, n, eof, type);
1950     case S_FILE_LABEL_2:
1951       return segmenter_parse_file_label_2__ (s, input, n, eof, type);
1952     case S_FILE_LABEL_3:
1953       return segmenter_parse_file_label_3__ (s, input, n, eof, type);
1954
1955     case S_DO_REPEAT_1:
1956       return segmenter_parse_do_repeat_1__ (s, input, n, eof, type);
1957     case S_DO_REPEAT_2:
1958       return segmenter_parse_do_repeat_2__ (s, input, n, eof, type);
1959     case S_DO_REPEAT_3:
1960       return segmenter_parse_do_repeat_3__ (s, input, n, eof, type);
1961
1962     case S_DEFINE_1:
1963     case S_DEFINE_2:
1964       return segmenter_parse_define_1_2__ (s, input, n, eof, type);
1965     case S_DEFINE_3:
1966       return segmenter_parse_define_3__ (s, input, n, eof, type);
1967     case S_DEFINE_4:
1968       return segmenter_parse_define_4__ (s, input, n, eof, type);
1969     case S_DEFINE_5:
1970       return segmenter_parse_define_5__ (s, input, n, eof, type);
1971
1972     case S_BEGIN_DATA_1:
1973       return segmenter_parse_begin_data_1__ (s, input, n, eof, type);
1974     case S_BEGIN_DATA_2:
1975       return segmenter_parse_begin_data_2__ (s, input, n, eof, type);
1976     case S_BEGIN_DATA_3:
1977       return segmenter_parse_begin_data_3__ (s, input, n, eof, type);
1978     case S_BEGIN_DATA_4:
1979       return segmenter_parse_begin_data_4__ (s, input, n, eof, type);
1980     }
1981
1982   NOT_REACHED ();
1983 }
1984
1985 /* Returns the style of command prompt to display to an interactive user for
1986    input in S.  The return value is most accurate in mode SEG_MODE_INTERACTIVE
1987    and at the beginning of a line (that is, if segmenter_push() consumed as
1988    much as possible of the input up to a new-line).  */
1989 enum prompt_style
1990 segmenter_get_prompt (const struct segmenter *s)
1991 {
1992   switch (s->state)
1993     {
1994     case S_SHBANG:
1995       return PROMPT_FIRST;
1996
1997     case S_GENERAL:
1998       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
1999
2000     case S_COMMENT_1:
2001     case S_COMMENT_2:
2002       return PROMPT_COMMENT;
2003
2004     case S_DOCUMENT_1:
2005     case S_DOCUMENT_2:
2006       return PROMPT_DOCUMENT;
2007     case S_DOCUMENT_3:
2008       return PROMPT_FIRST;
2009
2010     case S_FILE_LABEL_1:
2011       return PROMPT_LATER;
2012     case S_FILE_LABEL_2:
2013     case S_FILE_LABEL_3:
2014       return PROMPT_FIRST;
2015
2016     case S_DO_REPEAT_1:
2017     case S_DO_REPEAT_2:
2018       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
2019     case S_DO_REPEAT_3:
2020       return PROMPT_DO_REPEAT;
2021
2022     case S_DEFINE_1:
2023     case S_DEFINE_2:
2024     case S_DEFINE_3:
2025       return s->substate & SS_START_OF_COMMAND ? PROMPT_FIRST : PROMPT_LATER;
2026     case S_DEFINE_4:
2027     case S_DEFINE_5:
2028       return PROMPT_DEFINE;
2029
2030     case S_BEGIN_DATA_1:
2031       return PROMPT_FIRST;
2032     case S_BEGIN_DATA_2:
2033       return PROMPT_LATER;
2034     case S_BEGIN_DATA_3:
2035     case S_BEGIN_DATA_4:
2036       return PROMPT_DATA;
2037
2038     }
2039
2040   NOT_REACHED ();
2041 }