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