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