mirror of
https://git.savannah.gnu.org/git/bison.git
synced 2026-08-08 18:25:13 +00:00
Compare commits
7
Commits
v3.4.90
...
partialorder
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8c9212bbd | ||
|
|
d992a222af | ||
|
|
86a2a43854 | ||
|
|
d8de391c38 | ||
|
|
f8a710c6f4 | ||
|
|
2d8fc07778 | ||
|
|
a910d26cfb |
@@ -2,6 +2,32 @@ GNU Bison NEWS
|
||||
|
||||
* Noteworthy changes in release ?.? (????-??-??) [?]
|
||||
|
||||
** New syntax: partial-order precedence relationships
|
||||
|
||||
Formerly, the precedence order of tokens was linear, depending only on the
|
||||
order in which they were declared. With the new syntax, all the tokens are
|
||||
not necessarily comparable. It is possible to declare a group of tokens with
|
||||
no links outside of the group, and to later on add only those needed.
|
||||
The uncomparability of tokens would allow for more feedback on new conflicts
|
||||
silently resolved via precedence.
|
||||
|
||||
An example of the new syntax applied to arithmetic and boolean operators,
|
||||
with '^' serving as both numerical power and boolean XOR:
|
||||
|
||||
%gprec arith {
|
||||
%left '+' '-'
|
||||
%left '*' '/'
|
||||
}
|
||||
%gprec bool {
|
||||
%left OR
|
||||
%left AND
|
||||
}
|
||||
%gprec { %right '^' }
|
||||
|
||||
%precr '^' > arith
|
||||
%precr OR AND > '^'
|
||||
|
||||
Here, AND is not comparable with '+', but '^' > '+' and AND > '^'
|
||||
|
||||
* Noteworthy changes in release 3.0 (2013-07-25) [stable]
|
||||
|
||||
|
||||
@@ -740,7 +740,7 @@ AnnotationList__computeDominantContribution (AnnotationList const *self,
|
||||
if (reduce_precedence
|
||||
&& (reduce_precedence < shift_precedence
|
||||
|| (reduce_precedence == shift_precedence
|
||||
&& token->content->assoc == right_assoc)))
|
||||
&& token->content->prec_node->assoc == right_assoc)))
|
||||
continue;
|
||||
if (!AnnotationList__stateMakesContribution (self, nitems, ci,
|
||||
lookaheads))
|
||||
@@ -748,7 +748,7 @@ AnnotationList__computeDominantContribution (AnnotationList const *self,
|
||||
/* This uneliminated reduction contributes, so see if it can cause
|
||||
an error action. */
|
||||
if (reduce_precedence == shift_precedence
|
||||
&& token->content->assoc == non_assoc)
|
||||
&& token->content->prec_node->assoc == non_assoc)
|
||||
{
|
||||
/* It's not possible to find split-stable domination over
|
||||
shift after a potential %nonassoc. */
|
||||
|
||||
+77
-56
@@ -53,7 +53,8 @@ enum conflict_resolution
|
||||
reduce_resolution,
|
||||
left_resolution,
|
||||
right_resolution,
|
||||
nonassoc_resolution
|
||||
nonassoc_resolution,
|
||||
uncomparable_resolution
|
||||
};
|
||||
|
||||
|
||||
@@ -90,6 +91,7 @@ log_resolution (rule *r, symbol_number token,
|
||||
break;
|
||||
|
||||
case nonassoc_resolution:
|
||||
case uncomparable_resolution:
|
||||
obstack_printf (&solved_conflicts_obstack,
|
||||
_(" Conflict between rule %d and token %s"
|
||||
" resolved as an error"),
|
||||
@@ -132,6 +134,12 @@ log_resolution (rule *r, symbol_number token,
|
||||
" (%%nonassoc %s)",
|
||||
symbols[token]->tag);
|
||||
break;
|
||||
case uncomparable_resolution:
|
||||
obstack_printf (&solved_conflicts_obstack,
|
||||
" (%s uncomparable with %s)",
|
||||
r->prec->symbol->tag,
|
||||
symbols[token]->tag);
|
||||
break;
|
||||
}
|
||||
|
||||
obstack_sgrow (&solved_conflicts_obstack, ".\n");
|
||||
@@ -161,6 +169,7 @@ log_resolution (rule *r, symbol_number token,
|
||||
xml_escape (symbols[token]->tag));
|
||||
break;
|
||||
|
||||
case uncomparable_resolution:
|
||||
case nonassoc_resolution:
|
||||
obstack_printf (&solved_conflicts_xml_obstack,
|
||||
" <resolution rule=\"%d\" symbol=\"%s\""
|
||||
@@ -203,7 +212,13 @@ log_resolution (rule *r, symbol_number token,
|
||||
obstack_printf (&solved_conflicts_xml_obstack,
|
||||
"%%nonassoc %s",
|
||||
xml_escape (symbols[token]->tag));
|
||||
break;
|
||||
break;
|
||||
case uncomparable_resolution:
|
||||
obstack_printf (&solved_conflicts_xml_obstack,
|
||||
"%s uncomparable with %s",
|
||||
xml_escape_n (0, symbols[token]->tag),
|
||||
xml_escape_n (1, r->prec->symbol->tag));
|
||||
break;
|
||||
}
|
||||
|
||||
obstack_sgrow (&solved_conflicts_xml_obstack, "</resolution>\n");
|
||||
@@ -243,7 +258,6 @@ flush_reduce (bitset lookahead_tokens, int token)
|
||||
bitset_reset (lookahead_tokens, token);
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------.
|
||||
| Attempt to resolve shift-reduce conflict for one rule by means of |
|
||||
| precedence declarations. It has already been checked that the |
|
||||
@@ -263,66 +277,73 @@ resolve_sr_conflict (state *s, int ruleno, symbol **errors, int *nerrs)
|
||||
reductions *reds = s->reductions;
|
||||
/* Find the rule to reduce by to get precedence of reduction. */
|
||||
rule *redrule = reds->rules[ruleno];
|
||||
int redprec = redrule->prec->prec;
|
||||
prec_node *redprecsym = redrule->prec->prec_node;
|
||||
bitset lookahead_tokens = reds->lookahead_tokens[ruleno];
|
||||
|
||||
for (i = 0; i < ntokens; i++)
|
||||
if (bitset_test (lookahead_tokens, i)
|
||||
&& bitset_test (lookahead_set, i)
|
||||
&& symbols[i]->content->prec)
|
||||
&& bitset_test (lookahead_set, i))
|
||||
{
|
||||
/* Shift-reduce conflict occurs for token number i
|
||||
and it has a precedence.
|
||||
The precedence of shifting is that of token i. */
|
||||
if (symbols[i]->content->prec < redprec)
|
||||
if (redprecsym && symbols[i]->content->prec_node)
|
||||
{
|
||||
register_precedence (redrule->prec->number, i);
|
||||
log_resolution (redrule, i, reduce_resolution);
|
||||
flush_shift (s, i);
|
||||
}
|
||||
else if (symbols[i]->content->prec > redprec)
|
||||
{
|
||||
register_precedence (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, shift_resolution);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
/* Shift-reduce conflict occurs for token number i
|
||||
and it has a precedence.
|
||||
The precedence of shifting is that of token i. */
|
||||
if (is_prec_superior (redprecsym, symbols[i]->content->prec_node))
|
||||
{
|
||||
register_precedence (redrule->prec->number, i);
|
||||
log_resolution (redrule, i, reduce_resolution);
|
||||
flush_shift (s, i);
|
||||
}
|
||||
else if (is_prec_superior (symbols[i]->content->prec_node,
|
||||
redprecsym))
|
||||
{
|
||||
register_precedence (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, shift_resolution);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
}
|
||||
else if (is_prec_equal (redprecsym, symbols[i]->content->prec_node))
|
||||
/* Matching precedence levels.
|
||||
For non-defined associativity, keep both: unexpected
|
||||
associativity conflict.
|
||||
For left associativity, keep only the reduction.
|
||||
For right associativity, keep only the shift.
|
||||
For nonassociativity, keep neither. */
|
||||
|
||||
switch (symbols[i]->content->prec_node->assoc)
|
||||
{
|
||||
case undef_assoc:
|
||||
break;
|
||||
|
||||
case precedence_assoc:
|
||||
break;
|
||||
|
||||
case right_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, right_resolution);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
break;
|
||||
|
||||
case left_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, left_resolution);
|
||||
flush_shift (s, i);
|
||||
break;
|
||||
|
||||
case non_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, nonassoc_resolution);
|
||||
flush_shift (s, i);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
/* Record an explicit error for this token. */
|
||||
errors[(*nerrs)++] = symbols[i];
|
||||
break;
|
||||
}
|
||||
else
|
||||
log_resolution (redrule, i, uncomparable_resolution);
|
||||
}
|
||||
else
|
||||
/* Matching precedence levels.
|
||||
For non-defined associativity, keep both: unexpected
|
||||
associativity conflict.
|
||||
For left associativity, keep only the reduction.
|
||||
For right associativity, keep only the shift.
|
||||
For nonassociativity, keep neither. */
|
||||
|
||||
switch (symbols[i]->content->assoc)
|
||||
{
|
||||
case undef_assoc:
|
||||
abort ();
|
||||
|
||||
case precedence_assoc:
|
||||
break;
|
||||
|
||||
case right_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, right_resolution);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
break;
|
||||
|
||||
case left_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, left_resolution);
|
||||
flush_shift (s, i);
|
||||
break;
|
||||
|
||||
case non_assoc:
|
||||
register_assoc (i, redrule->prec->number);
|
||||
log_resolution (redrule, i, nonassoc_resolution);
|
||||
flush_shift (s, i);
|
||||
flush_reduce (lookahead_tokens, i);
|
||||
/* Record an explicit error for this token. */
|
||||
errors[(*nerrs)++] = symbols[i];
|
||||
break;
|
||||
}
|
||||
log_resolution (redrule, i, uncomparable_resolution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +375,7 @@ set_conflicts (state *s, symbol **errors)
|
||||
check for shift-reduce conflict, and try to resolve using
|
||||
precedence. */
|
||||
for (i = 0; i < reds->num; ++i)
|
||||
if (reds->rules[i]->prec && reds->rules[i]->prec->prec
|
||||
if (reds->rules[i]->prec /* && reds->rules[i]->prec->prec */
|
||||
&& !bitset_disjoint_p (reds->lookahead_tokens[i], lookahead_set))
|
||||
resolve_sr_conflict (s, i, errors, &nerrs);
|
||||
|
||||
|
||||
+4
-2
@@ -44,6 +44,8 @@ int nvars = 0;
|
||||
|
||||
symbol_number *token_translations = NULL;
|
||||
|
||||
enum braces_state prec_braces = 0;
|
||||
|
||||
int max_user_token_number = 256;
|
||||
|
||||
bool
|
||||
@@ -239,7 +241,7 @@ grammar_dump (FILE *out, const char *title)
|
||||
for (i = ntokens; i < nsyms; i++)
|
||||
fprintf (out, "%5d %5d %5d %s\n",
|
||||
i,
|
||||
symbols[i]->content->prec, symbols[i]->content->assoc,
|
||||
symbols[i]->content->prec, symbols[i]->content->prec_node->assoc,
|
||||
symbols[i]->tag);
|
||||
fprintf (out, "\n\n");
|
||||
}
|
||||
@@ -262,7 +264,7 @@ grammar_dump (FILE *out, const char *title)
|
||||
fprintf (out, "%3d (%2d, %2d, %2d, %2u-%2u) %2d ->",
|
||||
i,
|
||||
rule_i->prec ? rule_i->prec->prec : 0,
|
||||
rule_i->prec ? rule_i->prec->assoc : 0,
|
||||
rule_i->prec ? rule_i->prec->prec_node->assoc : 0,
|
||||
rule_i->useful,
|
||||
rhs_itemno,
|
||||
rhs_itemno + rhs_count - 1,
|
||||
|
||||
+11
@@ -117,6 +117,17 @@ typedef int item_number;
|
||||
extern item_number *ritem;
|
||||
extern unsigned int nritems;
|
||||
|
||||
enum braces_state
|
||||
{
|
||||
default_braces_state,
|
||||
gprec_seen,
|
||||
group_name_seen,
|
||||
braces_seen
|
||||
};
|
||||
|
||||
/* Marker for the lexer and parser, to correctly interpret braces. */
|
||||
extern enum braces_state prec_braces;
|
||||
|
||||
/* There is weird relationship between OT1H item_number and OTOH
|
||||
symbol_number and rule_number: we store the latter in
|
||||
item_number. symbol_number values are stored as-is, while
|
||||
|
||||
+787
-652
File diff suppressed because it is too large
Load Diff
+64
-57
@@ -52,7 +52,7 @@ extern int gram_debug;
|
||||
|
||||
#include "symlist.h"
|
||||
#include "symtab.h"
|
||||
#line 221 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 233 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
@@ -61,7 +61,7 @@ extern int gram_debug;
|
||||
param_parse = 1 << 1,
|
||||
param_both = param_lex | param_parse
|
||||
} param_type;
|
||||
#line 645 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 723 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#include "muscle-tab.h"
|
||||
|
||||
#line 68 "src/parse-gram.h" /* yacc.c:1909 */
|
||||
@@ -84,49 +84,54 @@ extern int gram_debug;
|
||||
PERCENT_PRECEDENCE = 267,
|
||||
PERCENT_PREC = 268,
|
||||
PERCENT_DPREC = 269,
|
||||
PERCENT_MERGE = 270,
|
||||
PERCENT_CODE = 271,
|
||||
PERCENT_DEFAULT_PREC = 272,
|
||||
PERCENT_DEFINE = 273,
|
||||
PERCENT_DEFINES = 274,
|
||||
PERCENT_ERROR_VERBOSE = 275,
|
||||
PERCENT_EXPECT = 276,
|
||||
PERCENT_EXPECT_RR = 277,
|
||||
PERCENT_FLAG = 278,
|
||||
PERCENT_FILE_PREFIX = 279,
|
||||
PERCENT_GLR_PARSER = 280,
|
||||
PERCENT_INITIAL_ACTION = 281,
|
||||
PERCENT_LANGUAGE = 282,
|
||||
PERCENT_NAME_PREFIX = 283,
|
||||
PERCENT_NO_DEFAULT_PREC = 284,
|
||||
PERCENT_NO_LINES = 285,
|
||||
PERCENT_NONDETERMINISTIC_PARSER = 286,
|
||||
PERCENT_OUTPUT = 287,
|
||||
PERCENT_REQUIRE = 288,
|
||||
PERCENT_SKELETON = 289,
|
||||
PERCENT_START = 290,
|
||||
PERCENT_TOKEN_TABLE = 291,
|
||||
PERCENT_VERBOSE = 292,
|
||||
PERCENT_YACC = 293,
|
||||
BRACED_CODE = 294,
|
||||
BRACED_PREDICATE = 295,
|
||||
BRACKETED_ID = 296,
|
||||
CHAR = 297,
|
||||
EPILOGUE = 298,
|
||||
EQUAL = 299,
|
||||
ID = 300,
|
||||
ID_COLON = 301,
|
||||
PERCENT_PERCENT = 302,
|
||||
PIPE = 303,
|
||||
PROLOGUE = 304,
|
||||
SEMICOLON = 305,
|
||||
TAG = 306,
|
||||
TAG_ANY = 307,
|
||||
TAG_NONE = 308,
|
||||
INT = 309,
|
||||
PERCENT_PARAM = 310,
|
||||
PERCENT_UNION = 311,
|
||||
PERCENT_EMPTY = 312
|
||||
PERCENT_GPREC = 270,
|
||||
PERCENT_PRECR = 271,
|
||||
PERCENT_MERGE = 272,
|
||||
PERCENT_CODE = 273,
|
||||
PERCENT_DEFAULT_PREC = 274,
|
||||
PERCENT_DEFINE = 275,
|
||||
PERCENT_DEFINES = 276,
|
||||
PERCENT_ERROR_VERBOSE = 277,
|
||||
PERCENT_EXPECT = 278,
|
||||
PERCENT_EXPECT_RR = 279,
|
||||
PERCENT_FLAG = 280,
|
||||
PERCENT_FILE_PREFIX = 281,
|
||||
PERCENT_GLR_PARSER = 282,
|
||||
PERCENT_INITIAL_ACTION = 283,
|
||||
PERCENT_LANGUAGE = 284,
|
||||
PERCENT_NAME_PREFIX = 285,
|
||||
PERCENT_NO_DEFAULT_PREC = 286,
|
||||
PERCENT_NO_LINES = 287,
|
||||
PERCENT_NONDETERMINISTIC_PARSER = 288,
|
||||
PERCENT_OUTPUT = 289,
|
||||
PERCENT_REQUIRE = 290,
|
||||
PERCENT_SKELETON = 291,
|
||||
PERCENT_START = 292,
|
||||
PERCENT_TOKEN_TABLE = 293,
|
||||
PERCENT_VERBOSE = 294,
|
||||
PERCENT_YACC = 295,
|
||||
BRACED_CODE = 296,
|
||||
BRACED_PREDICATE = 297,
|
||||
BRACKETED_ID = 298,
|
||||
CHAR = 299,
|
||||
EPILOGUE = 300,
|
||||
EQUAL = 301,
|
||||
ID = 302,
|
||||
ID_COLON = 303,
|
||||
PERCENT_PERCENT = 304,
|
||||
PIPE = 305,
|
||||
PROLOGUE = 306,
|
||||
SEMICOLON = 307,
|
||||
GT = 308,
|
||||
TAG = 309,
|
||||
TAG_ANY = 310,
|
||||
TAG_NONE = 311,
|
||||
LBRACE = 312,
|
||||
RBRACE = 313,
|
||||
INT = 314,
|
||||
PERCENT_PARAM = 315,
|
||||
PERCENT_UNION = 316,
|
||||
PERCENT_EMPTY = 317
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -135,27 +140,29 @@ extern int gram_debug;
|
||||
typedef union GRAM_STYPE GRAM_STYPE;
|
||||
union GRAM_STYPE
|
||||
{
|
||||
#line 182 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 187 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
unsigned char character;
|
||||
#line 186 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
char *code;
|
||||
#line 191 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
char *code;
|
||||
#line 196 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
uniqstr uniqstr;
|
||||
#line 199 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 204 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
int integer;
|
||||
#line 203 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
symbol *symbol;
|
||||
#line 208 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
symbol *symbol;
|
||||
#line 213 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
assoc assoc;
|
||||
#line 211 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 216 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
symbol_list *list;
|
||||
#line 214 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 219 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
named_ref *named_ref;
|
||||
#line 241 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 224 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
prec_rel_comparator prec_rel_comparator;
|
||||
#line 253 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
param_type param;
|
||||
#line 409 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 423 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
code_props_type code_type;
|
||||
#line 647 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
#line 725 "src/parse-gram.y" /* yacc.c:1909 */
|
||||
|
||||
struct
|
||||
{
|
||||
@@ -163,7 +170,7 @@ code_props_type code_type;
|
||||
muscle_kind kind;
|
||||
} value;
|
||||
|
||||
#line 167 "src/parse-gram.h" /* yacc.c:1909 */
|
||||
#line 174 "src/parse-gram.h" /* yacc.c:1909 */
|
||||
};
|
||||
# define GRAM_STYPE_IS_TRIVIAL 1
|
||||
# define GRAM_STYPE_IS_DECLARED 1
|
||||
|
||||
@@ -130,6 +130,8 @@
|
||||
|
||||
%token PERCENT_PREC "%prec"
|
||||
%token PERCENT_DPREC "%dprec"
|
||||
%token PERCENT_GPREC "%gprec"
|
||||
%token PERCENT_PRECR "%precr"
|
||||
%token PERCENT_MERGE "%merge"
|
||||
|
||||
/*----------------------.
|
||||
@@ -175,9 +177,12 @@
|
||||
%token PIPE "|"
|
||||
%token PROLOGUE "%{...%}"
|
||||
%token SEMICOLON ";"
|
||||
%token GT ">"
|
||||
%token TAG "<tag>"
|
||||
%token TAG_ANY "<*>"
|
||||
%token TAG_NONE "<>"
|
||||
%token LBRACE "{"
|
||||
%token RBRACE "}"
|
||||
|
||||
%union {unsigned char character;}
|
||||
%type <character> CHAR
|
||||
@@ -214,6 +219,13 @@
|
||||
%union {named_ref *named_ref;}
|
||||
%type <named_ref> named_ref.opt
|
||||
|
||||
%type <uniqstr> prec_group_name.opt string_or_id
|
||||
|
||||
%union {prec_rel_comparator prec_rel_comparator;}
|
||||
%type <prec_rel_comparator> prec_rel_comparator
|
||||
|
||||
%type <list> precedence_relation_symbols precedence_symbol
|
||||
|
||||
/*---------.
|
||||
| %param. |
|
||||
`---------*/
|
||||
@@ -365,6 +377,8 @@ params:
|
||||
|
||||
grammar_declaration:
|
||||
precedence_declaration
|
||||
| precedence_group_declaration
|
||||
| precedence_relation_declaration
|
||||
| symbol_declaration
|
||||
| "%start" symbol
|
||||
{
|
||||
@@ -457,6 +471,30 @@ symbol_declaration:
|
||||
}
|
||||
;
|
||||
|
||||
/* A group of symbols for precedence declaration */
|
||||
precedence_group_declaration:
|
||||
"%gprec" prec_group_name.opt
|
||||
{
|
||||
set_current_group ($2, &@2);
|
||||
}
|
||||
"{" precedence_declarations "}"
|
||||
{
|
||||
set_current_group (DEFAULT_GROUP_NAME, NULL);
|
||||
}
|
||||
;
|
||||
|
||||
/* Name for the precedence group. If none is present a new unique one is
|
||||
generated. */
|
||||
prec_group_name.opt:
|
||||
%empty { $$ = new_anonymous_group_name (); }
|
||||
| variable /* Just a string, maybe there's a better way? */
|
||||
;
|
||||
|
||||
precedence_declarations:
|
||||
precedence_declaration
|
||||
| precedence_declarations precedence_declaration
|
||||
;
|
||||
|
||||
precedence_declaration:
|
||||
precedence_declarator tag.opt symbols.prec
|
||||
{
|
||||
@@ -484,6 +522,46 @@ tag.opt:
|
||||
| TAG { current_type = $1; tag_seen = true; }
|
||||
;
|
||||
|
||||
/* Declaration of a precedence relation between two (lists of) tokens */
|
||||
precedence_relation_declaration:
|
||||
"%precr" precedence_relation_symbols
|
||||
{ prec_braces = default_braces_state; }
|
||||
prec_rel_comparator
|
||||
precedence_relation_symbols
|
||||
{ declare_precedence_relation ($2, $5, $4, @4); }
|
||||
;
|
||||
|
||||
precedence_relation_symbols:
|
||||
precedence_symbol { $$ = $1; }
|
||||
| precedence_relation_symbols precedence_symbol
|
||||
{ $$ = symbol_list_append ($1, $2); }
|
||||
;
|
||||
|
||||
precedence_symbol:
|
||||
string_or_id
|
||||
{
|
||||
if (is_prec_group ($1))
|
||||
$$ = expand_symbol_group (symgroup_from_uniqstr($1, &@1), @1);
|
||||
else
|
||||
$$ = symbol_list_sym_new (symbol_from_uniqstr ($1, @1), @1);
|
||||
}
|
||||
| CHAR
|
||||
{
|
||||
$$ = symbol_list_sym_new (symbol_from_uniqstr (uniqstr_new (char_name ($1)), @1), @1);
|
||||
}
|
||||
;
|
||||
|
||||
string_or_id:
|
||||
STRING { $$ = uniqstr_new (quotearg_style (c_quoting_style, $1)); }
|
||||
| ID { $$ = $1; }
|
||||
;
|
||||
|
||||
prec_rel_comparator:
|
||||
">" { $$ = prec_superior; }
|
||||
| "=" { $$ = prec_equal; }
|
||||
| ">" ">" { $$ = prec_superior_strict; }
|
||||
;
|
||||
|
||||
/* Just like symbols.1 but accept INT for the sake of POSIX. */
|
||||
symbols.prec:
|
||||
symbol.prec
|
||||
|
||||
+2
-1
@@ -392,7 +392,8 @@ print_grammar (FILE *out, int level)
|
||||
{
|
||||
char const *tag = symbols[token_translations[i]]->tag;
|
||||
int precedence = symbols[token_translations[i]]->content->prec;
|
||||
assoc associativity = symbols[token_translations[i]]->content->assoc;
|
||||
assoc associativity = symbols[token_translations[i]]->content->prec_node
|
||||
->assoc;
|
||||
xml_indent (out, level + 2);
|
||||
fprintf (out,
|
||||
"<terminal symbol-number=\"%d\" token-number=\"%d\""
|
||||
|
||||
@@ -223,6 +223,10 @@ eqopt ([[:space:]]*=)?
|
||||
"%fixed-output-files" return PERCENT_YACC;
|
||||
"%initial-action" return PERCENT_INITIAL_ACTION;
|
||||
"%glr-parser" return PERCENT_GLR_PARSER;
|
||||
"%gprec" {
|
||||
prec_braces = gprec_seen;
|
||||
return PERCENT_GPREC;
|
||||
}
|
||||
"%language" return PERCENT_LANGUAGE;
|
||||
"%left" return PERCENT_LEFT;
|
||||
"%lex-param" RETURN_PERCENT_PARAM(lex);
|
||||
@@ -239,6 +243,7 @@ eqopt ([[:space:]]*=)?
|
||||
"%parse-param" RETURN_PERCENT_PARAM(parse);
|
||||
"%prec" return PERCENT_PREC;
|
||||
"%precedence" return PERCENT_PRECEDENCE;
|
||||
"%precr" return PERCENT_PRECR;
|
||||
"%printer" return PERCENT_PRINTER;
|
||||
"%pure-parser" RETURN_PERCENT_FLAG("api.pure");
|
||||
"%require" return PERCENT_REQUIRE;
|
||||
@@ -273,10 +278,17 @@ eqopt ([[:space:]]*=)?
|
||||
"=" return EQUAL;
|
||||
"|" return PIPE;
|
||||
";" return SEMICOLON;
|
||||
"}" return RBRACE;
|
||||
">" return GT;
|
||||
|
||||
{id} {
|
||||
val->uniqstr = uniqstr_new (yytext);
|
||||
id_loc = *loc;
|
||||
if (prec_braces == gprec_seen)
|
||||
{
|
||||
prec_braces = group_name_seen;
|
||||
return ID;
|
||||
}
|
||||
bracketed_id_str = NULL;
|
||||
BEGIN SC_AFTER_IDENTIFIER;
|
||||
}
|
||||
@@ -307,6 +319,11 @@ eqopt ([[:space:]]*=)?
|
||||
|
||||
/* Code in between braces. */
|
||||
"{" {
|
||||
if (prec_braces == gprec_seen || prec_braces == group_name_seen)
|
||||
{
|
||||
prec_braces = braces_seen;
|
||||
return LBRACE;
|
||||
}
|
||||
STRING_GROW;
|
||||
nesting = 0;
|
||||
code_start = loc->start;
|
||||
|
||||
+483
-12
@@ -26,6 +26,7 @@
|
||||
#include "complain.h"
|
||||
#include "gram.h"
|
||||
#include "symtab.h"
|
||||
#include "symlist.h"
|
||||
|
||||
/*-------------------------------------------------------------------.
|
||||
| Symbols sorted by tag. Allocated by the first invocation of |
|
||||
@@ -58,6 +59,305 @@ static symgraph **prec_nodes;
|
||||
|
||||
bool *used_assoc = NULL;
|
||||
|
||||
/*-------------------------------------------------------------.
|
||||
| The current precedence group of symbols. Used by the parser. |
|
||||
`-------------------------------------------------------------*/
|
||||
|
||||
static symgroup *current_group = NULL;
|
||||
|
||||
/*-------------------------------------------------------.
|
||||
| The list of symbols declared in the current statement. |
|
||||
`-------------------------------------------------------*/
|
||||
|
||||
static symbol_list *current_prec_declaration = NULL;
|
||||
|
||||
/*-------------------------------------------------.
|
||||
| A counter to distinguish precedence declarations |
|
||||
`-------------------------------------------------*/
|
||||
|
||||
static int current_prec_level = 0;
|
||||
|
||||
/*-----------------------------.
|
||||
| Constructor for a prec_link. |
|
||||
`-----------------------------*/
|
||||
|
||||
static prec_link *
|
||||
prec_link_new (prec_node *to, bool transitive)
|
||||
{
|
||||
prec_link *res = malloc (sizeof *res);
|
||||
res->target = to;
|
||||
res->transitive = transitive;
|
||||
res->next = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*-------------------------------------.
|
||||
| Destructor for a simple symbol list. |
|
||||
`-------------------------------------*/
|
||||
|
||||
static void
|
||||
symbol_list_prec_free (symbol_list *l)
|
||||
{
|
||||
if (l)
|
||||
{
|
||||
symbol_list_prec_free (l->next);
|
||||
free (l);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------------------------------------------.
|
||||
| Check if PARENT has a higher priority than SON. |
|
||||
`------------------------------------------------*/
|
||||
|
||||
bool
|
||||
is_prec_superior (prec_node *parent, prec_node *son)
|
||||
{
|
||||
prec_link *l;
|
||||
for (l = parent->sons; l; l = l->next)
|
||||
if (l->target == son)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------.
|
||||
| Check if S1 has the same priority as S2. |
|
||||
`-----------------------------------------*/
|
||||
|
||||
bool
|
||||
is_prec_equal (prec_node *s1, prec_node *s2)
|
||||
{
|
||||
prec_link *l;
|
||||
if (s1 == s2)
|
||||
return true;
|
||||
for (l = s1->equals; l; l = l->next)
|
||||
if (l->target == s2)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
complain_contradicting_prec (location *loc, uniqstr s1, uniqstr s2, char c1,
|
||||
char c2)
|
||||
{
|
||||
complain (loc, Wprecedence, _("contradicting declaration: %s %c %s is in "
|
||||
"conflict with the previous declaration: %s %c %s"), s1, c1, s2,
|
||||
s1, c2, s2);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------.
|
||||
| Compare LINK with TARGET, and return whether they are equal. |
|
||||
| In case of equality, complain of the duplicate precedence declaration. |
|
||||
`-----------------------------------------------------------------------*/
|
||||
|
||||
static inline bool
|
||||
is_prec_target (prec_node *l, prec_node *target, uniqstr from, char c,
|
||||
location loc)
|
||||
{
|
||||
if (l == target)
|
||||
{
|
||||
complain (&loc, Wprecedence, _("duplicate declaration of the precedence "
|
||||
"relationship %s %c %s"), from, c,
|
||||
target->symbol->tag);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*-----------------------------------------.
|
||||
| Add a precedence relationship FROM > TO. |
|
||||
`-----------------------------------------*/
|
||||
|
||||
static void
|
||||
add_prec_link (prec_node *from, prec_node *to, bool transitive, location loc)
|
||||
{
|
||||
if (is_prec_superior (to, from))
|
||||
complain_contradicting_prec(&loc, from->symbol->tag, to->symbol->tag,
|
||||
'>', '<');
|
||||
else if (is_prec_equal (from, to))
|
||||
complain_contradicting_prec(&loc, from->symbol->tag, to->symbol->tag,
|
||||
'>', '=');
|
||||
else
|
||||
{
|
||||
if (from->sons)
|
||||
{
|
||||
if (is_prec_target (from->sons->target, to, from->symbol->tag, '>',
|
||||
loc))
|
||||
return;
|
||||
|
||||
prec_link *son = from->sons;
|
||||
for (; son->next; son = son->next)
|
||||
if (is_prec_target (son->next->target, to, from->symbol->tag, '>',
|
||||
loc))
|
||||
return;
|
||||
son->next = prec_link_new (to, transitive);
|
||||
}
|
||||
else
|
||||
from->sons = prec_link_new (to, transitive);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------.
|
||||
| Add a precedence relationship S1 == S2, one way. |
|
||||
`-------------------------------------------------*/
|
||||
|
||||
static void
|
||||
create_prec_equal_link (prec_node *s1, prec_node *s2, bool transitive,
|
||||
location loc)
|
||||
{
|
||||
if (s1->equals)
|
||||
{
|
||||
if (is_prec_target (s1->equals->target, s2, s1->symbol->tag, '=',
|
||||
loc))
|
||||
return;
|
||||
prec_link *eq = s1->equals;
|
||||
for (; eq->next; eq = eq->next)
|
||||
if (is_prec_target (eq->next->target, s2, s1->symbol->tag, '=',
|
||||
loc))
|
||||
return;
|
||||
eq->next = prec_link_new (s2, transitive);
|
||||
}
|
||||
else
|
||||
s1->equals = prec_link_new (s2, transitive);
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------.
|
||||
| Add a precedence relationship S1 == S2, both ways. |
|
||||
`---------------------------------------------------*/
|
||||
|
||||
static void
|
||||
add_prec_equal_link (prec_node *s1, prec_node *s2, bool transitive,
|
||||
location loc)
|
||||
{
|
||||
if (is_prec_superior (s2, s1))
|
||||
complain_contradicting_prec(&loc, s1->symbol->tag, s2->symbol->tag,
|
||||
'=', '>');
|
||||
else if (is_prec_superior (s1, s2))
|
||||
complain_contradicting_prec(&loc, s1->symbol->tag, s2->symbol->tag,
|
||||
'=', '<');
|
||||
create_prec_equal_link (s1, s2, transitive, loc);
|
||||
create_prec_equal_link (s2, s1, transitive, loc);
|
||||
}
|
||||
|
||||
|
||||
/* The function to use to register \a c type relations. */
|
||||
typedef void (*add_link_t) (prec_node *, prec_node *, bool, location);
|
||||
static add_link_t
|
||||
add_link_function (prec_rel_comparator c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case prec_superior_strict:
|
||||
case prec_superior:
|
||||
return &add_prec_link;
|
||||
case prec_equal:
|
||||
return &add_prec_equal_link;
|
||||
}
|
||||
abort ();
|
||||
}
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------.
|
||||
| Handle the precedence declaration between the elements of S1 and S2. |
|
||||
`---------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
declare_precedence_relation (symbol_list *s1, symbol_list *s2,
|
||||
prec_rel_comparator c, location loc)
|
||||
{
|
||||
void (*functionPtr) (prec_node *, prec_node *, bool, location)
|
||||
= add_link_function (c);
|
||||
bool transitive = c != prec_superior_strict;
|
||||
for (symbol_list *l1 = s1; l1; l1 = l1->next)
|
||||
for (symbol_list *l2 = s2; l2; l2 = l2->next)
|
||||
(*functionPtr)(l1->content.sym->content->prec_node,
|
||||
l2->content.sym->content->prec_node, transitive, loc);
|
||||
symbol_list_free (s1);
|
||||
symbol_list_free (s2);
|
||||
}
|
||||
|
||||
/*----------------------------------------------.
|
||||
| Get the list of symbols contained in a group. |
|
||||
`----------------------------------------------*/
|
||||
|
||||
symbol_list *
|
||||
expand_symbol_group (symgroup *group, location loc)
|
||||
{
|
||||
symbol_list *l = NULL;
|
||||
for (sym_content *s = group->symbol_list; s; s = s->group_next)
|
||||
l = symbol_list_append (l, symbol_list_sym_new (s->symbol, loc));
|
||||
return l;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------.
|
||||
| Add a symbol to the current declaration group, and declare the implicit |
|
||||
| precedence links. SAME_LINE is true if the symbol was declared in the |
|
||||
| same statement as the previous one (same precedence level). |
|
||||
`------------------------------------------------------------------------*/
|
||||
|
||||
void
|
||||
add_to_current_group (sym_content *s, bool same_line)
|
||||
{
|
||||
if (!same_line)
|
||||
for (symbol_list *l = current_prec_declaration; l; l = l->next)
|
||||
{
|
||||
sym_content *symb = l->content.sym->content;
|
||||
if (!current_group->symbol_list)
|
||||
current_group->symbol_list = symb;
|
||||
else
|
||||
{
|
||||
sym_content *sym = current_group->symbol_list;
|
||||
while (sym->group_next)
|
||||
sym = sym->group_next;
|
||||
sym->group_next = symb;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_group->symbol_list)
|
||||
for (sym_content *sym = current_group->symbol_list; sym;
|
||||
sym = sym->group_next)
|
||||
add_prec_link (s->prec_node, sym->prec_node, true,
|
||||
s->prec_node->prec_location);
|
||||
|
||||
if (!same_line)
|
||||
{
|
||||
symbol_list_prec_free (current_prec_declaration);
|
||||
current_prec_declaration = malloc (sizeof *current_prec_declaration);
|
||||
current_prec_declaration->content.sym = s->symbol;
|
||||
current_prec_declaration->next = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
symbol_list *l = current_prec_declaration;
|
||||
for (; true; l = l->next)
|
||||
{
|
||||
add_prec_equal_link (s->prec_node, l->content.sym->content->prec_node,
|
||||
true, s->prec_node->prec_location);
|
||||
if (!l->next)
|
||||
break;
|
||||
}
|
||||
l->next = malloc (sizeof *l->next);
|
||||
l->next->content.sym = s->symbol;
|
||||
l->next->next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------.
|
||||
| Create a new prec_node for the symbol s. |
|
||||
`-----------------------------------------*/
|
||||
|
||||
static prec_node *
|
||||
prec_node_new (symbol * s)
|
||||
{
|
||||
prec_node * res = malloc (sizeof *res);
|
||||
res->symbol = s;
|
||||
res->assoc = undef_assoc;
|
||||
res->sons = NULL;
|
||||
res-> equals = NULL;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------.
|
||||
| Create a new sym_content. |
|
||||
`--------------------------*/
|
||||
@@ -78,12 +378,14 @@ sym_content_new (symbol *s)
|
||||
|
||||
res->number = NUMBER_UNDEFINED;
|
||||
res->prec = 0;
|
||||
res->assoc = undef_assoc;
|
||||
res->user_token_number = USER_NUMBER_UNDEFINED;
|
||||
|
||||
res->class = unknown_sym;
|
||||
res->status = undeclared;
|
||||
|
||||
res->group_next = NULL;
|
||||
res->prec_node = prec_node_new (s);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -105,6 +407,7 @@ symbol_new (uniqstr tag, location loc)
|
||||
|
||||
res->tag = tag;
|
||||
res->location = loc;
|
||||
|
||||
res->alias = NULL;
|
||||
res->content = sym_content_new (res);
|
||||
res->is_alias = false;
|
||||
@@ -116,6 +419,28 @@ symbol_new (uniqstr tag, location loc)
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
prec_link_free (prec_link * l)
|
||||
{
|
||||
if (l)
|
||||
{
|
||||
prec_link_free (l->next);
|
||||
free (l);
|
||||
}
|
||||
}
|
||||
|
||||
/*--------------------.
|
||||
| Free one prec_node. |
|
||||
`--------------------*/
|
||||
|
||||
static void
|
||||
prec_node_free (prec_node * n)
|
||||
{
|
||||
prec_link_free (n->sons);
|
||||
prec_link_free (n->equals);
|
||||
free (n);
|
||||
}
|
||||
|
||||
/*--------------------.
|
||||
| Free a sym_content. |
|
||||
`--------------------*/
|
||||
@@ -123,6 +448,7 @@ symbol_new (uniqstr tag, location loc)
|
||||
static void
|
||||
sym_content_free (sym_content *sym)
|
||||
{
|
||||
prec_node_free (sym->prec_node);
|
||||
free (sym);
|
||||
}
|
||||
|
||||
@@ -367,14 +693,16 @@ symbol_precedence_set (symbol *sym, int prec, assoc a, location loc)
|
||||
sym_content *s = sym->content;
|
||||
if (a != undef_assoc)
|
||||
{
|
||||
if (s->prec)
|
||||
if (s->prec_node->assoc != undef_assoc)
|
||||
symbol_redeclaration (sym, assoc_to_string (a),
|
||||
s->prec_location, loc);
|
||||
s->prec_node->prec_location, loc);
|
||||
else
|
||||
{
|
||||
s->prec = prec;
|
||||
s->assoc = a;
|
||||
s->prec_location = loc;
|
||||
s->prec_node->assoc = a;
|
||||
s->prec_node->prec_location = loc;
|
||||
add_to_current_group (s, prec == current_prec_level);
|
||||
current_prec_level = prec;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -684,6 +1012,38 @@ hash_semantic_type_hasher (void const *m, size_t tablesize)
|
||||
return hash_semantic_type (m, tablesize);
|
||||
}
|
||||
|
||||
/*-------------------------------------.
|
||||
| Symbol precedence group hash table. |
|
||||
`-------------------------------------*/
|
||||
|
||||
static struct hash_table *group_table = NULL;
|
||||
|
||||
static inline bool
|
||||
hash_compare_group (const symgroup *m1, const symgroup *m2)
|
||||
{
|
||||
/* Since tags are unique, we can compare the pointers themselves. */
|
||||
return UNIQSTR_EQ (m1->tag, m2->tag);
|
||||
}
|
||||
|
||||
static bool
|
||||
hash_group_comparator (void const *m1, void const *m2)
|
||||
{
|
||||
return hash_compare_group (m1, m2);
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
hash_group (const symgroup *m, size_t tablesize)
|
||||
{
|
||||
/* Since tags are unique, we can hash the pointer itself. */
|
||||
return ((uintptr_t) m->tag) % tablesize;
|
||||
}
|
||||
|
||||
static size_t
|
||||
hash_group_hasher (void const *m, size_t tablesize)
|
||||
{
|
||||
return hash_group (m, tablesize);
|
||||
}
|
||||
|
||||
/*-------------------------------.
|
||||
| Create the symbol hash table. |
|
||||
`-------------------------------*/
|
||||
@@ -701,6 +1061,12 @@ symbols_new (void)
|
||||
hash_semantic_type_hasher,
|
||||
hash_semantic_type_comparator,
|
||||
free);
|
||||
group_table = hash_initialize (HT_INITIAL_CAPACITY,
|
||||
NULL,
|
||||
hash_group_hasher,
|
||||
hash_group_comparator,
|
||||
free);
|
||||
set_current_group (DEFAULT_GROUP_NAME, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -815,9 +1181,11 @@ symbols_free (void)
|
||||
{
|
||||
hash_free (symbol_table);
|
||||
hash_free (semantic_type_table);
|
||||
hash_free (group_table);
|
||||
free (symbols);
|
||||
free (symbols_sorted);
|
||||
free (semantic_types_sorted);
|
||||
symbol_list_prec_free (current_prec_declaration);
|
||||
}
|
||||
|
||||
|
||||
@@ -1102,8 +1470,8 @@ static inline bool
|
||||
is_assoc_useless (symbol *s)
|
||||
{
|
||||
return s
|
||||
&& s->content->assoc != undef_assoc
|
||||
&& s->content->assoc != precedence_assoc
|
||||
&& s->content->prec_node->assoc != undef_assoc
|
||||
&& s->content->prec_node->assoc != precedence_assoc
|
||||
&& !used_assoc[s->content->number];
|
||||
}
|
||||
|
||||
@@ -1136,21 +1504,124 @@ print_precedence_warnings (void)
|
||||
{
|
||||
symbol *s = symbols[i];
|
||||
if (s
|
||||
&& s->content->prec != 0
|
||||
&& !prec_nodes[i]->pred
|
||||
&& !prec_nodes[i]->succ)
|
||||
{
|
||||
if (is_assoc_useless (s))
|
||||
complain (&s->content->prec_location, Wprecedence,
|
||||
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||
_("useless precedence and associativity for %s"), s->tag);
|
||||
else if (s->content->assoc == precedence_assoc)
|
||||
complain (&s->content->prec_location, Wprecedence,
|
||||
else if (s->content->prec_node->assoc == precedence_assoc)
|
||||
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||
_("useless precedence for %s"), s->tag);
|
||||
}
|
||||
else if (is_assoc_useless (s))
|
||||
complain (&s->content->prec_location, Wprecedence,
|
||||
complain (&s->content->prec_node->prec_location, Wprecedence,
|
||||
_("useless associativity for %s, use %%precedence"), s->tag);
|
||||
}
|
||||
free (used_assoc);
|
||||
assoc_free ();
|
||||
}
|
||||
|
||||
/*------------------------------------------------.
|
||||
| Counter to create unique anonymous group names. |
|
||||
`------------------------------------------------*/
|
||||
|
||||
static unsigned int anon_group_counter = 0;
|
||||
|
||||
/*-------------------------------------------------.
|
||||
| Return a new unique name for an anonymous group. |
|
||||
`-------------------------------------------------*/
|
||||
|
||||
uniqstr new_anonymous_group_name (void)
|
||||
{
|
||||
char buff[20];
|
||||
snprintf (buff, 20, "__anon%u__", anon_group_counter++);
|
||||
return uniqstr_new (buff);
|
||||
}
|
||||
|
||||
/*-------------------------------------------.
|
||||
| Constructor for a symbol precedence group. |
|
||||
`-------------------------------------------*/
|
||||
|
||||
symgroup *
|
||||
symgroup_new (const uniqstr tag, location loc)
|
||||
{
|
||||
symgroup *group = xmalloc (sizeof (*group));
|
||||
group->tag = tag;
|
||||
group->symbol_list = NULL;
|
||||
group->location = loc;
|
||||
return group;
|
||||
}
|
||||
|
||||
/*----------------------------------------.
|
||||
| Check if there is a group by that name. |
|
||||
`----------------------------------------*/
|
||||
|
||||
bool
|
||||
is_prec_group (const uniqstr key)
|
||||
{
|
||||
symgroup probe;
|
||||
symgroup *entry;
|
||||
probe.tag = key;
|
||||
entry = hash_lookup (group_table, &probe);
|
||||
return entry != NULL;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------.
|
||||
| Get the symbol precedence group by that name. If not present, a new group |
|
||||
| is created and inserted in the table, with the location information |
|
||||
| provided, if any. |
|
||||
`--------------------------------------------------------------------------*/
|
||||
|
||||
symgroup *
|
||||
symgroup_from_uniqstr (const uniqstr key, location *loc)
|
||||
{
|
||||
bool null_loc = loc == NULL;
|
||||
if (null_loc)
|
||||
{
|
||||
loc = malloc (sizeof *loc);
|
||||
boundary_set (&loc->start, uniqstr_new (""), 1, 1);
|
||||
boundary_set (&loc->end, uniqstr_new (""), 1, 1);
|
||||
}
|
||||
symgroup probe;
|
||||
symgroup *entry;
|
||||
|
||||
probe.tag = key;
|
||||
entry = hash_lookup (group_table, &probe);
|
||||
|
||||
if (!entry)
|
||||
{
|
||||
/* First insertion in the hash. */
|
||||
entry = symgroup_new (key, *loc);
|
||||
if (!hash_insert (group_table, entry))
|
||||
xalloc_die ();
|
||||
}
|
||||
if (null_loc)
|
||||
free (loc);
|
||||
return entry;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------.
|
||||
| Change the current group to the one designated by the name, and create it |
|
||||
| if necessary. The location information is used for creation if available. |
|
||||
`--------------------------------------------------------------------------*/
|
||||
|
||||
void set_current_group (const uniqstr tag, location *loc)
|
||||
{
|
||||
for (symbol_list *l = current_prec_declaration; l; l = l->next)
|
||||
{
|
||||
sym_content *symb = l->content.sym->content;
|
||||
if (!current_group->symbol_list)
|
||||
current_group->symbol_list = symb;
|
||||
else
|
||||
{
|
||||
sym_content *sym = current_group->symbol_list;
|
||||
for (; sym->group_next; sym = sym->group_next)
|
||||
{}
|
||||
sym->group_next = symb;
|
||||
}
|
||||
}
|
||||
symbol_list_prec_free (current_prec_declaration);
|
||||
current_prec_declaration = NULL;
|
||||
current_group = symgroup_from_uniqstr (tag, loc);
|
||||
}
|
||||
|
||||
+99
-2
@@ -31,6 +31,8 @@
|
||||
# include "scan-code.h"
|
||||
# include "uniqstr.h"
|
||||
|
||||
typedef struct symbol_list symbol_list;
|
||||
|
||||
/*----------.
|
||||
| Symbols. |
|
||||
`----------*/
|
||||
@@ -62,6 +64,8 @@ typedef struct sym_content sym_content;
|
||||
When status are checked at the end, "declared" symbols are fine,
|
||||
"used" symbols trigger warnings, otherwise it's an error. */
|
||||
|
||||
typedef struct prec_node prec_node;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
/** Used in the input file for an unknown reason (error). */
|
||||
@@ -125,13 +129,21 @@ struct sym_content
|
||||
code_props props[CODE_PROPS_SIZE];
|
||||
|
||||
symbol_number number;
|
||||
location prec_location;
|
||||
|
||||
/* Not used anymore, to remove. */
|
||||
int prec;
|
||||
assoc assoc;
|
||||
|
||||
int user_token_number;
|
||||
|
||||
symbol_class class;
|
||||
status status;
|
||||
|
||||
/* The next element in the symbol precedence group. */
|
||||
sym_content *group_next;
|
||||
|
||||
/* The graph node containing all the precedence information for this
|
||||
symbol. */
|
||||
prec_node *prec_node;
|
||||
};
|
||||
|
||||
/** Undefined user number. */
|
||||
@@ -286,6 +298,91 @@ void print_precedence_warnings (void);
|
||||
|
||||
void register_assoc (graphid i, graphid j);
|
||||
|
||||
|
||||
/*------------------.
|
||||
| Groups of symbols |
|
||||
`------------------*/
|
||||
|
||||
#define DEFAULT_GROUP_NAME uniqstr_new ("__default__")
|
||||
|
||||
typedef struct symgroup symgroup;
|
||||
|
||||
struct symgroup
|
||||
{
|
||||
/** The name of the group. */
|
||||
uniqstr tag;
|
||||
|
||||
/** The list of symbols in the group. */
|
||||
sym_content * symbol_list;
|
||||
|
||||
location location;
|
||||
} ;
|
||||
|
||||
/** Get a dummy name for an anonymous group. */
|
||||
uniqstr new_anonymous_group_name (void);
|
||||
|
||||
/** Set the current group in the token precedence declaration to a new group
|
||||
* with this name */
|
||||
void set_current_group (const uniqstr name, location *loc);
|
||||
|
||||
/** Get or create the group by that name. The location information is used for
|
||||
* creation when available. */
|
||||
symgroup *
|
||||
symgroup_from_uniqstr (const uniqstr key, location *loc);
|
||||
|
||||
/** Check if there is a symbol precedence group by that name. */
|
||||
bool
|
||||
is_prec_group (const uniqstr key);
|
||||
|
||||
|
||||
/*----------------------------------.
|
||||
| Graph of precedence relationships |
|
||||
`----------------------------------*/
|
||||
|
||||
typedef struct prec_link prec_link;
|
||||
|
||||
struct prec_link
|
||||
{
|
||||
prec_node *target;
|
||||
bool transitive;
|
||||
prec_link *next;
|
||||
};
|
||||
|
||||
struct prec_node
|
||||
{
|
||||
symbol *symbol;
|
||||
/** Associativity for the symbol. */
|
||||
assoc assoc;
|
||||
location prec_location;
|
||||
prec_link *sons;
|
||||
prec_link *equals;
|
||||
};
|
||||
|
||||
typedef enum prec_rel_comparator prec_rel_comparator;
|
||||
|
||||
enum prec_rel_comparator
|
||||
{
|
||||
prec_equal,
|
||||
prec_superior,
|
||||
prec_superior_strict,
|
||||
};
|
||||
|
||||
/** Declare a precedence relationship between the symbols of the two lists,
|
||||
* as defined by the operator. */
|
||||
void
|
||||
declare_precedence_relation (symbol_list *l1, symbol_list *l2,
|
||||
prec_rel_comparator c, location loc);
|
||||
/** Return the list of symbols contained in the group. */
|
||||
symbol_list *
|
||||
expand_symbol_group (symgroup * group, location loc);
|
||||
|
||||
/** Check if s1 and s2 have the same precedence level. */
|
||||
bool is_prec_equal (prec_node * s1, prec_node * s2);
|
||||
|
||||
/** Check if from > to . */
|
||||
bool is_prec_superior (prec_node * from, prec_node * to);
|
||||
|
||||
|
||||
/*-----------------.
|
||||
| Semantic types. |
|
||||
`-----------------*/
|
||||
|
||||
@@ -17,6 +17,152 @@
|
||||
|
||||
AT_BANNER([[Conflicts.]])
|
||||
|
||||
## ----------------- ##
|
||||
## Precedence groups ##
|
||||
## ----------------- ##
|
||||
|
||||
# Sample use case of precedence groups and relations, working.
|
||||
|
||||
AT_SETUP([Precedence groups])
|
||||
|
||||
AT_DATA_GRAMMAR([[input.y]],
|
||||
[[%token CARET "^"
|
||||
%token NUM BOOL '^' OR AND
|
||||
|
||||
%left '+' '-'
|
||||
%gprec {
|
||||
%right CARET
|
||||
}
|
||||
%gprec boolean {
|
||||
%left OR
|
||||
%left AND
|
||||
}
|
||||
%left '*' '/'
|
||||
|
||||
%precr boolean >> "^"
|
||||
%precr CARET > '*' '/' '-' '+'
|
||||
|
||||
%%
|
||||
|
||||
stmt:
|
||||
exp
|
||||
| bool_exp
|
||||
|
||||
exp:
|
||||
NUM
|
||||
| exp '+' exp
|
||||
| exp '-' exp
|
||||
| exp '*' exp
|
||||
| exp '/' exp
|
||||
| exp "^" exp
|
||||
|
||||
bool_exp:
|
||||
BOOL
|
||||
| bool_exp AND bool_exp
|
||||
| bool_exp OR bool_exp
|
||||
| bool_exp CARET bool_exp
|
||||
]])
|
||||
|
||||
AT_BISON_CHECK([[--report=all -o input.c input.y]], 0, [])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
## -------------------------------- ##
|
||||
## Conflicting precedence relations ##
|
||||
## -------------------------------- ##
|
||||
|
||||
AT_SETUP([Conflicting precedence relations])
|
||||
|
||||
AT_DATA_GRAMMAR([[input.y]],
|
||||
[[%token TOKEN
|
||||
%precedence A
|
||||
%precedence B
|
||||
%precedence C
|
||||
%precedence D E
|
||||
|
||||
%gprec group {
|
||||
%precedence F
|
||||
%precedence G
|
||||
}
|
||||
|
||||
%precr B = C
|
||||
%precr A > B
|
||||
%precr C > B
|
||||
%precr F > G
|
||||
%precr F > A
|
||||
%%
|
||||
exp:
|
||||
TOKEN
|
||||
| exp A exp
|
||||
| exp B exp
|
||||
| exp C exp
|
||||
| exp D exp
|
||||
| exp E exp
|
||||
| exp F exp
|
||||
| exp G exp
|
||||
]])
|
||||
|
||||
AT_BISON_CHECK([[-Wall -o input.c input.y]], 0, [],
|
||||
[[input.y:20.10: warning: contradicting declaration: B = C is in conflict with the previous declaration: B > C [-Wprecedence]
|
||||
input.y:21.10: warning: contradicting declaration: A > B is in conflict with the previous declaration: A < B [-Wprecedence]
|
||||
input.y:22.10: warning: contradicting declaration: C > B is in conflict with the previous declaration: C = B [-Wprecedence]
|
||||
input.y:23.10: warning: contradicting declaration: F > G is in conflict with the previous declaration: F < G [-Wprecedence]
|
||||
input.y: warning: 27 shift/reduce conflicts [-Wconflicts-sr]
|
||||
]])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
## ------------------------------ ##
|
||||
## Duplicate precedence relations ##
|
||||
## ------------------------------ ##
|
||||
|
||||
AT_SETUP([Duplicate precedence relations])
|
||||
|
||||
AT_DATA_GRAMMAR([[input.y]],
|
||||
[[%token TOKEN
|
||||
%precedence A
|
||||
%precedence B
|
||||
%precedence C
|
||||
%precedence D E
|
||||
|
||||
%gprec group {
|
||||
%precedence F
|
||||
%precedence G
|
||||
}
|
||||
|
||||
%precr D = E
|
||||
%precr B > A
|
||||
%precr C > B
|
||||
%precr G > F
|
||||
%precr F > A
|
||||
%precr C > group
|
||||
%precr C > F
|
||||
%%
|
||||
exp:
|
||||
TOKEN
|
||||
| exp A exp
|
||||
| exp B exp
|
||||
| exp C exp
|
||||
| exp D exp
|
||||
| exp E exp
|
||||
| exp F exp
|
||||
| exp G exp
|
||||
]])
|
||||
|
||||
AT_BISON_CHECK([[-Wall -o input.c input.y]], 0, [],
|
||||
[[input.y:20.10: warning: duplicate declaration of the precedence relationship D = E [-Wprecedence]
|
||||
input.y:20.10: warning: duplicate declaration of the precedence relationship E = D [-Wprecedence]
|
||||
input.y:21.10: warning: duplicate declaration of the precedence relationship B > A [-Wprecedence]
|
||||
input.y:22.10: warning: duplicate declaration of the precedence relationship C > B [-Wprecedence]
|
||||
input.y:23.10: warning: duplicate declaration of the precedence relationship G > F [-Wprecedence]
|
||||
input.y:26.10: warning: duplicate declaration of the precedence relationship C > F [-Wprecedence]
|
||||
input.y: warning: 23 shift/reduce conflicts [-Wconflicts-sr]
|
||||
]])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
|
||||
|
||||
## ------------------------- ##
|
||||
## Token declaration order. ##
|
||||
## ------------------------- ##
|
||||
|
||||
+4
-4
@@ -484,7 +484,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
||||
|
||||
NAME [reduce using rule 152 (opt_variable)]
|
||||
'$' [reduce using rule 152 (opt_variable)]
|
||||
@@ -5379,7 +5379,7 @@
|
||||
@@ -5385,7 +5385,7 @@
|
||||
156 | . '$' non_post_simp_exp
|
||||
|
||||
NAME shift, and go to state 9
|
||||
@@ -493,7 +493,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
||||
|
||||
NAME [reduce using rule 152 (opt_variable)]
|
||||
'$' [reduce using rule 152 (opt_variable)]
|
||||
@@ -5399,7 +5399,7 @@
|
||||
@@ -5405,7 +5405,7 @@
|
||||
156 | . '$' non_post_simp_exp
|
||||
|
||||
NAME shift, and go to state 9
|
||||
@@ -502,7 +502,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
||||
|
||||
NAME [reduce using rule 152 (opt_variable)]
|
||||
'$' [reduce using rule 152 (opt_variable)]
|
||||
@@ -6214,7 +6214,7 @@
|
||||
@@ -6220,7 +6220,7 @@
|
||||
156 | . '$' non_post_simp_exp
|
||||
|
||||
NAME shift, and go to state 9
|
||||
@@ -511,7 +511,7 @@ dnl - 61 -> 328: reduce -> shift on '*', '/', and '%'
|
||||
|
||||
NAME [reduce using rule 152 (opt_variable)]
|
||||
'$' [reduce using rule 152 (opt_variable)]
|
||||
@@ -11099,3 +11099,274 @@
|
||||
@@ -11117,3 +11117,274 @@
|
||||
45 statement: LEX_FOR '(' opt_exp semi opt_nls exp semi opt_nls opt_exp r_paren opt_nls statement .
|
||||
|
||||
$default reduce using rule 45 (statement)
|
||||
|
||||
+1
-2
@@ -64,14 +64,13 @@ AT_CHECK([[$PERL -pi -e 's/\\(\d{3})/chr(oct($1))/ge' input.y || exit 77]])
|
||||
AT_BISON_CHECK([input.y], [1], [],
|
||||
[[input.y:1.1-2: error: invalid characters: '\0\001\002\377?'
|
||||
input.y:3.1: error: invalid character: '?'
|
||||
input.y:4.14: error: invalid character: '}'
|
||||
input.y:4.14: error: syntax error, unexpected }
|
||||
input.y:5.1: error: invalid character: '%'
|
||||
input.y:5.2: error: invalid character: '&'
|
||||
input.y:6.1-17: error: invalid directive: '%a-does-not-exist'
|
||||
input.y:7.1: error: invalid character: '%'
|
||||
input.y:7.2: error: invalid character: '-'
|
||||
input.y:8.1-9.0: error: missing '%}' at end of file
|
||||
input.y:8.1-9.0: error: syntax error, unexpected %{...%}
|
||||
]])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
+1
-2
@@ -405,14 +405,13 @@ default: 'a' }
|
||||
|
||||
AT_BISON_CHECK([input.y], [1], [],
|
||||
[[input.y:2.1: error: invalid character: '?'
|
||||
input.y:3.14: error: invalid character: '}'
|
||||
input.y:3.14: error: syntax error, unexpected }
|
||||
input.y:4.1: error: invalid character: '%'
|
||||
input.y:4.2: error: invalid character: '&'
|
||||
input.y:5.1-17: error: invalid directive: '%a-does-not-exist'
|
||||
input.y:6.1: error: invalid character: '%'
|
||||
input.y:6.2: error: invalid character: '-'
|
||||
input.y:7.1-8.0: error: missing '%}' at end of file
|
||||
input.y:7.1-8.0: error: syntax error, unexpected %{...%}
|
||||
]])
|
||||
|
||||
AT_CLEANUP
|
||||
|
||||
Reference in New Issue
Block a user