From b6aec69654f43ea6757201dc9dcc6a354d3efbea Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis <karakasis@cscs.ch> Date: Fri, 21 Oct 2016 20:24:08 -0400 Subject: [PATCH] Support for units syntax within state block. --- data/test.mod | 4 ++-- modcc/blocks.hpp | 46 ++++++++++++++++++------------------- modcc/module.cpp | 4 ++-- modcc/parser.cpp | 32 ++++++++++++++++++++------ tests/modcc/test_parser.cpp | 9 ++++---- 5 files changed, 57 insertions(+), 38 deletions(-) diff --git a/data/test.mod b/data/test.mod index d7403c79..0f95e717 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 b9e41bfa..3ea27608 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 6001e1b4..c9f749e9 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 0b4b8106..ffa498c0 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 1e590d83..2d09e570 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 -- GitLab