User Guide
symbol_table.cpp
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 #include <utility>
9 
10 #include "ast/ast.hpp"
11 #include "ast/ast_decl.hpp"
12 #include "symtab/symbol_table.hpp"
13 #include "utils/logger.hpp"
14 #include "utils/table_data.hpp"
15 
16 namespace nmodl {
17 namespace symtab {
18 
19 using namespace ast;
20 using syminfo::NmodlType;
21 using syminfo::Status;
22 
23 
24 int SymbolTable::Table::counter = 0; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
25 
26 /**
27  * Insert symbol into current symbol table. There are certain
28  * cases where we were getting re-insertion errors.
29  */
30 void SymbolTable::Table::insert(const std::shared_ptr<Symbol>& symbol) {
31  const auto& name = symbol->get_name();
32  if (lookup(name) != nullptr) {
33  throw std::runtime_error("Trying to re-insert symbol " + name);
34  }
35  symbol->set_id(counter++);
36  symbols.push_back(symbol);
37 }
38 
39 
40 std::shared_ptr<Symbol> SymbolTable::Table::lookup(const std::string& name) const {
41  for (const auto& symbol: symbols) {
42  if (symbol->get_name() == name) {
43  return symbol;
44  }
45  }
46  return nullptr;
47 }
48 
49 
51  : symtab_name{table.name()}
52  , global{table.global_scope()}
53  , node{nullptr}
54  , parent{nullptr} {}
55 
56 bool SymbolTable::is_method_defined(const std::string& name) const {
57  const auto& symbol = lookup_in_scope(name);
58  if (symbol == nullptr) {
59  return false;
60  }
61  const auto& nodes = symbol->get_nodes_by_type(
62  {AstNodeType::FUNCTION_BLOCK, AstNodeType::PROCEDURE_BLOCK});
63  return !nodes.empty();
64 }
65 
66 
67 std::string SymbolTable::position() const {
68  auto token = node->get_token();
69  std::string position;
70  if (token != nullptr) {
71  position = token->position();
72  } else {
74  }
75  return position;
76 }
77 
78 
79 void SymbolTable::insert_table(const std::string& name, const std::shared_ptr<SymbolTable>& table) {
80  if (children.find(name) != children.end()) {
81  throw std::runtime_error("Trying to re-insert SymbolTable " + name);
82  }
83  children[name] = std::move(table);
84 }
85 
86 
87 /// return all symbol having any of the provided properties
88 std::vector<std::shared_ptr<Symbol>> SymbolTable::get_variables_with_properties(
89  NmodlType properties,
90  bool all) const {
91  std::vector<std::shared_ptr<Symbol>> variables;
92  for (auto& symbol: table.symbols) {
93  if (all) {
94  if (symbol->has_all_properties(properties)) {
95  variables.push_back(symbol);
96  }
97  } else {
98  if (symbol->has_any_property(properties)) {
99  variables.push_back(symbol);
100  }
101  }
102  }
103  return variables;
104 }
105 
106 /// return all symbol which has all "with" properties and none of the "without" properties
107 std::vector<std::shared_ptr<Symbol>> SymbolTable::get_variables(NmodlType with,
108  NmodlType without) const {
109  const auto& variables = get_variables_with_properties(with, true);
110  std::decay_t<decltype(variables)> result;
111  for (auto& variable: variables) {
112  if (!variable->has_any_property(without)) {
113  result.push_back(variable);
114  }
115  }
116  return result;
117 }
118 
119 std::vector<std::shared_ptr<Symbol>> SymbolTable::get_variables_with_status(Status status,
120  bool all) const {
121  std::vector<std::shared_ptr<Symbol>> variables;
122  for (auto& symbol: table.symbols) {
123  if (all) {
124  if (symbol->has_all_status(status)) {
125  variables.push_back(symbol);
126  }
127  } else {
128  if (symbol->has_any_status(status)) {
129  variables.push_back(symbol);
130  }
131  }
132  }
133  return variables;
134 }
135 
136 
137 /**
138  * Check if current symbol table is in global scope
139  *
140  * We create program scope at the top level and it has global scope.
141  * It contains neuron variables like t, dt, celsius etc. Then each
142  * nmodl block defining variables are added under this program's symbol
143  * table. Hence there are multiple levels of global scopes. In this
144  * helper function we make sure current block as well as it's parent are
145  * under global scopes.
146  */
148  bool global_scope = global;
149  auto parent_table = parent;
150 
151  // traverse all parent blocks to make sure everyone is global
152  while (global_scope && (parent_table != nullptr)) {
153  parent_table = parent_table->parent;
154  if (parent_table != nullptr) {
155  global_scope = parent_table->global_scope();
156  }
157  }
158  return global_scope;
159 }
160 
161 
162 /// lookup for symbol in current scope as well as all parents
163 std::shared_ptr<Symbol> SymbolTable::lookup_in_scope(const std::string& name) const {
164  auto symbol = table.lookup(name);
165  if (!symbol && (parent != nullptr)) {
166  symbol = parent->lookup_in_scope(name);
167  }
168  return symbol;
169 }
170 
171 /// lookup in current symtab as well as all parent symbol tables
172 std::shared_ptr<Symbol> ModelSymbolTable::lookup(const std::string& name) {
173  if (current_symtab == nullptr) {
174  throw std::logic_error("Lookup with previous symtab = nullptr ");
175  }
176 
177  auto symbol = current_symtab->lookup(name);
178 
179  if (!symbol) {
180  // check into all parent symbol tables
181  auto parent = current_symtab->get_parent_table();
182  while (parent != nullptr) {
183  symbol = parent->lookup(name);
184  if (symbol) {
185  break;
186  }
187  parent = parent->get_parent_table();
188  }
189  }
190  return symbol;
191 }
192 
193 
194 // show symbol table related message for debugging purposes
195 void ModelSymbolTable::emit_message(const std::shared_ptr<Symbol>& first,
196  const std::shared_ptr<Symbol>& second,
197  bool redefinition) {
198  const auto& nodes = first->get_nodes();
199  const auto& name = first->get_name();
200  auto properties = to_string(second->get_properties());
201  std::string type = "UNKNOWN";
202  if (!nodes.empty()) {
203  // Here we take the first one, because this is a redefinition
204  type = nodes.front()->get_node_type_name();
205  }
206 
207  if (redefinition) {
208  auto msg = fmt::format("Re-declaration of {} [{}] <{}> in {} with one in {}",
209  name,
210  type,
211  properties,
212  current_symtab->name(),
213  second->get_scope());
214  throw std::runtime_error(msg);
215  }
216  logger->debug("SYMTAB :: {} [{}] in {} shadows <{}> definition in {}",
217  name,
218  type,
219  current_symtab->name(),
220  properties);
221 }
222 
223 
224 /**
225  * Insert symbol in the update mode i.e. symbol table is previously created
226  * and we are adding new symbol table.
227  *
228  * We set status as "created" because missing symbol means the variable is
229  * added by some intermediate passes.
230  *
231  * Consider inlining pass which creates a block like:
232  *
233  * DERIVATIVE states() {
234  * LOCAL xx
235  * {
236  * LOCAL xx
237  * }
238  * }
239  *
240  * Second xx is not added into symbol table (and hence not visible
241  * to other passes like local renamer). In this case we have to do
242  * local lookup in the current symtab and insert if doesn't exist.
243  */
244 std::shared_ptr<Symbol> ModelSymbolTable::update_mode_insert(
245  const std::shared_ptr<Symbol>& symbol) {
246  symbol->set_scope(current_symtab->name());
247  symbol->mark_created();
248 
249  const auto& name = symbol->get_name();
250  auto search_symbol = lookup(name);
251 
252  /// if no symbol found then safe to insert
253  if (search_symbol == nullptr) {
254  current_symtab->insert(symbol);
255  return symbol;
256  }
257 
258  /// for global scope just combine properties
259  if (current_symtab->global_scope()) {
260  search_symbol->add_properties(symbol->get_properties());
261  return search_symbol;
262  }
263 
264  /// insert into current block's symbol table
265  if (current_symtab->lookup(name) == nullptr) {
266  current_symtab->insert(symbol);
267  }
268  return symbol;
269 }
270 
271 void ModelSymbolTable::update_order(const std::shared_ptr<Symbol>& present_symbol,
272  const std::shared_ptr<Symbol>& new_symbol) {
273  const auto& symbol = (present_symbol != nullptr) ? present_symbol : new_symbol;
274 
275  const bool is_parameter = new_symbol->has_any_property(NmodlType::param_assign);
276  const bool is_assigned_definition = new_symbol->has_any_property(
277  NmodlType::assigned_definition);
278 
279  if (symbol->get_definition_order() == -1) {
280  if (is_parameter || is_assigned_definition) {
281  symbol->set_definition_order(definition_order++);
282  }
283  }
284 }
285 
286 std::shared_ptr<Symbol> ModelSymbolTable::insert(const std::shared_ptr<Symbol>& symbol) {
287  if (current_symtab == nullptr) {
288  throw std::logic_error("Can not insert symbol without entering scope");
289  }
290 
291  const auto& search_symbol = lookup(symbol->get_name());
292  update_order(search_symbol, symbol);
293 
294  /// handle update mode insertion
295  if (update_table) {
296  return update_mode_insert(symbol);
297  }
298 
299  symbol->set_scope(current_symtab->name());
300 
301  // if no symbol found then safe to insert
302  if (search_symbol == nullptr) {
303  current_symtab->insert(symbol);
304  return symbol;
305  }
306 
307  /**
308  * For global symbol tables, same variable can appear in multiple
309  * nmodl "global" blocks. It's an error if it appears multiple times
310  * in the same nmodl block. To check this we compare symbol properties
311  * which are bit flags. If they are not same that means, we have to
312  * add new properties to existing symbol. If the properties are same
313  * that means symbol are duplicate.
314  */
315  if (current_symtab->global_scope()) {
316  if (search_symbol->has_any_property(symbol->get_properties())) {
317  emit_message(symbol, search_symbol, true);
318  } else {
319  search_symbol->add_properties(symbol->get_properties());
320  for (const auto& n: symbol->get_nodes()) {
321  search_symbol->add_node(n);
322  }
323  }
324  return search_symbol;
325  }
326 
327  /**
328  * For non-global scopes, check if symbol that we found has same
329  * scope name as symbol table. This means variable is being re-declared
330  * within the same scope. Otherwise, there is variable with same name
331  * in parent scopes and it will shadow the definition. In this case just
332  * emit the warning and insert the symbol.
333  *
334  * Note:
335  * We suppress the warning for the voltage since in most cases it is extern
336  * as well as argument and it is fine like that.
337  */
338  if (search_symbol->get_scope() == current_symtab->name()) {
339  emit_message(symbol, search_symbol, true);
340  } else {
341  /**
342  * Suppress warning for voltage since it is often extern and argument.
343  */
344  if (symbol->get_name() != "v") {
345  emit_message(symbol, search_symbol, false);
346  }
347  current_symtab->insert(symbol);
348  }
349  return symbol;
350 }
351 
352 
353 /**
354  * Some blocks can appear multiple times in the nmodl file. In order to distinguish
355  * them we simply append counter.
356  * \todo We should add position information to make name unique
357  */
358 std::string ModelSymbolTable::get_unique_name(const std::string& name, Ast* node, bool is_global) {
359  static int block_counter = 0;
360  std::string new_name(name);
361  if (is_global) {
362  new_name = GLOBAL_SYMTAB_NAME;
363  } else if (node->is_statement_block() || node->is_solve_block() || node->is_before_block() ||
364  node->is_after_block()) {
365  new_name += std::to_string(block_counter++);
366  }
367  return new_name;
368 }
369 
370 
371 /**
372  * Function callback at the entry of every block in nmodl file
373  * Every block starts a new scope and hence new symbol table is created.
374  * The same symbol table is returned so that visitor can store pointer to
375  * symbol table within a node.
376  */
378  Ast* node,
379  bool global,
380  SymbolTable* node_symtab) {
381  if (node == nullptr) {
382  throw std::runtime_error("Can't enter with empty node");
383  }
384 
385  /**
386  * All global blocks in mod file have same global symbol table. If there
387  * is already symbol table setup in global scope, return the same.
388  */
389  if (symtab && global) {
390  return symtab.get();
391  }
392 
393  /// statement block within global scope is part of global block itself
395  return symtab.get();
396  }
397 
398  if (node_symtab == nullptr || !update_table) {
399  const auto& new_name = get_unique_name(name, node, global);
400  auto new_symtab = std::make_shared<SymbolTable>(new_name, node, global);
401  new_symtab->set_parent_table(current_symtab);
402  if (symtab == nullptr) {
403  symtab = new_symtab;
404  }
405  if (current_symtab != nullptr) {
406  current_symtab->insert_table(new_name, new_symtab);
407  }
408  node_symtab = new_symtab.get();
409  }
410  current_symtab = node_symtab;
411  return current_symtab;
412 }
413 
414 
415 /**
416  * Callback at the exit of every block in nmodl file. When we reach
417  * program node (top most level), there is no parent block and hence
418  * use top level symbol table. Otherwise traverse back to parent.
419  */
421  if (current_symtab == nullptr) {
422  throw std::logic_error("Trying leave scope without entering");
423  }
425  if (current_symtab == nullptr) {
426  current_symtab = symtab.get();
427  }
428 }
429 
430 
431 /**
432  * Update mode is true if we want to re-use exisiting symbol table.
433  * If there is no symbol table constructed then we toggle mode.
434  */
435 void ModelSymbolTable::set_mode(bool update_mode) {
436  if (update_mode && symtab == nullptr) {
437  update_mode = false;
438  }
439  update_table = update_mode;
440  if (!update_table) {
441  symtab = nullptr;
442  current_symtab = nullptr;
443  }
444  definition_order = 0;
445 }
446 
447 
448 //=============================================================================
449 // Symbol table pretty-printing functions
450 //=============================================================================
451 
452 
453 void SymbolTable::Table::print(std::ostream& stream, std::string title, int indent) const {
455  using utils::TableData;
456  if (!symbols.empty()) {
457  TableData table;
458  table.title = std::move(title);
459  table.headers = {
460  "NAME", "# NODES", "PROPERTIES", "STATUS", "LOCATION", "VALUE", "# READS", "# WRITES"};
461  table.alignments = {text_alignment::left,
462  text_alignment::left,
463  text_alignment::left,
464  text_alignment::right,
465  text_alignment::right,
466  text_alignment::right};
467 
468  for (const auto& symbol: symbols) {
469  auto is_external = symbol->is_external_variable();
470  auto read_count = symbol->get_read_count();
471  auto write_count = symbol->get_write_count();
472 
473  // do not print external symbols which are not used in the current model
474  if (is_external && read_count == 0 && write_count == 0) {
475  continue;
476  }
477 
478  auto name = symbol->get_name();
479  if (symbol->is_array()) {
480  name += "[" + std::to_string(symbol->get_length()) + "]";
481  }
482  const auto& position = symbol->get_token().position();
483  const auto& properties = syminfo::to_string(symbol->get_properties());
484  const auto status = syminfo::to_string(symbol->get_status());
485  const auto reads = std::to_string(symbol->get_read_count());
486  const auto nodes = std::to_string(symbol->get_nodes().size());
487  std::string value;
488  const auto& sym_value = symbol->get_value();
489  if (sym_value) {
490  value = std::to_string(*sym_value);
491  }
492  auto writes = std::to_string(symbol->get_write_count());
493  table.rows.push_back({name, nodes, properties, status, position, value, reads, writes});
494  }
495  table.print(stream, indent);
496  }
497 }
498 
499 
500 /// construct title for symbol table
501 std::string SymbolTable::title() const {
502  const auto& node_type = node->get_node_type_name();
503  const auto& name = symtab_name + " [" + node_type + " IN " + get_parent_table_name() + "] ";
504  const auto& location = "POSITION : " + position();
505  const auto scope = global ? "GLOBAL" : "LOCAL";
506  return name + location + " SCOPE : " + scope;
507 }
508 
509 
510 void SymbolTable::print(std::ostream& ss, int level) const {
511  table.print(ss, title(), level);
512 
513  /// when current symbol table is empty, the children
514  /// can be printed from the same indentation level
515  /// (this is to avoid unnecessary empty indentations)
516  auto next_level = level;
517  if (table.symbols.empty()) {
518  next_level--;
519  }
520 
521  /// recursively print all children tables
522  for (const auto& item: children) {
523  if (item.second->symbol_count() >= 0) {
524  (item.second)->print(ss, ++next_level);
525  next_level--;
526  }
527  }
528 }
529 
530 } // namespace symtab
531 } // 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::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::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
ast_decl.hpp
THIS FILE IS GENERATED AT BUILD TIME AND SHALL NOT BE EDITED.
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
symbol_table.hpp
Implement classes for representing symbol table at block and file scope.
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::logger
logger_type logger
Definition: logger.cpp:34
nmodl::symtab::ModelSymbolTable::definition_order
int definition_order
current order of variable being defined
Definition: symbol_table.hpp:257
nmodl::ModToken::position
std::string position() const
Return position of the token as string.
Definition: modtoken.cpp:14
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)
Definition: symbol_table.cpp:195
nmodl::utils::TableData
Class to construct and pretty-print tabular data.
Definition: table_data.hpp:36
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::ast::Ast::get_node_type_name
virtual std::string get_node_type_name() const =0
Return type (ast::AstNodeType) of ast node as std::string.
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
table_data.hpp
Implement generic table data structure.
nmodl::symtab::syminfo::to_string
std::string to_string(const T &obj)
Definition: symbol_properties.hpp:282
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:172
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:119
nmodl::ast::Ast::get_token
virtual const ModToken * get_token() const
Return associated token for the AST node.
Definition: ast.cpp:36
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
ast.hpp
Auto generated AST classes declaration.
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::stringutils::text_alignment
text_alignment
text alignment when printing in the tabular form
Definition: string_utils.hpp:35
nmodl::ast::Ast::is_statement_block
virtual bool is_statement_block() const noexcept
Check if the ast node is an instance of ast::StatementBlock.
Definition: ast.cpp:130
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
logger.hpp
Implement logger based on spdlog library.
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::ast::Ast::is_solve_block
virtual bool is_solve_block() const noexcept
Check if the ast node is an instance of ast::SolveBlock.
Definition: ast.cpp:148
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::ast::Ast::is_before_block
virtual bool is_before_block() const noexcept
Check if the ast node is an instance of ast::BeforeBlock.
Definition: ast.cpp:152
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::ast::Ast::is_after_block
virtual bool is_after_block() const noexcept
Check if the ast node is an instance of ast::AfterBlock.
Definition: ast.cpp:154
nmodl::ModToken
Represent token returned by scanner.
Definition: modtoken.hpp:50
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:163
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:147