diff --git a/data/test.mod b/data/test.mod index d7403c791f390dacf899fe6a32429ad4b5f4096d..0f95e7179e48240b43d407a8c654e530672e6c86 100644 --- a/data/test.mod +++ b/data/test.mod @@ -10,8 +10,8 @@ NEURON { } STATE { - h - m r + h (mA) + m (mV) r (S) } UNITS { diff --git a/modcc/blocks.hpp b/modcc/blocks.hpp index b9e41bfa3d2fb1963691abae539f4ad94d45de2c..3ea276085f0f05c9f8b36f3e13d7424ddc7c15f7 100644 --- a/modcc/blocks.hpp +++ b/modcc/blocks.hpp @@ -26,6 +26,28 @@ enum class moduleKind { density }; +typedef std::vector<Token> unit_tokens; +struct Id { + Token token; + std::string value; // store the value as a string, not a number : empty + // string == no value + unit_tokens units; + + Id(Token const& t, std::string const& v, unit_tokens const& u) + : token(t), value(v), units(u) + {} + + Id() {} + + bool has_value() const { + return value.size()>0; + } + + std::string const& name() const { + return token.spelling; + } +}; + // information stored in a NEURON {} block in mod file. struct NeuronBlock { bool threadsafe = false; @@ -42,7 +64,7 @@ struct NeuronBlock { // information stored in a NEURON {} block in mod file struct StateBlock { - std::vector<std::string> state_variables; + std::vector<Id> state_variables; auto begin() -> decltype(state_variables.begin()) { return state_variables.begin(); } @@ -52,32 +74,11 @@ struct StateBlock { }; // information stored in a NEURON {} block in mod file -typedef std::vector<Token> unit_tokens; struct UnitsBlock { typedef std::pair<unit_tokens, unit_tokens> units_pair; std::vector<units_pair> unit_aliases; }; -struct Id { - Token token; - std::string value; // store the value as a string, not a number : empty string == no value - unit_tokens units; - - Id(Token const& t, std::string const& v, unit_tokens const& u) - : token(t), value(v), units(u) - {} - - Id() {} - - bool has_value() const { - return value.size()>0; - } - - std::string const& name() const { - return token.spelling; - } -}; - // information stored in a NEURON {} block in mod file struct ParameterBlock { std::vector<Id> parameters; @@ -164,4 +165,3 @@ inline std::ostream& operator<< (std::ostream& os, AssignedBlock const& A) { return os; } - diff --git a/modcc/module.cpp b/modcc/module.cpp index 6001e1b458f8cf16ffa488ca10ceb4e46268787e..c9f749e9ea7a89b1c0dabfa205d03062a3a55111 100644 --- a/modcc/module.cpp +++ b/modcc/module.cpp @@ -612,7 +612,7 @@ void Module::add_variables_to_symbols() { // add state variables for(auto const &var : state_block()) { - VariableExpression *id = new VariableExpression(Location(), var); + VariableExpression *id = new VariableExpression(Location(), var.name()); id->state(true); // set state to true // state variables are private @@ -623,7 +623,7 @@ void Module::add_variables_to_symbols() { id->range(rangeKind::range); // always a range id->access(accessKind::readwrite); - symbols_[var] = symbol_ptr{id}; + symbols_[var.name()] = symbol_ptr{id}; } // add the parameters diff --git a/modcc/parser.cpp b/modcc/parser.cpp index 0b4b81068ed22111b6c28ed04313d245ce613f4a..ffa498c08f50e4b0b1c2d7a6a3b8370c4e8c38de 100644 --- a/modcc/parser.cpp +++ b/modcc/parser.cpp @@ -368,17 +368,35 @@ void Parser::parse_state_block() { return; } - // there are no use cases for curly brace in a STATE block, so we don't have to count them - // we have to get the next token before entering the loop to handle the case of - // an empty block {} + // there are no use cases for curly brace in a STATE block, so we don't have + // to count them we have to get the next token before entering the loop to + // handle the case of an empty block {} get_token(); - while(token_.type!=tok::rbrace) { + while(token_.type!=tok::rbrace && token_.type != tok::eof) { + int line = location_.line; + Id parm; + if(token_.type != tok::identifier) { - error(pprintf("'%' is not a valid name for a state variable", token_.spelling)); + error(pprintf("'%' is not a valid name for a state variable", + token_.spelling)); return; } - state_block.state_variables.push_back(token_.spelling); + + parm.token = token_; + //state_block.state_variables.push_back(token_.spelling); get_token(); + + // get unit parameters + if (line == location_.line && token_.type == tok::lparen) { + parm.units = unit_description(); + if (status_ == lexerStatus::error) { + error(pprintf("STATUS block unexpected symbol '%s'", + token_.spelling)); + return; + } + } + + state_block.state_variables.push_back(parm); } // add this state block information to the module @@ -505,7 +523,7 @@ void Parser::parse_parameter_block() { parm_exit: // only write error message if one hasn't already been logged by the lexer if(!success && status_==lexerStatus::happy) { - error(pprintf("PARAMETER block unexpected symbol '%'", token_.spelling)); + error(pprintf("PARAMETER block unexpected symbol '%s'", token_.spelling)); } return; } diff --git a/tests/modcc/test_parser.cpp b/tests/modcc/test_parser.cpp index 1e590d8315a5d95b3e93555d5ddbd2dbd9ad00be..2d09e5703fd2d2344c7f7ddc1da22560d146e3d3 100644 --- a/tests/modcc/test_parser.cpp +++ b/tests/modcc/test_parser.cpp @@ -550,10 +550,11 @@ TEST(Parser, parse_binop) { EXPECT_NE(e, nullptr); EXPECT_EQ(p.status(), lexerStatus::happy); - // A loose tolerance of 1d-10 is required here because the eval() function uses long double - // for intermediate results (like constant folding in modparser). - // For expressions with transcendental operations this can see relatively large divergence between - // the double and long double results. + // A loose tolerance of 1d-10 is required here because the eval() + // function uses long double for intermediate results (like constant + // folding in modparser). For expressions with transcendental + // operations this can see relatively large divergence between the + // double and long double results. EXPECT_NEAR(eval(e.get()), test_case.second, 1e-10); // always print the compiler errors, because they are unexpected