Basil

Contents:
Home
Synopsis
Config file format
Grammar file format
Symbol attributes
Getting started
Visitors
Simulator
Examples
Download

Visitors

The syntax tree constructed by the parser is designed to be traversed with visitors. The syntax tree can be traversed as it is being formed (in the parser onNode function), or when the syntax tree is fully constructed.

A visitor must derive from the generated base visitor class (or another visitor). The base visitor class contains a virtual visit function for each node defined in the grammar file. The constructor of the class takes one bool argument. If the argument is true, then the visitor is slippery. The argument is defaulted to true.

For example, consider the grammar

# start rule
[ClassSpecNode]
start -> CLASS IDENT COLON ident-list-opt

# ident list opt
ident-list-opt -> ident-list
ident-list-opt ->    

# ident list
ident-list -> ident
[$ ListNode]
ident-list -> ident-list COMMA ident

# ident
[IdentNode]
ident -> IDENT
The generated base visitor class is
// NodeVisitor.lzz
//

$hdr
#include "basl_Visitor.h"
$end

$src
#include "Nonterm.h"
$end

// node forward declarations
class ClassSpecNode;
class ListNode;
class IdentNode;

// base visitor
class NodeVisitor : public basl::Visitor
{
  // true if slippery
  bool m_slippery;

public:
  // constructor
  inline NodeVisitor (bool slippery = true)
    : m_slippery (slippery)
  {
  }

  // start -> CLASS IDENT COLON ident-list-opt
  virtual void visit (ClassSpecNode & node) const
  {
  }

  // ident-list -> ident-list COMMA ident
  virtual void visit (ListNode & node) const
  {
    if (m_slippery)
    {
      node.visitChildren (* this);
    }
  }

  // ident -> IDENT
  virtual void visit (IdentNode & node) const
  {
  }
}
The visit functions take a non-const reference to a node. This allows the visit functions to attach attributes to the nodes.

Visitors can be developed very easily with lzz. For example, the visitor below collects the identifier lexemes in the above grammar.

// get identifiers
struct GetIdentListVisitor (IdentVector & ident_set) : NodeVisitor (true)
{
  // ident -> IDENT
  void visit (IdentNode & node) const
  {
    ident_set.push_back (node.getIDENT ().getLexeme ());
  }
}
This visitor could be called when visiting ClassSpecNode:
// my visitor
struct MyVisitor () : NodeVistor ()
{
  // start -> CLASS IDENT COLON ident-list-opt
  void visit (ClassSpecNode & node) const
  {
    IdentVector ident_set;
    node.getIdentListOpt ().accept (GetIdentListVisitor (ident_set));
  }
}
The member functions of the generated nonterminals that return the right-hand side nodes are named after the corresponding symbols. For a token, the get function is named "get" followed by the name of the token (in upper case), with all '-' characters substituted with '_'. For a nonterminal, the get function is named "get" followed by the name of the symbol, with all '-' and '_' characters removed and the words separated by those characters capitalized. The table below contains some examples.
Symbol name Generated get function name
ident getIdent
ident-list getIdentList
ident_list getIdentList
TIMES getTIMES
TIMES-TIMES getTIMES_TIMES
TIMES_TIMES getTIMES_TIMES
A number starting with 1 is appended to any names that are the same.

A get function will return one of three types:

basl::Token
This is the return type if the symbol is a token, or if the symbol is a nonterminal and it can represent only tokens. For example, in StartNode, defined in the grammar below, the functions getA and getB will have the return the type basl::Token.
[StartNode] start -> A b
b ->
b -> B
b -> BB
The function basl::Token::isSet () returns true if a token is set.

basl::Nonterm
This is the return type if the symbol is a nonterminal and it can represent only nonterminal nodes, or the nonterminal can only be epsilon. For example, in StartNode, defined in the grammar below, the functions getA and getB will have the return type basl::Nonterm.
[StartNode] start -> a b
a ->
[A1Node] a -> A
[A2Node] a -> A A
b ->
The function basl::Nonterm::isSet () returns true if a nonterminal is set.

basl::Node
This is the return type otherwise. This type encapsulates both a token and a nonterminal. The functions basl::Node::getToken () and basl::Node::getNonterm () return a node's token and nonterminal nodes respectively.
The basl::Nonterm::accept function accepts a visitor. This function initiates the double dispatch mechanism on a nonterminal, but only if the nonterminal is set.

Attributes can be attached to nonterminal nodes only. The functions basl::Nonterm::setAttrib (AttribPtr const &) and basl::Nonterm::getAttrib () can be used to set and get the attribute of a nonterminal node respectively. basl::Attrib is defined in basl_Attrib.lzz:

// basl_Attrib.lzz
//

$hdr
$end

$src
$end

// basil
namespace basl
{
  // Attrib
  class Attrib
  {
  public:
    // constructor
    Attrib ()
    {
    }

    // destructor
    virtual ~ Attrib ()
    {
    }
  }
}
The type basl::AttribPtr is a typedef to reference counted smart pointer.