From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id SdXRCw37mmrw5CgAWB0awg (envelope-from ) for ; Fri, 04 Sep 2026 13:08:29 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=D+oLrBXg; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 2886D1E166; Fri, 04 Sep 2026 13:08:29 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 2D7881E033 for ; Fri, 04 Sep 2026 13:08:27 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id A9E0E4BB58BB for ; Fri, 4 Sep 2026 17:08:26 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A9E0E4BB58BB Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=D+oLrBXg Received: from smtp.polymtl.ca (smtp.polymtl.ca [132.207.4.11]) by sourceware.org (Postfix) with ESMTPS id 7BA3E4BA2E0A for ; Fri, 4 Sep 2026 17:07:58 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 7BA3E4BA2E0A Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=polymtl.ca Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=polymtl.ca ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 7BA3E4BA2E0A Authentication-Results: sourceware.org; arc=none smtp.remote-ip=132.207.4.11 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788541678; cv=none; b=f8S6013u6UxbsvWO/s4gahe81nLb8NIGIlkg4SSMQMfBWFvgOARWlqz1cRcDzDKmbDS5SZ+a9VAMUrpwD7uu5VPm9pIBPTLBzxPVWnr7aEAkpmKZm71CojE0V6kw9ZgRqXNggfvwo6NDo+JmgjtZycy6vr3OCemmpdclSyo/WHw= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1788541678; c=relaxed/simple; bh=FYrCAcPh2qd0sWKekrVnSZFz9BuTundP8SCMfVDUhMg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=oIcU5luS2EjBQgsjhzchr45jUEfkAjuS8ExhI3+suIltdiuroSJl0+AmoYPbf6PtozwG4m3Ejc2rOzwK1olcM/pzpr7mtjPOGOnpR0bRgTaUSfxDuV7f6rw0bkvHVSwry02EVgMloAUjeLL/NdpWOb/luh3QJi2iITWydhZ1J9M= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=polymtl.ca header.i=@polymtl.ca header.a=rsa-sha256 header.s=oct2025 header.b=D+oLrBXg DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7BA3E4BA2E0A Received: from simark.ca (simark.ca [158.69.221.121]) (authenticated bits=0) by smtp.polymtl.ca (8.14.7/8.14.7) with ESMTP id 684H7qtQ143233 (version=TLSv1/SSLv3 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Fri, 4 Sep 2026 13:07:57 -0400 DKIM-Filter: OpenDKIM Filter v2.11.0 smtp.polymtl.ca 684H7qtQ143233 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=polymtl.ca; s=oct2025; t=1788541677; bh=4+jUD0dMJt6Vg/KU7lPLPDyv1C8WnBSF2fu6Salvk6U=; h=From:To:Cc:Subject:Date:In-Reply-To:From; b=D+oLrBXgCnycwR6rGN+hAs3nrt1QQtPa1v9FFdS5RF9QQBuYreKbFiivQGgHENnm6 pV7nJLecnQfh6nMgwzWZHcLUAgahILxLCME3uTLsU0WwMRgXfrMmfVbvLF/nG8tyBx siGrN1PfW0j1fWFCpPRAcda5l5Jvy329X19i7LuUkBawIfNOg16POZao2WWw4Gbo4E TTEm3r/fVT8sqXdfHTBvyvaUqZmra3jQnEN+qvF9zmL1Ct9Hd9qiMJsyeB4QvgV6XU PDFjoYY8UROvl8vcZdz7jo50vikOKDE+TYNHJCr7s3AQ4v5biY6psbJFMleh3f1WOu l17mmzfE7Tvog== Received: by simark.ca (Postfix) id 41C391E033; Fri, 04 Sep 2026 13:07:52 -0400 (EDT) From: simon.marchi@polymtl.ca To: gdb-patches@sourceware.org Cc: Simon Marchi Subject: [PATCH 16/17] gdb: move m2-exp-parser.y's support code to m2-exp-parser.c Date: Fri, 4 Sep 2026 12:56:48 -0400 Message-ID: <20260904170338.1643894-17-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260904170338.1643894-1-simon.marchi@polymtl.ca> References: <20260904170338.1643894-1-simon.marchi@polymtl.ca> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Poly-FromMTA: (simark.ca [158.69.221.121]) at Fri, 4 Sep 2026 17:07:52 +0000 X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org From: Simon Marchi Similar to the previous commits, but for the Modula-2 expression parser. Like the Fortran parser, the Modula-2 parser is entered through the m2_language::parser method rather than a free function, so add a free function m2_parse as the entry point (like the other parsers) and turn m2_language::parser into a thin wrapper around it, defined in m2-lang.c. Put the parser support code inside the m2_exp_parser namespace. Change-Id: I92669a1af7fb81cf59bfb41e2b8c63ce323652d2 --- gdb/Makefile.in | 2 + gdb/m2-exp-parser.c | 488 ++++++++++++++++++++++++++++++++++++++++++++ gdb/m2-exp-parser.h | 67 ++++++ gdb/m2-exp-parser.y | 465 +---------------------------------------- gdb/m2-lang.c | 9 + 5 files changed, 568 insertions(+), 463 deletions(-) create mode 100644 gdb/m2-exp-parser.c create mode 100644 gdb/m2-exp-parser.h diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 4289c5151fd0..1c4ba5a12d57 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -1137,6 +1137,7 @@ COMMON_SFILES = \ language.c \ linespec.c \ location.c \ + m2-exp-parser.c \ m2-lang.c \ m2-typeprint.c \ m2-valprint.c \ @@ -1518,6 +1519,7 @@ HFILES_NO_SRCDIR = \ linux-tdep.h \ location.h \ loongarch-tdep.h \ + m2-exp-parser.h \ m2-exp.h \ m2-lang.h \ m32r-tdep.h \ diff --git a/gdb/m2-exp-parser.c b/gdb/m2-exp-parser.c new file mode 100644 index 000000000000..821f1507aef3 --- /dev/null +++ b/gdb/m2-exp-parser.c @@ -0,0 +1,488 @@ +/* YACC parser support code for Modula-2 expressions, for GDB. + + Copyright (C) 1986-2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +#include "m2-exp-parser.h" +#include "m2-exp-parser-gen.h" +#include "block.h" +#include "expression.h" +#include "language.h" +#include "m2-exp.h" +#include "parser-defs.h" +#include "value.h" + +/* The entry point of the bison/yacc-generated parser, defined in + m2-exp-parser-gen.c. Bison produces a declaration for m2_yyparse in + m2-exp-parser-gen.h, but byacc does not, hence this declaration. */ + +int m2_yyparse (); + +/* Likewise, byacc does not produce a declaration for m2_yydebug. */ + +extern int m2_yydebug; + +namespace m2_exp_parser +{ + +/* See m2-exp-parser.h. */ + +parser_state *pstate; + +/* See m2-exp-parser.h. */ + +int number_sign = 1; + +/* Take care of parsing a number (anything that starts with a digit). + Set yylval and return the token type; update lexptr. + LEN is the number of characters in it. */ + +/*** Needs some error checking for the float case ***/ + +static int +parse_number (int olen) +{ + const char *p = pstate->lexptr; + ULONGEST n = 0; + ULONGEST prevn = 0; + int c,i,ischar=0; + int base = input_radix; + int len = olen; + + if(p[len-1] == 'H') + { + base = 16; + len--; + } + else if(p[len-1] == 'C' || p[len-1] == 'B') + { + base = 8; + ischar = p[len-1] == 'C'; + len--; + } + + /* Scan the number */ + for (c = 0; c < len; c++) + { + if (p[c] == '.' && base == 10) + { + /* It's a float since it contains a point. */ + if (!parse_float (p, len, + parse_m2_type (pstate)->builtin_real, + m2_yylval.val)) + return ERROR; + + pstate->lexptr += len; + return FLOAT; + } + if (p[c] == '.' && base != 10) + error (_("Floating point numbers must be base 10.")); + if (base == 10 && (p[c] < '0' || p[c] > '9')) + error (_("Invalid digit \'%c\' in number."),p[c]); + } + + while (len-- > 0) + { + c = *p++; + n *= base; + if( base == 8 && (c == '8' || c == '9')) + error (_("Invalid digit \'%c\' in octal number."),c); + if (c >= '0' && c <= '9') + i = c - '0'; + else + { + if (base == 16 && c >= 'A' && c <= 'F') + i = c - 'A' + 10; + else + return ERROR; + } + n+=i; + if(i >= base) + return ERROR; + if (n == 0 && prevn == 0) + ; + else if (RANGE_CHECK && prevn >= n) + range_error (_("Overflow on numeric constant.")); + + prevn=n; + } + + pstate->lexptr = p; + if(*p == 'B' || *p == 'C' || *p == 'H') + pstate->lexptr++; /* Advance past B,C or H */ + + if (ischar) + { + m2_yylval.ulval = n; + return CHAR; + } + + int int_bits = gdbarch_int_bit (pstate->gdbarch ()); + bool have_signed = number_sign == -1; + bool have_unsigned = number_sign == 1; + if (have_signed && fits_in_type (number_sign, n, int_bits, true)) + { + m2_yylval.lval = n; + return INT; + } + else if (have_unsigned && fits_in_type (number_sign, n, int_bits, false)) + { + m2_yylval.ulval = n; + return UINT; + } + else + error (_("Overflow on numeric constant.")); +} + +/* Some tokens */ + +static struct +{ + char name[2]; + int token; +} tokentab2[] = +{ + { {'<', '>'}, NOTEQUAL }, + { {':', '='}, ASSIGN }, + { {'<', '='}, LEQ }, + { {'>', '='}, GEQ }, + { {':', ':'}, COLONCOLON }, + +}; + +/* Some specific keywords */ + +struct keyword { + char keyw[10]; + int token; +}; + +static struct keyword keytab[] = +{ + {"OR" , OROR }, + {"IN", IN },/* Note space after IN */ + {"AND", LOGICAL_AND}, + {"ABS", ABS }, + {"ADR", ADR }, + {"CHR", CHR }, + {"DEC", DEC }, + {"NOT", NOT }, + {"DIV", DIV }, + {"INC", INC }, + {"MAX", MAX_FUNC }, + {"MIN", MIN_FUNC }, + {"MOD", MOD }, + {"ODD", ODD }, + {"CAP", CAP }, + {"ORD", ORD }, + {"VAL", VAL }, + {"EXCL", EXCL }, + {"HIGH", HIGH }, + {"INCL", INCL }, + {"SIZE", SIZE }, + {"FLOAT", FLOAT_FUNC }, + {"TRUNC", TRUNC }, + {"TSIZE", SIZE }, +}; + +/* Depth of parentheses. */ +static int paren_depth; + +/* See m2-exp-parser.h. */ + +int +m2_yylex (void) +{ + int c; + int namelen; + int i; + const char *tokstart; + char quote; + + retry: + + pstate->prev_lexptr = pstate->lexptr; + + tokstart = pstate->lexptr; + + + /* See if it is a special token of length 2 */ + for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++) + if (strncmp (tokentab2[i].name, tokstart, 2) == 0) + { + pstate->lexptr += 2; + return tokentab2[i].token; + } + + switch (c = *tokstart) + { + case 0: + return 0; + + case ' ': + case '\t': + case '\n': + pstate->lexptr++; + goto retry; + + case '(': + paren_depth++; + pstate->lexptr++; + return c; + + case ')': + if (paren_depth == 0) + return 0; + paren_depth--; + pstate->lexptr++; + return c; + + case ',': + if (pstate->comma_terminates && paren_depth == 0) + return 0; + pstate->lexptr++; + return c; + + case '.': + /* Might be a floating point number. */ + if (pstate->lexptr[1] >= '0' && pstate->lexptr[1] <= '9') + break; /* Falls into number code. */ + else + { + pstate->lexptr++; + return DOT; + } + +/* These are character tokens that appear as-is in the YACC grammar */ + case '+': + case '-': + case '*': + case '/': + case '^': + case '<': + case '>': + case '[': + case ']': + case '=': + case '{': + case '}': + case '#': + case '@': + case '~': + case '&': + pstate->lexptr++; + return c; + + case '\'' : + case '"': + quote = c; + for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) + if (c == '\\') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + { + c = tokstart[++namelen]; + if (c >= '0' && c <= '9') + c = tokstart[++namelen]; + } + } + if(c != quote) + error (_("Unterminated string or character constant.")); + m2_yylval.sval.ptr = tokstart + 1; + m2_yylval.sval.length = namelen - 1; + pstate->lexptr += namelen + 1; + + if(namelen == 2) /* Single character */ + { + m2_yylval.ulval = tokstart[1]; + return CHAR; + } + else + return STRING; + } + + /* Is it a number? */ + /* Note: We have already dealt with the case of the token '.'. + See case '.' above. */ + if ((c >= '0' && c <= '9')) + { + /* It's a number. */ + int got_dot = 0, got_e = 0; + const char *p = tokstart; + int toktype; + + for (++p ;; ++p) + { + if (!got_e && (*p == 'e' || *p == 'E')) + got_dot = got_e = 1; + else if (!got_dot && *p == '.') + got_dot = 1; + else if (got_e && (p[-1] == 'e' || p[-1] == 'E') + && (*p == '-' || *p == '+')) + /* This is the sign of the exponent, not the end of the + number. */ + continue; + else if ((*p < '0' || *p > '9') && + (*p < 'A' || *p > 'F') && + (*p != 'H')) /* Modula-2 hexadecimal number */ + break; + } + toktype = parse_number (p - tokstart); + if (toktype == ERROR) + error (_("Invalid number \"%.*s\"."), (int) (p - tokstart), + tokstart); + pstate->lexptr = p; + return toktype; + } + + if (!(c == '_' || c == '$' + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) + /* We must have come across a bad character (e.g. ';'). */ + error (_("Invalid character '%c' in expression."), c); + + /* It's a name. See how long it is. */ + namelen = 0; + for (c = tokstart[namelen]; + (c == '_' || c == '$' || (c >= '0' && c <= '9') + || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); + c = tokstart[++namelen]) + ; + + /* The token "if" terminates the expression and is NOT + removed from the input stream. */ + if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') + { + return 0; + } + + pstate->lexptr += namelen; + + /* Lookup special keywords */ + for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++) + if (namelen == strlen (keytab[i].keyw) + && strncmp (tokstart, keytab[i].keyw, namelen) == 0) + return keytab[i].token; + + m2_yylval.sval.ptr = tokstart; + m2_yylval.sval.length = namelen; + + if (*tokstart == '$') + return DOLLAR_VARIABLE; + + /* Use token-type BLOCKNAME for symbols that happen to be defined as + functions. If this is not so, then ... + Use token-type TYPENAME for symbols that happen to be defined + currently as names of types; NAME for other symbols. + The caller is not constrained to care about the distinction. */ + { + std::string tmp = copy_name (m2_yylval.sval); + struct symbol *sym; + + if (lookup_symtab (current_program_space, tmp.c_str ()) != nullptr) + return BLOCKNAME; + + sym = lookup_symbol (tmp.c_str (), pstate->expression_context_block, + SEARCH_VFT, 0).symbol; + if (sym && sym->loc_class () == LOC_BLOCK) + return BLOCKNAME; + if (lookup_typename (pstate->language (), + tmp.c_str (), pstate->expression_context_block, 1)) + return TYPENAME; + + if(sym) + { + switch(sym->loc_class ()) + { + case LOC_STATIC: + case LOC_REGISTER: + case LOC_ARG: + case LOC_REF_ARG: + case LOC_REGPARM_ADDR: + case LOC_LOCAL: + case LOC_CONST: + case LOC_CONST_BYTES: + case LOC_OPTIMIZED_OUT: + case LOC_COMPUTED: + return NAME; + + case LOC_TYPEDEF: + return TYPENAME; + + case LOC_BLOCK: + return BLOCKNAME; + + case LOC_UNDEF: + error (_("internal: Undefined class in m2lex()")); + + case LOC_LABEL: + case LOC_UNRESOLVED: + error (_("internal: Unforeseen case in m2lex()")); + + default: + error (_("unhandled token in m2lex()")); + break; + } + } + else + { + /* Built-in BOOLEAN type. This is sort of a hack. */ + if (startswith (tokstart, "TRUE")) + { + m2_yylval.ulval = 1; + return M2_TRUE; + } + else if (startswith (tokstart, "FALSE")) + { + m2_yylval.ulval = 0; + return M2_FALSE; + } + } + + /* Must be another type of name... */ + return NAME; + } +} + +/* See m2-exp-parser.h. */ + +void +m2_yyerror (const char *msg) +{ + pstate->parse_error (msg); +} + +} /* namespace m2_exp_parser */ + +/* See m2-exp-parser.h. */ + +int +m2_parse (struct parser_state *par_state) +{ + using namespace m2_exp_parser; + + /* Setting up the parser state. */ + scoped_restore pstate_restore = make_scoped_restore (&pstate); + gdb_assert (par_state != NULL); + pstate = par_state; + paren_depth = 0; + + int result = m2_yyparse (); + if (!result) + pstate->set_operation (pstate->pop ()); + return result; +} diff --git a/gdb/m2-exp-parser.h b/gdb/m2-exp-parser.h new file mode 100644 index 000000000000..bea7155188fb --- /dev/null +++ b/gdb/m2-exp-parser.h @@ -0,0 +1,67 @@ +/* YACC parser support code for Modula-2 expressions, for GDB. + + Copyright (C) 1986-2026 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +#ifndef GDB_M2_EXP_PARSER_H +#define GDB_M2_EXP_PARSER_H + +#include "parser-defs.h" +#include "m2-lang.h" + +union m2_exp_parser_YYSTYPE; + +namespace m2_exp_parser { + +/* The state of the parser, used internally when we are parsing the + expression. */ + +extern parser_state *pstate; + +/* The sign of the number being parsed. */ + +extern int number_sign; + +/* Return the Modula-2 type table for the architecture associated to PS. */ + +static inline const struct builtin_m2_type * +parse_m2_type (parser_state *ps) +{ + return builtin_m2_type (ps->gdbarch ()); +} + +/* Read one token, getting characters through lexptr. */ + +/* This is where we will check to make sure that the language and the + operators used are compatible */ + +int m2_yylex (); + +/* The error handler invoked by the generated parser. Report MSG as a + parse error on the current parser state. */ + +void m2_yyerror (const char *msg); + +} /* namespace m2_exp_parser */ + +/* Parse a Modula-2 expression using the lexer input and context held in + PAR_STATE. On success, return 0 and leave the resulting operation set + on PAR_STATE. On failure, return non-zero. */ + +int m2_parse (struct parser_state *par_state); + +#endif /* GDB_M2_EXP_PARSER_H */ diff --git a/gdb/m2-exp-parser.y b/gdb/m2-exp-parser.y index 0f1c62c7ae52..a10087fa03ab 100644 --- a/gdb/m2-exp-parser.y +++ b/gdb/m2-exp-parser.y @@ -42,33 +42,11 @@ #include "value.h" #include "parser-defs.h" #include "m2-lang.h" +#include "m2-exp-parser.h" #include "block.h" #include "m2-exp.h" -/* The state of the parser, used internally when we are parsing the - expression. */ - -static struct parser_state *pstate = NULL; - -int yyparse (void); - -static int yylex (void); - -static void yyerror (const char *); - -static int parse_number (int); - -/* The sign of the number being parsed. */ -static int number_sign = 1; - -/* Return the Modula-2 type table for the architecture associated to PS. */ - -static inline const struct builtin_m2_type * -parse_m2_type (parser_state *ps) -{ - return builtin_m2_type (ps->gdbarch ()); -} - +using namespace m2_exp_parser; using namespace expr; %} @@ -569,442 +547,3 @@ type } ; - -%% - -/* Take care of parsing a number (anything that starts with a digit). - Set yylval and return the token type; update lexptr. - LEN is the number of characters in it. */ - -/*** Needs some error checking for the float case ***/ - -static int -parse_number (int olen) -{ - const char *p = pstate->lexptr; - ULONGEST n = 0; - ULONGEST prevn = 0; - int c,i,ischar=0; - int base = input_radix; - int len = olen; - - if(p[len-1] == 'H') - { - base = 16; - len--; - } - else if(p[len-1] == 'C' || p[len-1] == 'B') - { - base = 8; - ischar = p[len-1] == 'C'; - len--; - } - - /* Scan the number */ - for (c = 0; c < len; c++) - { - if (p[c] == '.' && base == 10) - { - /* It's a float since it contains a point. */ - if (!parse_float (p, len, - parse_m2_type (pstate)->builtin_real, - yylval.val)) - return ERROR; - - pstate->lexptr += len; - return FLOAT; - } - if (p[c] == '.' && base != 10) - error (_("Floating point numbers must be base 10.")); - if (base == 10 && (p[c] < '0' || p[c] > '9')) - error (_("Invalid digit \'%c\' in number."),p[c]); - } - - while (len-- > 0) - { - c = *p++; - n *= base; - if( base == 8 && (c == '8' || c == '9')) - error (_("Invalid digit \'%c\' in octal number."),c); - if (c >= '0' && c <= '9') - i = c - '0'; - else - { - if (base == 16 && c >= 'A' && c <= 'F') - i = c - 'A' + 10; - else - return ERROR; - } - n+=i; - if(i >= base) - return ERROR; - if (n == 0 && prevn == 0) - ; - else if (RANGE_CHECK && prevn >= n) - range_error (_("Overflow on numeric constant.")); - - prevn=n; - } - - pstate->lexptr = p; - if(*p == 'B' || *p == 'C' || *p == 'H') - pstate->lexptr++; /* Advance past B,C or H */ - - if (ischar) - { - yylval.ulval = n; - return CHAR; - } - - int int_bits = gdbarch_int_bit (pstate->gdbarch ()); - bool have_signed = number_sign == -1; - bool have_unsigned = number_sign == 1; - if (have_signed && fits_in_type (number_sign, n, int_bits, true)) - { - yylval.lval = n; - return INT; - } - else if (have_unsigned && fits_in_type (number_sign, n, int_bits, false)) - { - yylval.ulval = n; - return UINT; - } - else - error (_("Overflow on numeric constant.")); -} - - -/* Some tokens */ - -static struct -{ - char name[2]; - int token; -} tokentab2[] = -{ - { {'<', '>'}, NOTEQUAL }, - { {':', '='}, ASSIGN }, - { {'<', '='}, LEQ }, - { {'>', '='}, GEQ }, - { {':', ':'}, COLONCOLON }, - -}; - -/* Some specific keywords */ - -struct keyword { - char keyw[10]; - int token; -}; - -static struct keyword keytab[] = -{ - {"OR" , OROR }, - {"IN", IN },/* Note space after IN */ - {"AND", LOGICAL_AND}, - {"ABS", ABS }, - {"ADR", ADR }, - {"CHR", CHR }, - {"DEC", DEC }, - {"NOT", NOT }, - {"DIV", DIV }, - {"INC", INC }, - {"MAX", MAX_FUNC }, - {"MIN", MIN_FUNC }, - {"MOD", MOD }, - {"ODD", ODD }, - {"CAP", CAP }, - {"ORD", ORD }, - {"VAL", VAL }, - {"EXCL", EXCL }, - {"HIGH", HIGH }, - {"INCL", INCL }, - {"SIZE", SIZE }, - {"FLOAT", FLOAT_FUNC }, - {"TRUNC", TRUNC }, - {"TSIZE", SIZE }, -}; - - -/* Depth of parentheses. */ -static int paren_depth; - -/* Read one token, getting characters through lexptr. */ - -/* This is where we will check to make sure that the language and the - operators used are compatible */ - -static int -yylex (void) -{ - int c; - int namelen; - int i; - const char *tokstart; - char quote; - - retry: - - pstate->prev_lexptr = pstate->lexptr; - - tokstart = pstate->lexptr; - - - /* See if it is a special token of length 2 */ - for( i = 0 ; i < (int) (sizeof tokentab2 / sizeof tokentab2[0]) ; i++) - if (strncmp (tokentab2[i].name, tokstart, 2) == 0) - { - pstate->lexptr += 2; - return tokentab2[i].token; - } - - switch (c = *tokstart) - { - case 0: - return 0; - - case ' ': - case '\t': - case '\n': - pstate->lexptr++; - goto retry; - - case '(': - paren_depth++; - pstate->lexptr++; - return c; - - case ')': - if (paren_depth == 0) - return 0; - paren_depth--; - pstate->lexptr++; - return c; - - case ',': - if (pstate->comma_terminates && paren_depth == 0) - return 0; - pstate->lexptr++; - return c; - - case '.': - /* Might be a floating point number. */ - if (pstate->lexptr[1] >= '0' && pstate->lexptr[1] <= '9') - break; /* Falls into number code. */ - else - { - pstate->lexptr++; - return DOT; - } - -/* These are character tokens that appear as-is in the YACC grammar */ - case '+': - case '-': - case '*': - case '/': - case '^': - case '<': - case '>': - case '[': - case ']': - case '=': - case '{': - case '}': - case '#': - case '@': - case '~': - case '&': - pstate->lexptr++; - return c; - - case '\'' : - case '"': - quote = c; - for (namelen = 1; (c = tokstart[namelen]) != quote && c != '\0'; namelen++) - if (c == '\\') - { - c = tokstart[++namelen]; - if (c >= '0' && c <= '9') - { - c = tokstart[++namelen]; - if (c >= '0' && c <= '9') - c = tokstart[++namelen]; - } - } - if(c != quote) - error (_("Unterminated string or character constant.")); - yylval.sval.ptr = tokstart + 1; - yylval.sval.length = namelen - 1; - pstate->lexptr += namelen + 1; - - if(namelen == 2) /* Single character */ - { - yylval.ulval = tokstart[1]; - return CHAR; - } - else - return STRING; - } - - /* Is it a number? */ - /* Note: We have already dealt with the case of the token '.'. - See case '.' above. */ - if ((c >= '0' && c <= '9')) - { - /* It's a number. */ - int got_dot = 0, got_e = 0; - const char *p = tokstart; - int toktype; - - for (++p ;; ++p) - { - if (!got_e && (*p == 'e' || *p == 'E')) - got_dot = got_e = 1; - else if (!got_dot && *p == '.') - got_dot = 1; - else if (got_e && (p[-1] == 'e' || p[-1] == 'E') - && (*p == '-' || *p == '+')) - /* This is the sign of the exponent, not the end of the - number. */ - continue; - else if ((*p < '0' || *p > '9') && - (*p < 'A' || *p > 'F') && - (*p != 'H')) /* Modula-2 hexadecimal number */ - break; - } - toktype = parse_number (p - tokstart); - if (toktype == ERROR) - error (_("Invalid number \"%.*s\"."), (int) (p - tokstart), - tokstart); - pstate->lexptr = p; - return toktype; - } - - if (!(c == '_' || c == '$' - || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))) - /* We must have come across a bad character (e.g. ';'). */ - error (_("Invalid character '%c' in expression."), c); - - /* It's a name. See how long it is. */ - namelen = 0; - for (c = tokstart[namelen]; - (c == '_' || c == '$' || (c >= '0' && c <= '9') - || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')); - c = tokstart[++namelen]) - ; - - /* The token "if" terminates the expression and is NOT - removed from the input stream. */ - if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f') - { - return 0; - } - - pstate->lexptr += namelen; - - /* Lookup special keywords */ - for(i = 0 ; i < (int) (sizeof(keytab) / sizeof(keytab[0])) ; i++) - if (namelen == strlen (keytab[i].keyw) - && strncmp (tokstart, keytab[i].keyw, namelen) == 0) - return keytab[i].token; - - yylval.sval.ptr = tokstart; - yylval.sval.length = namelen; - - if (*tokstart == '$') - return DOLLAR_VARIABLE; - - /* Use token-type BLOCKNAME for symbols that happen to be defined as - functions. If this is not so, then ... - Use token-type TYPENAME for symbols that happen to be defined - currently as names of types; NAME for other symbols. - The caller is not constrained to care about the distinction. */ - { - std::string tmp = copy_name (yylval.sval); - struct symbol *sym; - - if (lookup_symtab (current_program_space, tmp.c_str ()) != nullptr) - return BLOCKNAME; - - sym = lookup_symbol (tmp.c_str (), pstate->expression_context_block, - SEARCH_VFT, 0).symbol; - if (sym && sym->loc_class () == LOC_BLOCK) - return BLOCKNAME; - if (lookup_typename (pstate->language (), - tmp.c_str (), pstate->expression_context_block, 1)) - return TYPENAME; - - if(sym) - { - switch(sym->loc_class ()) - { - case LOC_STATIC: - case LOC_REGISTER: - case LOC_ARG: - case LOC_REF_ARG: - case LOC_REGPARM_ADDR: - case LOC_LOCAL: - case LOC_CONST: - case LOC_CONST_BYTES: - case LOC_OPTIMIZED_OUT: - case LOC_COMPUTED: - return NAME; - - case LOC_TYPEDEF: - return TYPENAME; - - case LOC_BLOCK: - return BLOCKNAME; - - case LOC_UNDEF: - error (_("internal: Undefined class in m2lex()")); - - case LOC_LABEL: - case LOC_UNRESOLVED: - error (_("internal: Unforeseen case in m2lex()")); - - default: - error (_("unhandled token in m2lex()")); - break; - } - } - else - { - /* Built-in BOOLEAN type. This is sort of a hack. */ - if (startswith (tokstart, "TRUE")) - { - yylval.ulval = 1; - return M2_TRUE; - } - else if (startswith (tokstart, "FALSE")) - { - yylval.ulval = 0; - return M2_FALSE; - } - } - - /* Must be another type of name... */ - return NAME; - } -} - -int -m2_language::parser (struct parser_state *par_state) const -{ - /* Setting up the parser state. */ - scoped_restore pstate_restore = make_scoped_restore (&pstate); - gdb_assert (par_state != NULL); - pstate = par_state; - paren_depth = 0; - - int result = yyparse (); - if (!result) - pstate->set_operation (pstate->pop ()); - return result; -} - -static void -yyerror (const char *msg) -{ - pstate->parse_error (msg); -} diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c index 7bee1f36dc83..53bb8e25212e 100644 --- a/gdb/m2-lang.c +++ b/gdb/m2-lang.c @@ -25,6 +25,7 @@ #include "language.h" #include "varobj.h" #include "m2-lang.h" +#include "m2-exp-parser.h" #include "c-lang.h" #include "valprint.h" #include "gdbarch.h" @@ -118,6 +119,14 @@ static m2_language m2_language_defn; /* See language.h. */ +int +m2_language::parser (struct parser_state *ps) const +{ + return m2_parse (ps); +} + +/* See language.h. */ + void m2_language::language_arch_info (struct gdbarch *gdbarch, struct language_arch_info *lai) const -- 2.55.0