From b6bd831b3ee41f2e84ddc47ef2b152baea55ad6e Mon Sep 17 00:00:00 2001 From: thorstenhater <24411438+thorstenhater@users.noreply.github.com> Date: Thu, 28 May 2020 15:00:35 +0200 Subject: [PATCH] Parser improvements for modcc (#1050) * Add ranges in STATE blocks of the form FROM ... TO ... * Unit test for the above * Add type check for <..., ...> ranges * Add units in procedure argument lists * Unit test for the above. --- modcc/parser.cpp | 59 +++++++++++++++++++++++++++++++-- modcc/parser.hpp | 1 + modcc/token.cpp | 2 ++ modcc/token.hpp | 1 + test/unit-modcc/test_parser.cpp | 6 +++- 5 files changed, 66 insertions(+), 3 deletions(-) diff --git a/modcc/parser.cpp b/modcc/parser.cpp index 55960aa3..753b0b80 100644 --- a/modcc/parser.cpp +++ b/modcc/parser.cpp @@ -399,9 +399,16 @@ void Parser::parse_state_block() { } parm.token = token_; - //state_block.state_variables.push_back(token_.spelling); get_token(); + if(token_.type == tok::from) { + // silently skips from/to + from_to_description(); + if (status_ == lexerStatus::error) { + return; + } + } + // get unit parameters if (line == location_.line && token_.type == tok::lparen) { parm.units = unit_description(); @@ -763,6 +770,10 @@ std::pair<Token, Token> Parser::range_description() { } get_token(); + if(token_.type != tok::integer) { + error(pprintf("range description must be <int, int>, found '%'", token_)); + return {}; + } lb = token_; get_token(); @@ -772,6 +783,10 @@ std::pair<Token, Token> Parser::range_description() { } get_token(); + if(token_.type != tok::integer) { + error(pprintf("range description must be <int, int>, found '%'", token_)); + return {}; + } ub = token_; get_token(); @@ -784,6 +799,39 @@ std::pair<Token, Token> Parser::range_description() { return {lb, ub}; } +std::pair<Token, Token> Parser::from_to_description() { + Token lb, ub; + + if(token_.type != tok::from) { + error(pprintf("range description must be of form FROM <int> TO <int>, found '%'", token_)); + return {}; + } + + get_token(); + if(token_.type != tok::integer) { + error(pprintf("range description must be of form FROM <int> TO <int>, found '%'", token_)); + return {}; + } + lb = token_; + + get_token(); + if(token_.type != tok::to) { + error(pprintf("range description must be of form FROM <int> TO <int>, found '%'", token_)); + return {}; + } + + get_token(); + if(token_.type != tok::integer) { + error(pprintf("range description must be of form FROM <int> TO <int>, found '%'", token_)); + return {}; + } + ub = token_; + + get_token(); + return {lb, ub}; +} + + // Returns a prototype expression for a function or procedure call // Takes an optional argument that allows the user to specify the // name of the prototype, which is used for prototypes where the name @@ -804,7 +852,6 @@ expression_ptr Parser::parse_prototype(std::string name=std::string()) { // check for an argument list enclosed in parenthesis (...) // return a prototype with an empty argument list if not found if( token_.type != tok::lparen ) { - //return make_expression<PrototypeExpression>(identifier.location, identifier.spelling, {}); return expression_ptr{new PrototypeExpression(identifier.location, identifier.spelling, {})}; } @@ -822,6 +869,14 @@ expression_ptr Parser::parse_prototype(std::string name=std::string()) { get_token(); // consume the identifier + // args may have a unit attached + if(token_.type == tok::lparen) { + unit_description(); + if(status_ == lexerStatus::error) { + return {}; + } + } + // look for a comma if(!(token_.type == tok::comma || token_.type==tok::rparen)) { error( "expected a comma or closing parenthesis, found '" diff --git a/modcc/parser.hpp b/modcc/parser.hpp index 49512f7e..a250ee8c 100644 --- a/modcc/parser.hpp +++ b/modcc/parser.hpp @@ -69,6 +69,7 @@ private: std::string value_literal(); int value_signed_integer(); std::pair<Token, Token> range_description(); + std::pair<Token, Token> from_to_description(); /// build the identifier list void add_variables_to_symbols(); diff --git a/modcc/token.cpp b/modcc/token.cpp index 8348a6e8..30ed8def 100644 --- a/modcc/token.cpp +++ b/modcc/token.cpp @@ -54,6 +54,8 @@ static Keyword keywords[] = { {"COMPARTMENT", tok::compartment}, {"METHOD", tok::method}, {"STEADYSTATE", tok::steadystate}, + {"FROM", tok::from}, + {"TO", tok::to}, {"if", tok::if_stmt}, {"IF", tok::if_stmt}, {"else", tok::else_stmt}, diff --git a/modcc/token.hpp b/modcc/token.hpp index 3c5344a4..21648dcd 100644 --- a/modcc/token.hpp +++ b/modcc/token.hpp @@ -64,6 +64,7 @@ enum class tok { solve, method, steadystate, threadsafe, global, point_process, + from, to, // prefix binary operators min, max, diff --git a/test/unit-modcc/test_parser.cpp b/test/unit-modcc/test_parser.cpp index 11e6e51b..10952756 100644 --- a/test/unit-modcc/test_parser.cpp +++ b/test/unit-modcc/test_parser.cpp @@ -93,7 +93,7 @@ TEST(Parser, procedure) { " y = a + b *c + a + b\n" "}" , - "PROCEDURE trates(v) {\n" + "PROCEDURE trates(v (mV)) {\n" " LOCAL qt\n" " qt=q10^((celsius-22)/10)\n" " minf=1-1/(1+exp((v-vhalfm)/km))\n" @@ -685,6 +685,10 @@ TEST(Parser, parse_state_block) { "STATE {\n" " h (nA)\n" " m (nA) r (uA)\n" + "}", + "STATE {\n" + " h FROM 0 TO 1\n" + " m r (uA)\n" "}" }; -- GitLab