User Guide
symbol_table.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2023 Blue Brain Project, EPFL.
3  * See the top-level LICENSE file for details.
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #pragma once
9 
10 /**
11  * \dir
12  * \brief Symbol table implementation
13  *
14  * \file
15  * \brief Implement classes for representing symbol table at block and file scope
16  */
17 
18 #include <map>
19 #include <memory>
20 #include <vector>
21 
22 #include "symtab/symbol.hpp"
23 
24 namespace nmodl {
25 namespace symtab {
26 
27 
28 /**
29  * @defgroup sym_tab Symbol Table Implementation
30  * @brief All %Symbol Table implementation details
31  *
32  * @{
33  */
34 
35 /**
36  * \brief Represent symbol table for a NMODL block
37  *
38  * Symbol Table is used to track information about every block construct
39  * encountered in the nmodl. In NMODL, block constructs are NEURON, PARAMETER
40  * NET_RECEIVE etc. Each block is considered a new scope.
41  *
42  * NMODL supports nested block definitions (i.e. nested blocks). One specific
43  * example of this is INITIAL block in NET_RECEIVE block. In this case we need
44  * multiple scopes for single top level block of NMODL. In the future if we
45  * enable block level scopes, we will need symbol tables per block. Hence we are
46  * implementing BlockSymbolTable which stores all symbol table information for
47  * specific NMODL block. Note that each BlockSymbolTable implementation is
48  * recursive because while symbol lookup we have to search first into
49  * local/current block. If lookup is unsuccessful then we have to traverse
50  * parent blocks until the end.
51  *
52  * \todo
53  * - Revisit when clone method is used and implementation of copy
54  * constructor
55  * - Name may not require as we have added AST node
56  */
57 class SymbolTable {
58  /**
59  * \class Table
60  * \brief Helper class for implementing symbol table
61  *
62  * Table is used to store information about every block construct
63  * encountered in the nmodl file. Each symbol has name but for fast lookup,
64  * we create map with the associated name.
65  *
66  * \todo Re-implement pretty printing
67  */
68  class Table {
69  /// number of tables
70  static int counter;
71 
72  public:
73  /// map of symbol name and associated symbol for faster lookup
74  std::vector<std::shared_ptr<Symbol>> symbols;
75 
76  /// insert new symbol into table
77  void insert(const std::shared_ptr<Symbol>& symbol);
78 
79  /// check if symbol with given name exist
80  std::shared_ptr<Symbol> lookup(const std::string& name) const;
81 
82  /// pretty print
83  void print(std::ostream& stream, std::string title, int indent) const;
84  };
85 
86  /// name of the block
87  const std::string symtab_name;
88 
89  /// table holding all symbols in the current block
91 
92  /// pointer to ast node for which current symbol table created
93  const ast::Ast* node = nullptr;
94 
95  /// true if current symbol table is global. blocks like NEURON,
96  /// PARAMETER defines global variables and hence they go into
97  /// single global symbol table
98  bool global = false;
99 
100  /// pointer to the symbol table of parent block in the mod file
101  SymbolTable* parent = nullptr;
102 
103  /// symbol table for each enclosing block in the current nmodl block
104  /// construct. for example, for every block statement (like if, while,
105  /// for) within function we append new symbol table. note that this is
106  /// also required for nested blocks like INITIAL in NET_RECEIVE.
107  std::map<std::string, std::shared_ptr<SymbolTable>> children;
108 
109  public:
110  /// \name Ctor & dtor
111  /// \{
112 
113  SymbolTable(std::string name, const ast::Ast* node, bool global = false)
114  : symtab_name(std::move(name))
115  , node(node)
116  , global(global) {}
117 
118  SymbolTable(const SymbolTable& table);
119 
120  /// \}
121 
122 
123  /// \name Getter
124  /// \{
125 
126  SymbolTable* get_parent_table() const noexcept {
127  return parent;
128  }
129 
130  std::string get_parent_table_name() const {
131  return parent ? parent->name() : "None";
132  }
133 
134  /**
135  * get variables
136  *
137  * \param with variables with properties. 0 matches everything
138  * \param without variables without properties. 0 matches nothing
139  *
140  * The two different behaviors for 0 depend on the fact that we get
141  * get variables with ALL the with properties and without ANY of the
142  * without properties
143  */
144  std::vector<std::shared_ptr<Symbol>> get_variables(
147 
148  /**
149  * get variables with properties
150  *
151  * \param properties variables with properties. -1 matches everything
152  * \param all all/any
153  */
154  std::vector<std::shared_ptr<Symbol>> get_variables_with_properties(
155  syminfo::NmodlType properties,
156  bool all = false) const;
157 
158  std::vector<std::shared_ptr<Symbol>> get_variables_with_status(syminfo::Status status,
159  bool all = false) const;
160 
161  /// \}
162 
163  /// convert symbol table to string
164  std::string to_string() const {
165  std::ostringstream s;
166  print(s, 0);
167  return s.str();
168  }
169 
170  const std::string& name() const noexcept {
171  return symtab_name;
172  }
173 
174  bool global_scope() const noexcept {
175  return global;
176  }
177 
178  void insert(const std::shared_ptr<Symbol>& symbol) {
179  table.insert(symbol);
180  }
181 
183  parent = block;
184  }
185 
186  int symbol_count() const {
187  return table.symbols.size();
188  }
189 
190  /**
191  * Create a copy of symbol table
192  * \todo Revisit the usage as tokens will be pointing to old nodes
193  */
194  SymbolTable* clone() const {
195  return new SymbolTable(*this);
196  }
197 
198  /// check if symbol with given name exist in the current table (but not in parents)
199  std::shared_ptr<Symbol> lookup(const std::string& name) const {
200  return table.lookup(name);
201  }
202 
203  /// check if symbol with given name exist in the current table (including all parents)
204  std::shared_ptr<Symbol> lookup_in_scope(const std::string& name) const;
205 
206  /// check if currently we are visiting global scope node
207  bool under_global_scope();
208 
209  /// insert new symbol table as one of the children block
210  void insert_table(const std::string& name, const std::shared_ptr<SymbolTable>& table);
211 
212  void print(std::ostream& ss, int level) const;
213 
214  std::string title() const;
215 
216  std::string position() const;
217 
218  /// check if procedure/function with given name is defined
219  bool is_method_defined(const std::string& name) const;
220 };
221 
222 /**
223  * \brief Hold top level (i.e. global) symbol table for mod file
224  *
225  * symtab::SymbolTable is sufficient to hold information about all symbols in
226  * the mod file. It might be sufficient to keep track of global symbol tables
227  * and local symbol tables. But we construct symbol table using visitor pass. In
228  * this case we visit ast and recursively create symbol table for each block
229  * scope. In this case, ModelSymbolTable provides high level interface to build
230  * symbol table as part of visitor.
231  *
232  * \note
233  * - For included mod file it's not clear yet whether we need to maintain
234  * separate ModelSymbolTable.
235  * - See command project in compiler teaching course for details
236  *
237  * \todo Unique name should be based on location. Use ModToken to get position.
238  */
240  /// symbol table for mod file (always top level symbol table)
241  std::shared_ptr<SymbolTable> symtab;
242 
243  /// current symbol table being constructed
245 
246  /// return unique name by appending some counter value
247  std::string get_unique_name(const std::string& name, ast::Ast* node, bool is_global);
248 
249  /// name of top level global symbol table
250  const std::string GLOBAL_SYMTAB_NAME = "NMODL_GLOBAL";
251 
252  /// default mode of symbol table: if update is true then we update exisiting
253  /// symbols otherwise we throw away old table and construct new one
254  bool update_table = false;
255 
256  /// current order of variable being defined
258 
259  /// insert symbol table in update mode
260  std::shared_ptr<Symbol> update_mode_insert(const std::shared_ptr<Symbol>& symbol);
261 
262  void emit_message(const std::shared_ptr<Symbol>& first,
263  const std::shared_ptr<Symbol>& second,
264  bool redefinition);
265 
266  void update_order(const std::shared_ptr<Symbol>& present_symbol,
267  const std::shared_ptr<Symbol>& new_symbol);
268 
269  public:
270  /// entering into new nmodl block
271  SymbolTable* enter_scope(const std::string& name,
272  ast::Ast* node,
273  bool global,
274  SymbolTable* node_symtab);
275 
276  /// leaving current nmodl block
277  void leave_scope();
278 
279  /// insert new symbol into current table
280  std::shared_ptr<Symbol> insert(const std::shared_ptr<Symbol>& symbol);
281 
282  /// lookup for symbol into current as well as all parent tables
283  std::shared_ptr<Symbol> lookup(const std::string& name);
284 
285  /// re-initialize members to throw away old symbol tables
286  /// this is required as symtab visitor pass runs multiple time
287  void set_mode(bool update_mode);
288 
289  /// pretty print
290  void print(std::ostream& ostr) const {
291  symtab->print(ostr, 0);
292  }
293 };
294 
295 /** @} */ // end of sym_tab
296 
297 } // namespace symtab
298 } // namespace nmodl
nmodl::symtab::SymbolTable::parent
SymbolTable * parent
pointer to the symbol table of parent block in the mod file
Definition: symbol_table.hpp:101
nmodl::symtab::SymbolTable::Table::lookup
std::shared_ptr< Symbol > lookup(const std::string &name) const
check if symbol with given name exist
Definition: symbol_table.cpp:40
nmodl::symtab::SymbolTable::to_string
std::string to_string() const
convert symbol table to string
Definition: symbol_table.hpp:164
symbol.hpp
Implement class to represent a symbol in Symbol Table.
nmodl::ast::Ast
Base class for all Abstract Syntax Tree node types.
Definition: ast.hpp:69
nmodl::symtab::SymbolTable::global_scope
bool global_scope() const noexcept
Definition: symbol_table.hpp:174
nmodl::symtab::SymbolTable::set_parent_table
void set_parent_table(SymbolTable *block)
Definition: symbol_table.hpp:182
nmodl::symtab::SymbolTable::get_parent_table
SymbolTable * get_parent_table() const noexcept
Definition: symbol_table.hpp:126
nmodl::symtab::ModelSymbolTable::insert
std::shared_ptr< Symbol > insert(const std::shared_ptr< Symbol > &symbol)
insert new symbol into current table
Definition: symbol_table.cpp:286
nmodl::symtab::SymbolTable::SymbolTable
SymbolTable(std::string name, const ast::Ast *node, bool global=false)
Definition: symbol_table.hpp:113
nmodl::symtab::ModelSymbolTable::symtab
std::shared_ptr< SymbolTable > symtab
symbol table for mod file (always top level symbol table)
Definition: symbol_table.hpp:241
nmodl::symtab::SymbolTable::symtab_name
const std::string symtab_name
name of the block
Definition: symbol_table.hpp:87
nmodl::symtab::SymbolTable::Table::insert
void insert(const std::shared_ptr< Symbol > &symbol)
insert new symbol into table
Definition: symbol_table.cpp:30
nmodl
encapsulates code generation backend implementations
Definition: ast_common.hpp:26
nmodl::symtab::SymbolTable::name
const std::string & name() const noexcept
Definition: symbol_table.hpp:170
nmodl::symtab::ModelSymbolTable::print
void print(std::ostream &ostr) const
pretty print
Definition: symbol_table.hpp:290
nmodl::symtab::SymbolTable::get_variables_with_properties
std::vector< std::shared_ptr< Symbol > > get_variables_with_properties(syminfo::NmodlType properties, bool all=false) const
get variables with properties
Definition: symbol_table.cpp:88
nmodl::symtab::SymbolTable::position
std::string position() const
Definition: symbol_table.cpp:67
nmodl::symtab::ModelSymbolTable::leave_scope
void leave_scope()
leaving current nmodl block
Definition: symbol_table.cpp:420
nmodl::symtab::syminfo::Status
Status
state during various compiler passes
Definition: symbol_properties.hpp:54
nmodl::symtab::SymbolTable::clone
SymbolTable * clone() const
Create a copy of symbol table.
Definition: symbol_table.hpp:194
nmodl::symtab::ModelSymbolTable::definition_order
int definition_order
current order of variable being defined
Definition: symbol_table.hpp:257
nmodl::symtab::SymbolTable::get_variables
std::vector< std::shared_ptr< Symbol > > get_variables(syminfo::NmodlType with=syminfo::NmodlType::empty, syminfo::NmodlType without=syminfo::NmodlType::empty) const
get variables
Definition: symbol_table.cpp:107
nmodl::symtab::ModelSymbolTable::emit_message
void emit_message(const std::shared_ptr< Symbol > &first, const std::shared_ptr< Symbol > &second, bool redefinition)
Emit warning message for shadowing definition or throw an exception if variable is being redefined in...
Definition: symbol_table.cpp:199
nmodl::symtab::SymbolTable::children
std::map< std::string, std::shared_ptr< SymbolTable > > children
symbol table for each enclosing block in the current nmodl block construct.
Definition: symbol_table.hpp:107
nmodl::symtab::SymbolTable::is_method_defined
bool is_method_defined(const std::string &name) const
check if procedure/function with given name is defined
Definition: symbol_table.cpp:56
nmodl::symtab::SymbolTable::title
std::string title() const
construct title for symbol table
Definition: symbol_table.cpp:501
nmodl::symtab::ModelSymbolTable::update_mode_insert
std::shared_ptr< Symbol > update_mode_insert(const std::shared_ptr< Symbol > &symbol)
insert symbol table in update mode
Definition: symbol_table.cpp:244
nmodl::symtab::ModelSymbolTable::current_symtab
SymbolTable * current_symtab
current symbol table being constructed
Definition: symbol_table.hpp:244
nmodl::symtab::SymbolTable::insert_table
void insert_table(const std::string &name, const std::shared_ptr< SymbolTable > &table)
insert new symbol table as one of the children block
Definition: symbol_table.cpp:79
nmodl::symtab::ModelSymbolTable::lookup
std::shared_ptr< Symbol > lookup(const std::string &name)
lookup for symbol into current as well as all parent tables
Definition: symbol_table.cpp:173
nmodl::symtab::SymbolTable::get_variables_with_status
std::vector< std::shared_ptr< Symbol > > get_variables_with_status(syminfo::Status status, bool all=false) const
Definition: symbol_table.cpp:120
nmodl::symtab::syminfo::NmodlType::empty
@ empty
nmodl::symtab::SymbolTable::Table
Helper class for implementing symbol table.
Definition: symbol_table.hpp:68
nmodl::symtab::SymbolTable::get_parent_table_name
std::string get_parent_table_name() const
Definition: symbol_table.hpp:130
nmodl::symtab::SymbolTable
Represent symbol table for a NMODL block.
Definition: symbol_table.hpp:57
nmodl::symtab::SymbolTable::global
bool global
true if current symbol table is global.
Definition: symbol_table.hpp:98
nmodl::symtab::SymbolTable::insert
void insert(const std::shared_ptr< Symbol > &symbol)
Definition: symbol_table.hpp:178
nmodl::symtab::SymbolTable::Table::print
void print(std::ostream &stream, std::string title, int indent) const
pretty print
Definition: symbol_table.cpp:453
nmodl::symtab::ModelSymbolTable::enter_scope
SymbolTable * enter_scope(const std::string &name, ast::Ast *node, bool global, SymbolTable *node_symtab)
entering into new nmodl block
Definition: symbol_table.cpp:377
nmodl::symtab::SymbolTable::node
const ast::Ast * node
pointer to ast node for which current symbol table created
Definition: symbol_table.hpp:93
nmodl::symtab::ModelSymbolTable::set_mode
void set_mode(bool update_mode)
re-initialize members to throw away old symbol tables this is required as symtab visitor pass runs mu...
Definition: symbol_table.cpp:435
nmodl::symtab::syminfo::NmodlType
NmodlType
NMODL variable properties.
Definition: symbol_properties.hpp:116
nmodl::symtab::SymbolTable::symbol_count
int symbol_count() const
Definition: symbol_table.hpp:186
nmodl::symtab::ModelSymbolTable
Hold top level (i.e.
Definition: symbol_table.hpp:239
nmodl::symtab::ModelSymbolTable::GLOBAL_SYMTAB_NAME
const std::string GLOBAL_SYMTAB_NAME
name of top level global symbol table
Definition: symbol_table.hpp:250
nmodl::symtab::SymbolTable::Table::counter
static int counter
number of tables
Definition: symbol_table.hpp:70
nmodl::symtab::ModelSymbolTable::update_order
void update_order(const std::shared_ptr< Symbol > &present_symbol, const std::shared_ptr< Symbol > &new_symbol)
Definition: symbol_table.cpp:271
nmodl::symtab::SymbolTable::print
void print(std::ostream &ss, int level) const
Definition: symbol_table.cpp:510
nmodl::symtab::SymbolTable::lookup
std::shared_ptr< Symbol > lookup(const std::string &name) const
check if symbol with given name exist in the current table (but not in parents)
Definition: symbol_table.hpp:199
nmodl::symtab::SymbolTable::table
Table table
table holding all symbols in the current block
Definition: symbol_table.hpp:90
nmodl::symtab::ModelSymbolTable::update_table
bool update_table
default mode of symbol table: if update is true then we update exisiting symbols otherwise we throw a...
Definition: symbol_table.hpp:254
nmodl::symtab::ModelSymbolTable::get_unique_name
std::string get_unique_name(const std::string &name, ast::Ast *node, bool is_global)
return unique name by appending some counter value
Definition: symbol_table.cpp:358
nmodl::symtab::SymbolTable::lookup_in_scope
std::shared_ptr< Symbol > lookup_in_scope(const std::string &name) const
check if symbol with given name exist in the current table (including all parents)
Definition: symbol_table.cpp:164
nmodl::symtab::SymbolTable::Table::symbols
std::vector< std::shared_ptr< Symbol > > symbols
map of symbol name and associated symbol for faster lookup
Definition: symbol_table.hpp:74
nmodl::symtab::SymbolTable::under_global_scope
bool under_global_scope()
check if currently we are visiting global scope node
Definition: symbol_table.cpp:148