mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-03-10 04:43:03 +00:00
Prompted by Rici Lake. http://lists.gnu.org/archive/html/bug-bison/2018-10/msg00000.html We have four classes of directives that declare symbols: %nterm, %type, %token, and the family of %left etc. Currently not all of them support the possibility to have several type tags (`<type>`), and not all of them support the fact of not having any type tag at all (%type). Let's unify this. - %type POSIX Yacc specifies that %type is for nonterminals only. However, some Bison users want to use it for both tokens and nterms (actually, Bison's own grammar does this in several places, e.g., CHAR). So it should accept char/string literals. As a consequence cannot be used to declare tokens with their alias: `%type foo "foo"` would be ambiguous (are we defining foo = "foo", or are these two different symbols?) POSIX specifies that it is OK to use %type without a type tag. I'm not sure what it means, but we support it. - %token Accept token declarations with number and string literal: (ID|CHAR) NUM? STRING?. - %left, etc. They cannot be the same as %token, because we accept to declare the symbol with %token, and to then qualify its precedence with %left. Then `%left foo "foo"` would also be ambiguous: foo="foo", or two symbols. They cannot be simply a list of identifiers, but POSIX Yacc says we can declare token numbers here. I personally think this is a bad idea, precedence management is tricky in itself and should not be cluttered with token declaration issues. We used to accept declaring a token number on a string literal here (e.g., `%left "token" 1`). This is abnormal. Either the feature is useful, and then it should be supported in %token, or it's useless and we should not support it in corner cases. - %nterm Obviously cannot accept tokens, nor char/string literals. Does not exist in POSIX Yacc, but since %type also works for terminals, it is a nice option to have. * src/parse-gram.y: Avoid relying on side effects. For instance, get rid of current_type, rather, build the list of symbols and iterate over it to assign the type. It's not always possible/convenient. For instance, we still use current_class. Prefer "decl" to "def", since in the rest of the implementation we actually "declare" symbols, we don't "define" them. (token_decls, token_decls_for_prec, symbol_decls, nterm_decls): New. Use them for %token, %left, %type and %nterm. * src/symlist.h, src/symlist.c (symbol_list_type_set): New. * tests/regression.at b/tests/regression.at (Token number in precedence declaration): We no longer accept to give a number to string literals.
236 lines
5.9 KiB
C
236 lines
5.9 KiB
C
/* Lists of symbols for Bison
|
|
|
|
Copyright (C) 2002, 2005-2007, 2009-2015, 2018 Free Software
|
|
Foundation, Inc.
|
|
|
|
This file is part of Bison, the GNU Compiler Compiler.
|
|
|
|
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/>. */
|
|
|
|
#include <config.h>
|
|
#include "system.h"
|
|
|
|
#include "symlist.h"
|
|
|
|
/*--------------------------------------.
|
|
| Create a list containing SYM at LOC. |
|
|
`--------------------------------------*/
|
|
|
|
symbol_list *
|
|
symbol_list_sym_new (symbol *sym, location loc)
|
|
{
|
|
symbol_list *res = xmalloc (sizeof *res);
|
|
|
|
res->content_type = SYMLIST_SYMBOL;
|
|
res->content.sym = sym;
|
|
res->location = res->sym_loc = loc;
|
|
res->named_ref = NULL;
|
|
|
|
res->midrule = NULL;
|
|
res->midrule_parent_rule = NULL;
|
|
res->midrule_parent_rhs_index = 0;
|
|
|
|
/* Members used for LHS only. */
|
|
res->ruleprec = NULL;
|
|
res->percent_empty_loc = empty_location;
|
|
code_props_none_init (&res->action_props);
|
|
res->dprec = 0;
|
|
res->dprec_location = empty_location;
|
|
res->merger = 0;
|
|
res->merger_declaration_location = empty_location;
|
|
res->expected_sr_conflicts = -1;
|
|
res->expected_rr_conflicts = -1;
|
|
|
|
res->next = NULL;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*--------------------------------------------.
|
|
| Create a list containing TYPE_NAME at LOC. |
|
|
`--------------------------------------------*/
|
|
|
|
symbol_list *
|
|
symbol_list_type_new (uniqstr type_name, location loc)
|
|
{
|
|
symbol_list *res = xmalloc (sizeof *res);
|
|
|
|
res->content_type = SYMLIST_TYPE;
|
|
res->content.sem_type = xmalloc (sizeof (semantic_type));
|
|
res->content.sem_type->tag = type_name;
|
|
res->content.sem_type->location = loc;
|
|
res->content.sem_type->status = undeclared;
|
|
|
|
res->location = res->sym_loc = loc;
|
|
res->named_ref = NULL;
|
|
res->next = NULL;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
symbol_list *
|
|
symbol_list_type_set (symbol_list *syms, uniqstr type_name, location loc)
|
|
{
|
|
for (symbol_list *l = syms; l; l = l->next)
|
|
symbol_type_set (l->content.sym, type_name, loc);
|
|
return syms;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------.
|
|
| Print this list, for which every content_type must be SYMLIST_SYMBOL. |
|
|
`-----------------------------------------------------------------------*/
|
|
|
|
void
|
|
symbol_list_syms_print (const symbol_list *l, FILE *f)
|
|
{
|
|
char const *sep = "";
|
|
for (/* Nothing. */; l && l->content.sym; l = l->next)
|
|
{
|
|
fputs (sep, f);
|
|
fputs (l->content_type == SYMLIST_SYMBOL ? "symbol: "
|
|
: l->content_type == SYMLIST_TYPE ? "type: "
|
|
: "invalid content_type: ",
|
|
f);
|
|
symbol_print (l->content.sym, f);
|
|
fputs (l->action_props.is_value_used ? " used" : " unused", f);
|
|
sep = ", ";
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------.
|
|
| Prepend NODE to the LIST. |
|
|
`---------------------------*/
|
|
|
|
symbol_list *
|
|
symbol_list_prepend (symbol_list *list, symbol_list *node)
|
|
{
|
|
node->next = list;
|
|
return node;
|
|
}
|
|
|
|
|
|
/*-------------------------.
|
|
| Append NODE to the LIST. |
|
|
`-------------------------*/
|
|
|
|
symbol_list *
|
|
symbol_list_append (symbol_list *list, symbol_list *node)
|
|
{
|
|
if (!list)
|
|
return node;
|
|
symbol_list *next = list;
|
|
while (next->next)
|
|
next = next->next;
|
|
next->next = node;
|
|
return list;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------.
|
|
| Free the LIST, but not the items it contains. |
|
|
`-----------------------------------------------*/
|
|
|
|
void
|
|
symbol_list_free (symbol_list *list)
|
|
{
|
|
symbol_list *node, *next;
|
|
for (node = list; node; node = next)
|
|
{
|
|
next = node->next;
|
|
named_ref_free (node->named_ref);
|
|
if (node->content_type == SYMLIST_TYPE)
|
|
free (node->content.sem_type);
|
|
free (node);
|
|
}
|
|
}
|
|
|
|
|
|
/*--------------------.
|
|
| Return its length. |
|
|
`--------------------*/
|
|
|
|
int
|
|
symbol_list_length (symbol_list const *l)
|
|
{
|
|
int res = 0;
|
|
for (/* Nothing. */;
|
|
l && !(l->content_type == SYMLIST_SYMBOL && l->content.sym == NULL);
|
|
l = l->next)
|
|
++res;
|
|
return res;
|
|
}
|
|
|
|
|
|
/*------------------------------.
|
|
| Get item N in symbol list L. |
|
|
`------------------------------*/
|
|
|
|
symbol_list *
|
|
symbol_list_n_get (symbol_list *l, int n)
|
|
{
|
|
aver (0 <= n);
|
|
for (int i = 0; i < n; ++i)
|
|
{
|
|
l = l->next;
|
|
aver (l);
|
|
}
|
|
aver (l->content_type == SYMLIST_SYMBOL);
|
|
aver (l->content.sym);
|
|
return l;
|
|
}
|
|
|
|
/*--------------------------------------------------------------.
|
|
| Get the data type (alternative in the union) of the value for |
|
|
| symbol N in symbol list L. |
|
|
`--------------------------------------------------------------*/
|
|
|
|
uniqstr
|
|
symbol_list_n_type_name_get (symbol_list *l, int n)
|
|
{
|
|
return symbol_list_n_get (l, n)->content.sym->content->type_name;
|
|
}
|
|
|
|
bool
|
|
symbol_list_null (symbol_list *node)
|
|
{
|
|
return (!node
|
|
|| (node->content_type == SYMLIST_SYMBOL && !node->content.sym));
|
|
}
|
|
|
|
void
|
|
symbol_list_code_props_set (symbol_list *node, code_props_type kind,
|
|
code_props const *cprops)
|
|
{
|
|
switch (node->content_type)
|
|
{
|
|
case SYMLIST_SYMBOL:
|
|
symbol_code_props_set (node->content.sym, kind, cprops);
|
|
if (node->content.sym->content->status == undeclared)
|
|
node->content.sym->content->status = used;
|
|
break;
|
|
case SYMLIST_TYPE:
|
|
semantic_type_code_props_set
|
|
(semantic_type_get (node->content.sem_type->tag,
|
|
&node->content.sem_type->location),
|
|
kind, cprops);
|
|
if (node->content.sem_type->status == undeclared)
|
|
node->content.sem_type->status = used;
|
|
break;
|
|
}
|
|
}
|