diff --git a/data/test.mod b/data/test.mod
index d7403c791f390dacf899fe6a32429ad4b5f4096d..bbb8ce41cf9ba422e9513a4387819ef957d1ba4c 100644
--- a/data/test.mod
+++ b/data/test.mod
@@ -10,7 +10,7 @@ NEURON  {
 }
 
 STATE {
-    h
+    h (nA)
     m r
 }
 
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..3e8fe3d77da7c2e2be24493cc04c00393f111f03 100644
--- a/modcc/module.cpp
+++ b/modcc/module.cpp
@@ -31,15 +31,21 @@ Module::Module(std::string const& fname)
     buffer_[size] = 0; // append \0 to terminate string
 }
 
-Module::Module(std::vector<char> const& buffer)
-{
+Module::Module(std::vector<char> const& buffer) {
     buffer_ = buffer;
 
     // add \0 to end of buffer if not already present
-    if(buffer_[buffer_.size()-1] != 0)
+    if (buffer_[buffer_.size()-1] != 0)
         buffer_.push_back(0);
 }
 
+Module::Module(const char* buffer, size_t count) {
+    auto size = std::distance(buffer, std::find(buffer, buffer+count, '\0'));
+    buffer_.reserve(size+1);
+    buffer_.insert(buffer_.end(), buffer, buffer+size);
+    buffer_.push_back(0);
+}
+
 std::vector<Module::symbol_ptr>&
 Module::procedures() {
     return procedures_;
@@ -612,7 +618,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 +629,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/module.hpp b/modcc/module.hpp
index f427d870ebc1cb770e8e424349d4d140892b3f45..1cd1cfe89b4e31d1bb18e3e3cedb6e173d049ee2 100644
--- a/modcc/module.hpp
+++ b/modcc/module.hpp
@@ -15,6 +15,7 @@ public :
 
     Module(std::string const& fname);
     Module(std::vector<char> const& buffer);
+    Module(const char* buffer, size_t count);
 
     std::vector<char> const& buffer() const {
         return buffer_;
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/modcc/parser.hpp b/modcc/parser.hpp
index 6768749df46e51181ade05d0d6acb1d4dddbe7c6..b55bede17e698aa9d790211ddbee5a54f90ba56a 100644
--- a/modcc/parser.hpp
+++ b/modcc/parser.hpp
@@ -39,9 +39,6 @@ public:
         return error_string_;
     }
 
-private:
-    Module *module_;
-
     // functions for parsing descriptive blocks
     // these are called in the first pass, and do not
     // construct any AST information
@@ -52,6 +49,9 @@ private:
     void parse_assigned_block();
     void parse_title();
 
+private:
+    Module *module_;
+
     std::vector<Token> comma_separated_identifiers();
     std::vector<Token> unit_description();
 
@@ -69,4 +69,3 @@ private:
     bool expect(tok, const char *str="");
     bool expect(tok, std::string const& str);
 };
-
diff --git a/tests/modcc/test_parser.cpp b/tests/modcc/test_parser.cpp
index 1e590d8315a5d95b3e93555d5ddbd2dbd9ad00be..1edfe1a9ad61a0e3837dbddba2877037fb30aee2 100644
--- a/tests/modcc/test_parser.cpp
+++ b/tests/modcc/test_parser.cpp
@@ -15,7 +15,7 @@ TEST(Parser, full_file) {
 }
 
 TEST(Parser, procedure) {
-    std::vector< const char*> calls =
+    std::vector<const char*> calls =
 {
 "PROCEDURE foo(x, y) {"
 "  LOCAL a\n"
@@ -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
@@ -561,3 +562,39 @@ TEST(Parser, parse_binop) {
             std::cout << red("error") << p.error_message() << std::endl;
     }
 }
+
+TEST(Parser, parse_state_block) {
+    std::vector<const char*> state_blocks = {
+        "STATE {\n"
+        "    h\n"
+        "    m r\n"
+        "}",
+        "STATE {\n"
+        "    h (nA)\n"
+        "    m r\n"
+        "}",
+        "STATE {\n"
+        "    h (nA)\n"
+        "    m (nA) r\n"
+        "}",
+        "STATE {\n"
+        "    h (nA)\n"
+        "    m r (uA)\n"
+        "}",
+        "STATE {\n"
+        "    h (nA)\n"
+        "    m (nA) r (uA)\n"
+        "}"
+    };
+
+    for (auto const& str: state_blocks) {
+        Module m(str, sizeof(str));
+        Parser p(m, false);
+        p.parse_state_block();
+        EXPECT_EQ(lexerStatus::happy, p.status());
+        if (p.status() == lexerStatus::error) {
+            std::cout << str << "\n"
+                      << red("error") << p.error_message() << "\n";
+        }
+    }
+}