Work on DEFINE command.
[pspp] / src / language / lexer / segment.c
index 8d17ce38fe56b4de73d05b764c652a9d9a040594..ac88117ff5270e1a8b43cdf38172af5aaf431f16 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "gl/c-ctype.h"
 #include "gl/c-strcase.h"
+#include "gl/verify.h"
 
 enum segmenter_state
   {
@@ -54,6 +55,9 @@ enum segmenter_state
     S_TITLE_2
   };
 
+/* S_SHBANG is the start state that SEGMENTER_INIT refers to as just 0. */
+verify (S_SHBANG == 0);
+
 #define SS_START_OF_LINE (1u << 0)
 #define SS_START_OF_COMMAND (1u << 1)
 
@@ -227,7 +231,7 @@ is_all_spaces (const char *input_, size_t n)
   for (int ofs = 0; ofs < n; ofs += mblen)
     {
       ucs4_t uc;
-      mblen = u8_mbtouc (&uc, input, n);
+      mblen = u8_mbtouc (&uc, input + ofs, n - ofs);
       if (!lex_uc_is_space (uc))
         return false;
     }
@@ -1512,7 +1516,10 @@ segmenter_parse_define_2__ (struct segmenter *s,
     {
       s->nest--;
       if (!s->nest)
-        s->state = S_DEFINE_3;
+        {
+          s->state = S_DEFINE_3;
+          s->substate = 0;
+        }
       return ofs;
     }
 
@@ -1554,9 +1561,15 @@ segmenter_parse_define_3__ (struct segmenter *s,
 
          The line might be blank, whether completely empty or just spaces and
          comments.  That's OK: we need to report blank lines because they can
-         have significance. */
-      *type = SEG_MACRO_BODY;
+         have significance.
+
+         However, if the first line of the macro body (the same line as the
+         closing parenthesis in the argument definition) is blank, we just
+         report it as spaces because it's not significant. */
+      *type = (s->substate == 0 && is_all_spaces (input, ofs)
+               ? SEG_SPACES : SEG_MACRO_BODY);
       s->state = S_DEFINE_4;
+      s->substate = 1;
       return ofs;
     }
   else
@@ -1797,9 +1810,7 @@ segment_type_to_string (enum segment_type type)
 void
 segmenter_init (struct segmenter *s, enum segmenter_mode mode)
 {
-  s->state = S_SHBANG;
-  s->substate = 0;
-  s->mode = mode;
+  *s = (struct segmenter) SEGMENTER_INIT (mode);
 }
 
 /* Returns the mode passed to segmenter_init() for S. */