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