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