aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog11
-rw-r--r--gdb/f-exp.y103
-rw-r--r--gdb/testsuite/ChangeLog4
-rw-r--r--gdb/testsuite/gdb.fortran/dot-ops.exp123
4 files changed, 189 insertions, 52 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 25a2280..61c5663 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,16 @@
2019-03-06 Andrew Burgess <andrew.burgess@embecosm.com>
+ * f-exp.y (struct token): Add comments.
+ (dot_ops): Remove uppercase versions and the end marker.
+ (f77_keywords): Likewise.
+ (yylex): Use ARRAY_SIZE to iterate over dot_ops, assert all
+ entries in the dot_ops array are case insensitive, and use
+ strncasecmp to compare strings. Also some whitespace cleanup in
+ this area. Similar for the f77_keywords array, except entries in
+ this list might be case sensitive.
+
+2019-03-06 Andrew Burgess <andrew.burgess@embecosm.com>
+
* f-exp.y (struct f77_boolean_val): Add comments.
(boolean_values): Remove uppercase versions, and end marker.
(yylex): Use ARRAY_SIZE for iterating over boolean_values array,
diff --git a/gdb/f-exp.y b/gdb/f-exp.y
index 704585e..5e98094 100644
--- a/gdb/f-exp.y
+++ b/gdb/f-exp.y
@@ -775,36 +775,33 @@ parse_number (struct parser_state *par_state,
struct token
{
+ /* The string to match against. */
const char *oper;
+
+ /* The lexer token to return. */
int token;
+
+ /* The expression opcode to embed within the token. */
enum exp_opcode opcode;
+
+ /* When this is true the string in OPER is matched exactly including
+ case, when this is false OPER is matched case insensitively. */
+ bool case_sensitive;
};
static const struct token dot_ops[] =
{
- { ".and.", BOOL_AND, BINOP_END },
- { ".AND.", BOOL_AND, BINOP_END },
- { ".or.", BOOL_OR, BINOP_END },
- { ".OR.", BOOL_OR, BINOP_END },
- { ".not.", BOOL_NOT, BINOP_END },
- { ".NOT.", BOOL_NOT, BINOP_END },
- { ".eq.", EQUAL, BINOP_END },
- { ".EQ.", EQUAL, BINOP_END },
- { ".eqv.", EQUAL, BINOP_END },
- { ".NEQV.", NOTEQUAL, BINOP_END },
- { ".neqv.", NOTEQUAL, BINOP_END },
- { ".EQV.", EQUAL, BINOP_END },
- { ".ne.", NOTEQUAL, BINOP_END },
- { ".NE.", NOTEQUAL, BINOP_END },
- { ".le.", LEQ, BINOP_END },
- { ".LE.", LEQ, BINOP_END },
- { ".ge.", GEQ, BINOP_END },
- { ".GE.", GEQ, BINOP_END },
- { ".gt.", GREATERTHAN, BINOP_END },
- { ".GT.", GREATERTHAN, BINOP_END },
- { ".lt.", LESSTHAN, BINOP_END },
- { ".LT.", LESSTHAN, BINOP_END },
- { NULL, 0, BINOP_END }
+ { ".and.", BOOL_AND, BINOP_END, false },
+ { ".or.", BOOL_OR, BINOP_END, false },
+ { ".not.", BOOL_NOT, BINOP_END, false },
+ { ".eq.", EQUAL, BINOP_END, false },
+ { ".eqv.", EQUAL, BINOP_END, false },
+ { ".neqv.", NOTEQUAL, BINOP_END, false },
+ { ".ne.", NOTEQUAL, BINOP_END, false },
+ { ".le.", LEQ, BINOP_END, false },
+ { ".ge.", GEQ, BINOP_END, false },
+ { ".gt.", GREATERTHAN, BINOP_END, false },
+ { ".lt.", LESSTHAN, BINOP_END, false },
};
/* Holds the Fortran representation of a boolean, and the integer value we
@@ -825,25 +822,25 @@ static const struct f77_boolean_val boolean_values[] =
{ ".false.", 0 }
};
-static const struct token f77_keywords[] =
+static const struct token f77_keywords[] =
{
- { "complex_16", COMPLEX_S16_KEYWORD, BINOP_END },
- { "complex_32", COMPLEX_S32_KEYWORD, BINOP_END },
- { "character", CHARACTER, BINOP_END },
- { "integer_2", INT_S2_KEYWORD, BINOP_END },
- { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END },
- { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END },
- { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END },
- { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END },
- { "integer", INT_KEYWORD, BINOP_END },
- { "logical", LOGICAL_KEYWORD, BINOP_END },
- { "real_16", REAL_S16_KEYWORD, BINOP_END },
- { "complex", COMPLEX_S8_KEYWORD, BINOP_END },
- { "sizeof", SIZEOF, BINOP_END },
- { "real_8", REAL_S8_KEYWORD, BINOP_END },
- { "real", REAL_KEYWORD, BINOP_END },
- { NULL, 0, BINOP_END }
-};
+ /* Historically these have always been lowercase only in GDB. */
+ { "complex_16", COMPLEX_S16_KEYWORD, BINOP_END, true },
+ { "complex_32", COMPLEX_S32_KEYWORD, BINOP_END, true },
+ { "character", CHARACTER, BINOP_END, true },
+ { "integer_2", INT_S2_KEYWORD, BINOP_END, true },
+ { "logical_1", LOGICAL_S1_KEYWORD, BINOP_END, true },
+ { "logical_2", LOGICAL_S2_KEYWORD, BINOP_END, true },
+ { "logical_8", LOGICAL_S8_KEYWORD, BINOP_END, true },
+ { "complex_8", COMPLEX_S8_KEYWORD, BINOP_END, true },
+ { "integer", INT_KEYWORD, BINOP_END, true },
+ { "logical", LOGICAL_KEYWORD, BINOP_END, true },
+ { "real_16", REAL_S16_KEYWORD, BINOP_END, true },
+ { "complex", COMPLEX_S8_KEYWORD, BINOP_END, true },
+ { "sizeof", SIZEOF, BINOP_END, true },
+ { "real_8", REAL_S8_KEYWORD, BINOP_END, true },
+ { "real", REAL_KEYWORD, BINOP_END, true },
+};
/* Implementation of a dynamically expandable buffer for processing input
characters acquired through lexptr and building a value to return in
@@ -951,18 +948,18 @@ yylex (void)
}
}
}
-
+
/* See if it is a special .foo. operator. */
-
- for (int i = 0; dot_ops[i].oper != NULL; i++)
- if (strncmp (tokstart, dot_ops[i].oper,
- strlen (dot_ops[i].oper)) == 0)
+ for (int i = 0; i < ARRAY_SIZE (dot_ops); i++)
+ if (strncasecmp (tokstart, dot_ops[i].oper,
+ strlen (dot_ops[i].oper)) == 0)
{
+ gdb_assert (!dot_ops[i].case_sensitive);
lexptr += strlen (dot_ops[i].oper);
yylval.opcode = dot_ops[i].opcode;
return dot_ops[i].token;
}
-
+
/* See if it is an exponentiation operator. */
if (strncmp (tokstart, "**", 2) == 0)
@@ -1122,16 +1119,18 @@ yylex (void)
lexptr += namelen;
/* Catch specific keywords. */
-
- for (int i = 0; f77_keywords[i].oper != NULL; i++)
+
+ for (int i = 0; i < ARRAY_SIZE (f77_keywords); i++)
if (strlen (f77_keywords[i].oper) == namelen
- && strncmp (tokstart, f77_keywords[i].oper, namelen) == 0)
+ && ((!f77_keywords[i].case_sensitive
+ && strncasecmp (tokstart, f77_keywords[i].oper, namelen) == 0)
+ || (f77_keywords[i].case_sensitive
+ && strncmp (tokstart, f77_keywords[i].oper, namelen) == 0)))
{
- /* lexptr += strlen(f77_keywords[i].operator); */
yylval.opcode = f77_keywords[i].opcode;
return f77_keywords[i].token;
}
-
+
yylval.sval.ptr = tokstart;
yylval.sval.length = namelen;
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index e2e74a8..296f03d 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,5 +1,9 @@
2019-03-06 Andrew Burgess <andrew.burgess@embecosm.com>
+ * gdb.fortran/dot-ops.exp: New file.
+
+2019-03-06 Andrew Burgess <andrew.burgess@embecosm.com>
+
* gdb.fortran/types.exp (test_logical_literal_types_accepted):
Check upper and lower case logical literals.
diff --git a/gdb/testsuite/gdb.fortran/dot-ops.exp b/gdb/testsuite/gdb.fortran/dot-ops.exp
new file mode 100644
index 0000000..787471d
--- /dev/null
+++ b/gdb/testsuite/gdb.fortran/dot-ops.exp
@@ -0,0 +1,123 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file tests GDB's handling of some of the builtin logical and
+# arithmetic dot operators in Fortran, for example `.AND.` and `.LE.`.
+
+load_lib "fortran.exp"
+
+if { [skip_fortran_tests] } { continue }
+
+proc test_dot_operations {} {
+
+ foreach_with_prefix format { "uppercase" "lowercase" } {
+ if {$format == "uppercase"} {
+ set true ".TRUE."
+ set false ".FALSE."
+ set and ".AND."
+ set or ".OR."
+ set not ".NOT."
+ set eqv ".EQV."
+ set neqv ".NEQV."
+ set eq ".EQ."
+ set ne ".NE."
+ set le ".LE."
+ set ge ".GE."
+ set lt ".LT."
+ set gt ".GT."
+ } else {
+ set true ".true."
+ set false ".false."
+ set and ".and."
+ set or ".or."
+ set not ".not."
+ set eqv ".eqv."
+ set neqv ".neqv."
+ set eq ".eq."
+ set ne ".ne."
+ set le ".le."
+ set ge ".ge."
+ set lt ".lt."
+ set gt ".gt."
+ }
+
+ # Logical AND
+ gdb_test "p $true $and $true" " = .TRUE."
+ gdb_test "p $true $and $false" " = .FALSE."
+ gdb_test "p $false $and $true" " = .FALSE."
+ gdb_test "p $false $and $false" " = .FALSE."
+
+ # Logical OR
+ gdb_test "p $true $or $true" " = .TRUE."
+ gdb_test "p $true $or $false" " = .TRUE."
+ gdb_test "p $false $or $true" " = .TRUE."
+ gdb_test "p $false $or $false" " = .FALSE."
+
+ # Logical NOT
+ gdb_test "p $not $true" " = .FALSE."
+ gdb_test "p $not $false" " = .TRUE."
+
+ # Logical EQV
+ gdb_test "p $true $eqv $true" " = .TRUE."
+ gdb_test "p $true $eqv $false" " = .FALSE."
+ gdb_test "p $false $eqv $true" " = .FALSE."
+ gdb_test "p $false $eqv $false" " = .TRUE."
+
+ # Logical NEQV
+ gdb_test "p $true $neqv $true" " = .FALSE."
+ gdb_test "p $true $neqv $false" " = .TRUE."
+ gdb_test "p $false $neqv $true" " = .TRUE."
+ gdb_test "p $false $neqv $false" " = .FALSE."
+
+ # Arithmetic EQ
+ gdb_test "p 5 $eq 4" " = .FALSE."
+ gdb_test "p 4 $eq 4" " = .TRUE."
+
+ # Arithmetic NE
+ gdb_test "p 5 $ne 4" " = .TRUE."
+ gdb_test "p 4 $ne 4" " = .FALSE."
+
+ # Arithmetic LE
+ gdb_test "p 5 $le 4" " = .FALSE."
+ gdb_test "p 4 $le 4" " = .TRUE."
+ gdb_test "p 3 $le 4" " = .TRUE."
+
+ # Arithmetic LT
+ gdb_test "p 5 $lt 4" " = .FALSE."
+ gdb_test "p 4 $lt 4" " = .FALSE."
+ gdb_test "p 3 $lt 4" " = .TRUE."
+
+ # Arithmetic GE
+ gdb_test "p 5 $ge 4" " = .TRUE."
+ gdb_test "p 4 $ge 4" " = .TRUE."
+ gdb_test "p 3 $ge 4" " = .FALSE."
+
+ # Arithmetic GT
+ gdb_test "p 5 $gt 4" " = .TRUE."
+ gdb_test "p 4 $gt 4" " = .FALSE."
+ gdb_test "p 3 $gt 4" " = .FALSE."
+ }
+}
+
+# Start of test script.
+
+clean_restart
+
+if [set_lang_fortran] then {
+ test_dot_operations
+} else {
+ warning "$test_name tests suppressed." 0
+}
+