Fix a new warning on Cygwin
[binutils-gdb.git] / gdb / ada-lex.l
index a0c9816e5683c737a7ee6bf9763a49b78f2487f9..33a08eaa93b8cb1b30a1915da5e82feeda5f815f 100644 (file)
@@ -39,6 +39,11 @@ OPER    ([-+*/=<>&]|"<="|">="|"**"|"/="|"and"|"or"|"xor"|"not"|"mod"|"rem"|"abs"
 EXP    (e[+-]{NUM10})
 POSEXP  (e"+"?{NUM10})
 
+/* This must agree with COMPLETION_CHAR below.  See the comment there
+   for the explanation.  */
+COMPLETE "\001"
+NOT_COMPLETE [^\001]
+
 %{
 
 #include "diagnostics.h"
@@ -73,18 +78,35 @@ static void rewind_to_char (int);
    Defining YY_NO_INPUT comments it out.  */
 #define YY_NO_INPUT
 
-#undef YY_INPUT
-#define YY_INPUT(BUF, RESULT, MAX_SIZE) \
-    if ( *pstate->lexptr == '\000' ) \
-      (RESULT) = YY_NULL; \
-    else \
-      { \
-        *(BUF) = *pstate->lexptr; \
-        (RESULT) = 1; \
-       pstate->lexptr += 1; \
-      }
+/* When completing, we'll return a special character at the end of the
+   input, to signal the completion position to the lexer.  This is
+   done because flex does not have a generally useful way to detect
+   EOF in a pattern.  This variable records whether the special
+   character has been emitted.  */
+static bool returned_complete = false;
 
-static int find_dot_all (const char *);
+/* The character we use to represent the completion point.  */
+#define COMPLETE_CHAR '\001'
+
+#undef YY_INPUT
+#define YY_INPUT(BUF, RESULT, MAX_SIZE)                                        \
+  if ( *pstate->lexptr == '\000' )                                     \
+    {                                                                  \
+      if (pstate->parse_completion && !returned_complete)              \
+       {                                                               \
+         returned_complete = true;                                     \
+         *(BUF) = COMPLETE_CHAR;                                       \
+         (RESULT) = 1;                                                 \
+       }                                                               \
+      else                                                             \
+       (RESULT) = YY_NULL;                                             \
+    }                                                                  \
+  else                                                                 \
+    {                                                                  \
+      *(BUF) = *pstate->lexptr == COMPLETE_CHAR ? ' ' : *pstate->lexptr; \
+      (RESULT) = 1;                                                    \
+      pstate->lexptr += 1;                                             \
+    }
 
 /* Depth of parentheses.  */
 static int paren_depth;
@@ -227,7 +249,7 @@ false               { return FALSEKEYWORD; }
 
         /* ATTRIBUTES */
 
-{TICK}[a-z][a-z_]+ { BEGIN INITIAL; return processAttribute (yytext+1); }
+{TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute (yytext); }
 
        /* PUNCTUATION */
 
@@ -239,9 +261,9 @@ false               { return FALSEKEYWORD; }
 "<="           { return LEQ; }
 ">="           { return GEQ; }
 
-<BEFORE_QUAL_QUOTE>"'" { BEGIN INITIAL; return '\''; }
+<BEFORE_QUAL_QUOTE>"'"/{NOT_COMPLETE} { BEGIN INITIAL; return '\''; }
 
-[-&*+./:<>=|;\[\]] { return yytext[0]; }
+[-&*+{}@/:<>=|;\[\]] { return yytext[0]; }
 
 ","            { if (paren_depth == 0 && pstate->comma_terminates)
                    {
@@ -265,14 +287,20 @@ false             { return FALSEKEYWORD; }
                    }
                }
 
-"."{WHITE}*all  { return DOT_ALL; }
-
-"."{WHITE}*{ID} {
+"."{WHITE}*{ID}{COMPLETE}? {
                  yylval.sval = processId (yytext+1, yyleng-1);
+                 if (yytext[yyleng - 1] == COMPLETE_CHAR)
+                   return DOT_COMPLETE;
                  return DOT_ID;
                }
 
-{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'")?  {
+"."{WHITE}*{COMPLETE} {
+                 yylval.sval.ptr = "";
+                 yylval.sval.length = 0;
+                 return DOT_COMPLETE;
+               }
+
+{ID}({WHITE}*"."{WHITE}*({ID}|\"{OPER}\"))*(" "*"'"|{COMPLETE})?  {
                   int all_posn = find_dot_all (yytext);
 
                   if (all_posn == -1 && yytext[yyleng-1] == '\'')
@@ -282,8 +310,9 @@ false               { return FALSEKEYWORD; }
                    }
                   else if (all_posn >= 0)
                    yyless (all_posn);
+                 bool is_completion = yytext[yyleng - 1] == COMPLETE_CHAR;
                   yylval.sval = processId (yytext, yyleng);
-                  return NAME;
+                  return is_completion ? NAME_COMPLETE : NAME;
                }
 
 
@@ -297,8 +326,6 @@ false               { return FALSEKEYWORD; }
 
 "::"            { return COLONCOLON; }
 
-[{}@]          { return yytext[0]; }
-
        /* REGISTERS AND GDB CONVENIENCE VARIABLES */
 
 "$"({LETTER}|{DIG}|"$")*  {
@@ -320,6 +347,7 @@ lexer_init (FILE *inp)
 {
   BEGIN INITIAL;
   paren_depth = 0;
+  returned_complete = false;
   yyrestart (inp);
 }
 
@@ -434,11 +462,11 @@ processInt (struct parser_state *par_state, const char *base0,
       return FLOAT;
     }
 
-  gdb_mpz maxval (ULONGEST_MAX / base);
+  gdb_mpz maxval (ULONGEST_MAX);
   if (mpz_cmp (result.val, maxval.val) > 0)
     error (_("Integer literal out of range"));
 
-  LONGEST value = result.as_integer<LONGEST> ();
+  ULONGEST value = result.as_integer<ULONGEST> ();
   if ((value >> (gdbarch_int_bit (par_state->gdbarch ())-1)) == 0)
     yylval.typed_val.type = type_int (par_state);
   else if ((value >> (gdbarch_long_bit (par_state->gdbarch ())-1)) == 0)
@@ -516,33 +544,33 @@ processId (const char *name0, int len)
       return result;
     }
 
+  bool in_quotes = false;
   i = i0 = 0;
   while (i0 < len)
     {
-      if (isalnum (name0[i0]))
+      if (name0[i0] == COMPLETE_CHAR)
+       {
+         /* Just ignore.  */
+         ++i0;
+       }
+      else if (in_quotes)
+       name[i++] = name0[i0++];
+      else if (isalnum (name0[i0]))
        {
          name[i] = tolower (name0[i0]);
          i += 1; i0 += 1;
        }
-      else switch (name0[i0])
+      else if (isspace (name0[i0]))
+       i0 += 1;
+      else if (name0[i0] == '\'')
        {
-       default:
-         name[i] = name0[i0];
-         i += 1; i0 += 1;
-         break;
-       case ' ': case '\t':
-         i0 += 1;
-         break;
-       case '\'':
-         do
-           {
-             name[i] = name0[i0];
-             i += 1; i0 += 1;
-           }
-         while (i0 < len && name0[i0] != '\'');
-         i0 += 1;
-         break;
+         /* Copy the starting quote, but not the ending quote.  */
+         if (!in_quotes)
+           name[i++] = name0[i0++];
+         in_quotes = !in_quotes;
        }
+      else
+       name[i++] = name0[i0++];
     }
   name[i] = '\000';
 
@@ -663,6 +691,21 @@ attributes[] = {
 static int
 processAttribute (const char *str)
 {
+  gdb_assert (*str == '\'');
+  ++str;
+  while (isspace (*str))
+    ++str;
+
+  int len = strlen (str);
+  if (len > 0 && str[len - 1] == COMPLETE_CHAR)
+    {
+      /* This is enforced by YY_INPUT.  */
+      gdb_assert (pstate->parse_completion);
+      yylval.sval.ptr = obstack_strndup (&temp_parse_space, str, len - 1);
+      yylval.sval.length = len - 1;
+      return TICK_COMPLETE;
+    }
+
   for (const auto &item : attributes)
     if (strcasecmp (str, item.name) == 0)
       return item.code;
@@ -682,6 +725,20 @@ processAttribute (const char *str)
   return *found;
 }
 
+bool
+ada_tick_completer::complete (struct expression *exp,
+                             completion_tracker &tracker)
+{
+  completion_list output;
+  for (const auto &item : attributes)
+    {
+      if (strncasecmp (item.name, m_name.c_str (), m_name.length ()) == 0)
+       output.emplace_back (xstrdup (item.name));
+    }
+  tracker.add_completions (std::move (output));
+  return true;
+}
+
 /* Back up lexptr by yyleng and then to the rightmost occurrence of
    character CH, case-folded (there must be one).  WARNING: since
    lexptr points to the next input character that Flex has not yet