gdb: LoongArch: Remove nonportable #include
[binutils-gdb.git] / gdb / ada-lex.l
index 8ce7c3a99a9cb061d2a0e411074f242b95d5a3c7..33a08eaa93b8cb1b30a1915da5e82feeda5f815f 100644 (file)
@@ -1,5 +1,5 @@
-/* FLEX lexer for Ada expressions, for GDB.
-   Copyright (C) 1994-2019 Free Software Foundation, Inc.
+/* FLEX lexer for Ada expressions, for GDB. -*- c++ -*-
+   Copyright (C) 1994-2022 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -30,7 +30,7 @@ HEXDIG        [0-9a-f]
 NUM16  ({HEXDIG}({HEXDIG}|_)*)
 OCTDIG [0-7]
 LETTER [a-z_]
-ID     ({LETTER}({LETTER}|{DIG})*|"<"{LETTER}({LETTER}|{DIG})*">")
+ID     ({LETTER}({LETTER}|{DIG}|[\x80-\xff])*|"<"{LETTER}({LETTER}|{DIG})*">")
 WHITE  [ \t\n]
 TICK   ("'"{WHITE}*)
 GRAPHIC [a-z0-9 #&'()*+,-./:;<>=_|!$%?@\[\]\\^`{}~]
@@ -39,13 +39,20 @@ 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"
 
 /* Some old versions of flex generate code that uses the "register" keyword,
    which clang warns about.  This was observed for example with flex 2.5.35,
-   as shipped with macOS 10.12.  */
+   as shipped with macOS 10.12.  The same happens with flex 2.5.37 and g++ 11
+   which defaults to ISO C++17, that does not allow register storage class
+   specifiers.  */
 DIAGNOSTIC_PUSH
 DIAGNOSTIC_IGNORE_DEPRECATED_REGISTER
 
@@ -71,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;
@@ -101,8 +125,9 @@ static int paren_depth;
 
 {NUM10}{POSEXP}  {
                   canonicalizeNumeral (numbuf, yytext);
-                  return processInt (pstate, NULL, numbuf,
-                                     strrchr (numbuf, 'e') + 1);
+                  char *e_ptr = strrchr (numbuf, 'e');
+                  *e_ptr = '\0';
+                  return processInt (pstate, nullptr, numbuf, e_ptr + 1);
                 }
 
 {NUM10}          {
@@ -112,12 +137,18 @@ static int paren_depth;
 
 {NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#"{POSEXP} {
                   canonicalizeNumeral (numbuf, yytext);
+                  char *e_ptr = strrchr (numbuf, 'e');
+                  *e_ptr = '\0';
                   return processInt (pstate, numbuf,
                                      strchr (numbuf, '#') + 1,
-                                     strrchr(numbuf, '#') + 1);
+                                     e_ptr + 1);
                 }
 
-{NUM10}"#"{HEXDIG}({HEXDIG}|_)*"#" {
+       /* The "llf" is a gdb extension to allow a floating-point
+          constant to be written in some other base.  The
+          floating-point number is formed by reinterpreting the
+          bytes, allowing direct control over the bits.  */
+{NUM10}(l{0,2}f)?"#"{HEXDIG}({HEXDIG}|_)*"#" {
                   canonicalizeNumeral (numbuf, yytext);
                   return processInt (pstate, numbuf, strchr (numbuf, '#') + 1,
                                      NULL);
@@ -148,20 +179,22 @@ static int paren_depth;
                }
 
 <INITIAL>"'"({GRAPHIC}|\")"'" {
-                  yylval.typed_val.type = type_char (pstate);
                   yylval.typed_val.val = yytext[1];
+                  yylval.typed_val.type = type_for_char (pstate, yytext[1]);
                   return CHARLIT;
                }
 
-<INITIAL>"'[\""{HEXDIG}{2}"\"]'"   {
-                   int v;
-                   yylval.typed_val.type = type_char (pstate);
-                  sscanf (yytext+3, "%2x", &v);
+<INITIAL>"'[\""{HEXDIG}{2,}"\"]'"   {
+                   ULONGEST v = strtoulst (yytext+3, nullptr, 16);
                   yylval.typed_val.val = v;
+                   yylval.typed_val.type = type_for_char (pstate, v);
                   return CHARLIT;
                }
 
-\"({GRAPHIC}|"[\""({HEXDIG}{2}|\")"\"]")*\"   {
+       /* Note that we don't handle bracket sequences of more than 2
+          digits here.  Currently there's no support for wide or
+          wide-wide strings.  */
+\"({GRAPHIC}|"[\""({HEXDIG}{2,}|\")"\"]")*\"   {
                   yylval.sval = processString (yytext+1, yyleng-2);
                   return STRING;
                }
@@ -216,7 +249,7 @@ false               { return FALSEKEYWORD; }
 
         /* ATTRIBUTES */
 
-{TICK}[a-zA-Z][a-zA-Z]+ { BEGIN INITIAL; return processAttribute (yytext+1); }
+{TICK}([a-z][a-z_]*)?{COMPLETE}? { BEGIN INITIAL; return processAttribute (yytext); }
 
        /* PUNCTUATION */
 
@@ -228,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)
                    {
@@ -254,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] == '\'')
@@ -271,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;
                }
 
 
@@ -286,8 +326,6 @@ false               { return FALSEKEYWORD; }
 
 "::"            { return COLONCOLON; }
 
-[{}@]          { return yytext[0]; }
-
        /* REGISTERS AND GDB CONVENIENCE VARIABLES */
 
 "$"({LETTER}|{DIG}|"$")*  {
@@ -309,6 +347,7 @@ lexer_init (FILE *inp)
 {
   BEGIN INITIAL;
   paren_depth = 0;
+  returned_complete = false;
   yyrestart (inp);
 }
 
@@ -340,18 +379,36 @@ static int
 processInt (struct parser_state *par_state, const char *base0,
            const char *num0, const char *exp0)
 {
-  ULONGEST result;
   long exp;
   int base;
-  const char *trailer;
+  /* For the based literal with an "f" prefix, we'll return a
+     floating-point number.  This counts the the number of "l"s seen,
+     to decide the width of the floating-point number to return.  -1
+     means no "f".  */
+  int floating_point_l_count = -1;
 
   if (base0 == NULL)
     base = 10;
   else
     {
-      base = strtol (base0, (char **) NULL, 10);
+      char *end_of_base;
+      base = strtol (base0, &end_of_base, 10);
       if (base < 2 || base > 16)
        error (_("Invalid base: %d."), base);
+      while (*end_of_base == 'l')
+       {
+         ++floating_point_l_count;
+         ++end_of_base;
+       }
+      /* This assertion is ensured by the pattern.  */
+      gdb_assert (floating_point_l_count == -1 || *end_of_base == 'f');
+      if (*end_of_base == 'f')
+       {
+         ++end_of_base;
+         ++floating_point_l_count;
+       }
+      /* This assertion is ensured by the pattern.  */
+      gdb_assert (*end_of_base == '#');
     }
 
   if (exp0 == NULL)
@@ -359,26 +416,62 @@ processInt (struct parser_state *par_state, const char *base0,
   else
     exp = strtol(exp0, (char **) NULL, 10);
 
-  errno = 0;
-  result = strtoulst (num0, &trailer, base);
-  if (errno == ERANGE)
-    error (_("Integer literal out of range"));
-  if (isxdigit(*trailer))
-    error (_("Invalid digit `%c' in based literal"), *trailer);
+  gdb_mpz result;
+  while (isxdigit (*num0))
+    {
+      int dig = fromhex (*num0);
+      if (dig >= base)
+       error (_("Invalid digit `%c' in based literal"), *num0);
+      mpz_mul_ui (result.val, result.val, base);
+      mpz_add_ui (result.val, result.val, dig);
+      ++num0;
+    }
 
   while (exp > 0)
     {
-      if (result > (ULONG_MAX / base))
-       error (_("Integer literal out of range"));
-      result *= base;
+      mpz_mul_ui (result.val, result.val, base);
       exp -= 1;
     }
 
-  if ((result >> (gdbarch_int_bit (par_state->gdbarch ())-1)) == 0)
+  if (floating_point_l_count > -1)
+    {
+      struct type *fp_type;
+      if (floating_point_l_count == 0)
+       fp_type = language_lookup_primitive_type (par_state->language (),
+                                                 par_state->gdbarch (),
+                                                 "float");
+      else if (floating_point_l_count == 1)
+       fp_type = language_lookup_primitive_type (par_state->language (),
+                                                 par_state->gdbarch (),
+                                                 "long_float");
+      else
+       {
+         /* This assertion is ensured by the pattern.  */
+         gdb_assert (floating_point_l_count == 2);
+         fp_type = language_lookup_primitive_type (par_state->language (),
+                                                   par_state->gdbarch (),
+                                                   "long_long_float");
+       }
+
+      yylval.typed_val_float.type = fp_type;
+      result.write (gdb::make_array_view (yylval.typed_val_float.val,
+                                         TYPE_LENGTH (fp_type)),
+                   type_byte_order (fp_type),
+                   true);
+
+      return FLOAT;
+    }
+
+  gdb_mpz maxval (ULONGEST_MAX);
+  if (mpz_cmp (result.val, maxval.val) > 0)
+    error (_("Integer literal out of range"));
+
+  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 ((result >> (gdbarch_long_bit (par_state->gdbarch ())-1)) == 0)
+  else if ((value >> (gdbarch_long_bit (par_state->gdbarch ())-1)) == 0)
     yylval.typed_val.type = type_long (par_state);
-  else if (((result >> (gdbarch_long_bit (par_state->gdbarch ())-1)) >> 1) == 0)
+  else if (((value >> (gdbarch_long_bit (par_state->gdbarch ())-1)) >> 1) == 0)
     {
       /* We have a number representable as an unsigned integer quantity.
          For consistency with the C treatment, we will treat it as an
@@ -389,18 +482,18 @@ processInt (struct parser_state *par_state, const char *base0,
        */
       yylval.typed_val.type
        = builtin_type (par_state->gdbarch ())->builtin_unsigned_long;
-      if (result & LONGEST_SIGN)
+      if (value & LONGEST_SIGN)
        yylval.typed_val.val =
-         (LONGEST) (result & ~LONGEST_SIGN)
+         (LONGEST) (value & ~LONGEST_SIGN)
          - (LONGEST_SIGN>>1) - (LONGEST_SIGN>>1);
       else
-       yylval.typed_val.val = (LONGEST) result;
+       yylval.typed_val.val = (LONGEST) value;
       return INT;
     }
   else
     yylval.typed_val.type = type_long_long (par_state);
 
-  yylval.typed_val.val = (LONGEST) result;
+  yylval.typed_val.val = value;
   return INT;
 }
 
@@ -451,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';
 
@@ -511,10 +604,12 @@ processString (const char *text, int len)
             }
            else
             {
-               int chr;
-              sscanf (p+2, "%2x", &chr);
+              const char *end;
+              ULONGEST chr = strtoulst (p + 2, &end, 16);
+              if (chr > 0xff)
+                error (_("wide strings are not yet supported"));
               *q = (char) chr;
-              p += 5;
+              p = end + 1;
             }
          }
        else
@@ -588,7 +683,6 @@ attributes[] = {
   { "size", TICK_SIZE },
   { "tag", TICK_TAG },
   { "val", TICK_VAL },
-  { NULL, -1 }
 };
 
 /* Return the syntactic code corresponding to the attribute name or
@@ -597,24 +691,52 @@ attributes[] = {
 static int
 processAttribute (const char *str)
 {
-  int i, k;
+  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 (i = 0; attributes[i].code != -1; i += 1)
-    if (strcasecmp (str, attributes[i].name) == 0)
-      return attributes[i].code;
+  for (const auto &item : attributes)
+    if (strcasecmp (str, item.name) == 0)
+      return item.code;
 
-  for (i = 0, k = -1; attributes[i].code != -1; i += 1)
-    if (subseqMatch (str, attributes[i].name))
+  gdb::optional<int> found;
+  for (const auto &item : attributes)
+    if (subseqMatch (str, item.name))
       {
-       if (k == -1)
-         k = i;
+       if (!found.has_value ())
+         found = item.code;
        else
          error (_("ambiguous attribute name: `%s'"), str);
       }
-  if (k == -1)
+  if (!found.has_value ())
     error (_("unrecognized attribute: `%s'"), str);
 
-  return attributes[k].code;
+  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