Vadim Zaytsev aka @grammarware

GraSs: A Taxonomy of Grammar Smells


Organisation
global problems
Navigation
problems with navigating through the grammar
Structure
harmful relationships among grammar components

Convention
violations of visual policies
Notation
metalanguage-related
Parsing
parsing techniques related smells
Duplication
the same fragment is repeated

Underuse
inferior substitutes are used instead of an available feature
Overspec
the same constraint specified through several means
Priorities
not present or circular
Singleton
trivial choice, sequence or conjunction
Combo
double modifier creates an ambiguity
Chant
comments cover up bad code
Deprecated
the use of a feature that is no longer welcome
Exotic
too idiosyncratic notational features decrease portability

Priorities Edit!

Related smells: Cross-module Cycle, No Layers, Stovepipe System

A typical layered grammar [IFM-2009-LammelZ] treats highly recursive language constructs with sophisticated priorities by explicitly encoding them in a long streak of nonterminals (ISO/IEC 14882:1998(E), Programming languages — C++, extracted):


expression ::=
    assignment-expr
    expression "," assignment-expr
assignment-expr ::=
    conditional-expr
    logical-or-expr assignment-operator assignment-expr
    throw-expr
conditional-expr ::=
    logical-or-expr
    logical-or-expr "?" expression ":" assignment-expr
logical-or-expr ::=
    logical-and-expr
    logical-or-expr "||" logical-and-expr
logical-and-expr ::=
    inclusive-or-expr
    logical-and-expr "&&" inclusive-or-expr
inclusive-or-expr ::=
    exclusive-or-expr
    inclusive-or-expr "|" exclusive-or-expr
exclusive-or-expr ::=
    and-expr
    exclusive-or-expr "^" and-expr
and-expr ::=
    equality-expr
    and-expr "&" equality-expr
equality-expr ::=
    relational-expr
    equality-expr "==" relational-expr
    equality-expr "!=" relational-expr
relational-expr ::=
    shift-expr
    relational-expr "<" shift-expr
    relational-expr ">" shift-expr
shift-expr ::=
    additive-expr
    shift-expr "<<" additive-expr
    shift-expr ">>" additive-expr
additive-expr ::=
    multiplicative-expr
    additive-expr "+" multiplicative-expr
    additive-expr "-" multiplicative-expr
multiplicative-expr ::=
    pm-expr
    multiplicative-expr "*" pm-expr
    multiplicative-expr "/" pm-expr
    multiplicative-expr "%" pm-expr
pm-expr ::=
    cast-expr
    pm-expr ".*" cast-expr
    pm-expr "->*" cast-expr
cast-expr ::=
    unary-expr
    "(" type-id ")" cast-expr
unary-expr ::=
    postfix-expr
    "++" cast-expr
    "--" cast-expr
    unary-operator cast-expr
    "sizeof" unary-expr
    "sizeof" "(" type-id ")"
    new-expr
    delete-expr
postfix-expr ::=
    primary-expr
    postfix-expr "[" expression "]"
    postfix-expr "(" expression-list? ")"
    postfix-expr "++"
    postfix-expr "--"
primary-expr ::=
    literal
    "this"
    "(" expression ")"
    id-expr

This example belongs to an obviously complicated programming language (C++), but the abundance of extra nonterminals increases this complexity. A cleaner way would have been to merge all definitions into one nonterminal (or a few conceptually grouped ones) and to define priorities between them. Priorities can be specified in a separate notation or by using ordered choices. Once these priorities are defined, there can be other variations of this smell in their specifications as such: circular dependencies, missing elements, etc.


The GraSs taxonomy is a joint effort maintained by Dr. Vadim Zaytsev a.k.a. @grammarware. Page last updated in March 2021.
XHTML 1.1 CSS 3