diff options
-rw-r--r-- | gdb/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/f-exp.y | 103 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/testsuite/gdb.fortran/dot-ops.exp | 123 |
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 +} + |