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