syntax: introducing %precr to add specific precedence relations

It is now possible to add specific precedence relations between two symbols,
or a symbol and a group, with the %precr keyword:

%gprec arith {
  %left '+' '-'
  %left '*' '/'
}
%gprec boolean {
  %left OR
  %left AND
}
%right '^'

%precr '^' > arith
%precr OR AND > '^'

Here, the symbol ^ is of higher priority than the the ones in arith, but of
lower priority than both OR and AND. OR and '+', for example, cannot be
compared.

* src/parse-gram.y, src/scan-gram.l: Lexer and grammar implementation of
%precr.
* src/symtab.c, src/symtab.h: implementation of the addition of single link
precedence relationships.
This commit is contained in:
Valentin Tolmer
2013-08-01 14:53:49 +02:00
parent f8a710c6f4
commit d8de391c38
4 changed files with 131 additions and 1 deletions

View File

@@ -131,6 +131,7 @@
%token PERCENT_PREC "%prec" %token PERCENT_PREC "%prec"
%token PERCENT_DPREC "%dprec" %token PERCENT_DPREC "%dprec"
%token PERCENT_GPREC "%gprec" %token PERCENT_GPREC "%gprec"
%token PERCENT_PRECR "%precr"
%token PERCENT_MERGE "%merge" %token PERCENT_MERGE "%merge"
/*----------------------. /*----------------------.
@@ -176,6 +177,7 @@
%token PIPE "|" %token PIPE "|"
%token PROLOGUE "%{...%}" %token PROLOGUE "%{...%}"
%token SEMICOLON ";" %token SEMICOLON ";"
%token GT ">"
%token TAG "<tag>" %token TAG "<tag>"
%token TAG_ANY "<*>" %token TAG_ANY "<*>"
%token TAG_NONE "<>" %token TAG_NONE "<>"
@@ -217,7 +219,13 @@
%union {named_ref *named_ref;} %union {named_ref *named_ref;}
%type <named_ref> named_ref.opt %type <named_ref> named_ref.opt
%type <uniqstr> prec_group_name.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. | | %param. |
`---------*/ `---------*/
@@ -370,6 +378,7 @@ params:
grammar_declaration: grammar_declaration:
precedence_declaration precedence_declaration
| precedence_group_declaration | precedence_group_declaration
| precedence_relation_declaration
| symbol_declaration | symbol_declaration
| "%start" symbol | "%start" symbol
{ {
@@ -513,6 +522,46 @@ tag.opt:
| TAG { current_type = $1; tag_seen = true; } | 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. */ /* Just like symbols.1 but accept INT for the sake of POSIX. */
symbols.prec: symbols.prec:
symbol.prec symbol.prec

View File

@@ -243,6 +243,7 @@ eqopt ([[:space:]]*=)?
"%parse-param" RETURN_PERCENT_PARAM(parse); "%parse-param" RETURN_PERCENT_PARAM(parse);
"%prec" return PERCENT_PREC; "%prec" return PERCENT_PREC;
"%precedence" return PERCENT_PRECEDENCE; "%precedence" return PERCENT_PRECEDENCE;
"%precr" return PERCENT_PRECR;
"%printer" return PERCENT_PRINTER; "%printer" return PERCENT_PRINTER;
"%pure-parser" RETURN_PERCENT_FLAG("api.pure"); "%pure-parser" RETURN_PERCENT_FLAG("api.pure");
"%require" return PERCENT_REQUIRE; "%require" return PERCENT_REQUIRE;
@@ -278,6 +279,7 @@ eqopt ([[:space:]]*=)?
"|" return PIPE; "|" return PIPE;
";" return SEMICOLON; ";" return SEMICOLON;
"}" return RBRACE; "}" return RBRACE;
">" return GT;
{id} { {id} {
val->uniqstr = uniqstr_new (yytext); val->uniqstr = uniqstr_new (yytext);

View File

@@ -240,6 +240,55 @@ add_prec_equal_link (prec_node *s1, prec_node *s2, bool transitive,
} }
/* 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 | | 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 | | precedence links. SAME_LINE is true if the symbol was declared in the |
@@ -358,6 +407,7 @@ symbol_new (uniqstr tag, location loc)
res->tag = tag; res->tag = tag;
res->location = loc; res->location = loc;
res->alias = NULL; res->alias = NULL;
res->content = sym_content_new (res); res->content = sym_content_new (res);
res->is_alias = false; res->is_alias = false;
@@ -1503,6 +1553,20 @@ symgroup_new (const uniqstr tag, location loc)
return group; 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 | | 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 | | is created and inserted in the table, with the location information |

View File

@@ -330,6 +330,11 @@ void set_current_group (const uniqstr name, location *loc);
symgroup * symgroup *
symgroup_from_uniqstr (const uniqstr key, location *loc); 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 | | Graph of precedence relationships |
`----------------------------------*/ `----------------------------------*/
@@ -361,6 +366,16 @@ enum prec_rel_comparator
prec_superior, prec_superior,
prec_superior_strict, 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. */ /** Check if s1 and s2 have the same precedence level. */
bool is_prec_equal (prec_node * s1, prec_node * s2); bool is_prec_equal (prec_node * s1, prec_node * s2);