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