Skip to content
Snippets Groups Projects
Commit 4587836e authored by Sam Yates's avatar Sam Yates
Browse files

Add lexing, parsing for KINETIC, reactions

* Make verbose printing in test_modcc a runtime flag `-v`.
* Show results of `lexer.parse()` in test_modcc when run with `-v`.
* Split numerical lexing and parsing into real and integer categories.
* Add expression parsing for KINETIC block and enclosed reaction
  expressions.

Note: does not parse CONSERVE yet; no test for KINETIC block
(reactions are covered though.)
parent bcbff7df
No related branches found
No related tags found
No related merge requests found
......@@ -877,7 +877,7 @@ public:
{}
std::string to_string() const override {
return pprintf("%%", coeff()->to_string(), ident()->to_string());
return pprintf("% %", coeff()->to_string(), ident()->to_string());
}
void semantic(std::shared_ptr<scope_type> scp) override;
expression_ptr clone() const override;
......
......@@ -119,6 +119,10 @@ Token Lexer::parse() {
t.type = tok::rbrace;
t.spelling += character();
return t;
case '~':
t.type = tok::tilde;
t.spelling += character();
return t;
case '=': {
t.spelling += character();
if(*current_=='=') {
......
......@@ -967,11 +967,18 @@ expression_ptr Parser::parse_stoich_expression() {
auto here = location_;
if(token_.type==tok::integer || token_.type==tok::identifier) {
terms.push_back(parse_stoich_term());
auto term = parse_stoich_term();
if (!term) return nullptr;
terms.push_back(std::move(term));
while(token_.type==tok::plus) {
get_token(); // consume plus
terms.push_back(parse_stoich_term());
auto term = parse_stoich_term();
if (!term) return nullptr;
terms.push_back(std::move(term));
}
}
......@@ -981,37 +988,48 @@ expression_ptr Parser::parse_stoich_expression() {
expression_ptr Parser::parse_reaction_expression() {
auto here = location_;
// consume tilde
get_token();
if(token_.type!=tok::tilde) {
error(pprintf("expected '%', found '%'", yellow("~"), yellow(token_.spelling)));
return nullptr;
}
get_token(); // consume tilde
expression_ptr lhs = parse_stoich_expression();
if (!lhs) return nullptr;
if(token_.type != tok::arrow) {
error(pprintf("expected '%', found '%'", yellow("<->"), yellow(token_.spelling)));
return nullptr;
}
get_token(); // consume arrow
expression_ptr rhs = parse_stoich_expression();
if (!rhs) return nullptr;
if(token_.type != tok::lparen) {
error(pprintf("expected '%', found '%'", yellow("("), yellow(token_.spelling)));
return nullptr;
}
get_token(); // consume lparen
expression_ptr fwd = parse_expression();
if (!fwd) return nullptr;
if(token_.type != tok::comma) {
error(pprintf("expected '%', found '%'", yellow(","), yellow(token_.spelling)));
return nullptr;
}
get_token(); // consume comma
expression_ptr rev = parse_expression();
if (!rev) return nullptr;
if(token_.type != tok::rparen) {
error(pprintf("expected '%', found '%'", yellow(")"), yellow(token_.spelling)));
return nullptr;
}
get_token(); // consume rparen
return make_expression<ReactionExpression>(here, std::move(lhs), std::move(rhs),
std::move(fwd), std::move(rev));
}
......
......@@ -2,10 +2,17 @@
* unit test driver
**************************************************************/
#include <cstring>
#include "test.hpp"
bool g_verbose_flag = false;
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
if (argc>1 && (!std::strcmp(argv[1],"-v") || !std::strcmp(argv[1],"--verbose"))) {
g_verbose_flag = true;
}
return RUN_ALL_TESTS();
}
......@@ -5,12 +5,9 @@
#include "parser.hpp"
#include "modccutil.hpp"
//#define VERBOSE_TEST
#ifdef VERBOSE_TEST
#define VERBOSE_PRINT(x) std::cout << (x) << std::endl;
#else
#define VERBOSE_PRINT(x)
#endif
extern bool g_verbose_flag;
#define VERBOSE_PRINT(x) (g_verbose_flag && std::cout << (x) << "\n")
inline expression_ptr parse_line_expression(std::string const& s) {
return Parser(s).parse_line_expression();
......
#include <cmath>
#include <iterator>
#include <utility>
#include "test.hpp"
#include "lexer.hpp"
//#define PRINT_LEX_STRING std::cout << "________________\n" << string << "\n________________\n";
#define PRINT_LEX_STRING
void verbose_print(const char* string) {
if (!g_verbose_flag) return;
std::cout << "________________\n" << string << "\n________________\n";
}
void verbose_print(const Token& token) {
if (!g_verbose_flag) return;
std::cout << "tok: " << token << "\n";
}
class VerboseLexer: public Lexer {
public:
template <typename... Args>
VerboseLexer(Args&&... args): Lexer(std::forward<Args>(args)...) {
if (g_verbose_flag) {
std::cout << "________________\n" << std::string(begin_, end_) << "\n________________\n";
}
}
Token parse() {
auto tok = Lexer::parse();
if (g_verbose_flag) {
std::cout << "token: " << tok << "\n";
}
return tok;
}
};
/**************************************************************
* lexer tests
......@@ -13,8 +39,7 @@
// test identifiers
TEST(Lexer, identifiers) {
char string[] = "_foo:\nbar, buzz f_zz";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
auto t1 = lexer.parse();
EXPECT_EQ(t1.type, tok::identifier);
......@@ -43,9 +68,8 @@ TEST(Lexer, identifiers) {
// test keywords
TEST(Lexer, keywords) {
char string[] = "NEURON UNITS SOLVE else TITLE CONDUCTANCE";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
char string[] = "NEURON UNITS SOLVE else TITLE CONDUCTANCE KINETIC";
VerboseLexer lexer(string, string+sizeof(string));
// should skip all white space and go straight to eof
auto t1 = lexer.parse();
......@@ -69,19 +93,22 @@ TEST(Lexer, keywords) {
EXPECT_NE(t5.type, tok::identifier);
EXPECT_EQ(t5.spelling, "TITLE");
auto t6 = lexer.parse();
EXPECT_EQ(t6.type, tok::conductance);
EXPECT_EQ(t6.spelling, "CONDUCTANCE");
auto t7 = lexer.parse();
EXPECT_EQ(t7.type, tok::conductance);
EXPECT_EQ(t7.spelling, "CONDUCTANCE");
EXPECT_EQ(t7.type, tok::kinetic);
EXPECT_EQ(t7.spelling, "KINETIC");
auto t6 = lexer.parse();
EXPECT_EQ(t6.type, tok::eof);
auto tlast = lexer.parse();
EXPECT_EQ(tlast.type, tok::eof);
}
// test white space
TEST(Lexer, whitespace) {
char string[] = " \t\v\f";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
// should skip all white space and go straight to eof
auto t1 = lexer.parse();
......@@ -91,8 +118,7 @@ TEST(Lexer, whitespace) {
// test new line
TEST(Lexer, newline) {
char string[] = "foo \n bar \n +\r\n-";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
// get foo
auto t1 = lexer.parse();
......@@ -123,9 +149,8 @@ TEST(Lexer, newline) {
// test operators
TEST(Lexer, symbols) {
char string[] = "+-/*, t= ^ h'";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
char string[] = "+-/*, t= ^ h'<->~";
VerboseLexer lexer(string, string+sizeof(string));
auto t1 = lexer.parse();
EXPECT_EQ(t1.type, tok::plus);
......@@ -161,13 +186,18 @@ TEST(Lexer, symbols) {
EXPECT_EQ(t10.type, tok::prime);
auto t11 = lexer.parse();
EXPECT_EQ(t11.type, tok::eof);
EXPECT_EQ(t11.type, tok::arrow);
auto t12 = lexer.parse();
EXPECT_EQ(t12.type, tok::tilde);
auto tlast = lexer.parse();
EXPECT_EQ(tlast.type, tok::eof);
}
TEST(Lexer, comparison_operators) {
char string[] = "< <= > >= == != !";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
auto t1 = lexer.parse();
EXPECT_EQ(t1.type, tok::lt);
......@@ -191,8 +221,7 @@ TEST(Lexer, comparison_operators) {
// test braces
TEST(Lexer, braces) {
char string[] = "foo}";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
auto t1 = lexer.parse();
EXPECT_EQ(t1.type, tok::identifier);
......@@ -209,8 +238,7 @@ TEST(Lexer, comments) {
char string[] = "foo:this is one line\n"
"bar : another comment\n"
"foobar ? another comment\n";
PRINT_LEX_STRING
Lexer lexer(string, string+sizeof(string));
VerboseLexer lexer(string, string+sizeof(string));
auto t1 = lexer.parse();
EXPECT_EQ(t1.type, tok::identifier);
......@@ -243,7 +271,7 @@ TEST(Lexer, numbers) {
std::vector<long long> check_ints = {1, 23, 3};
std::vector<long long> ints;
Lexer lexer(floats_stream.str());
VerboseLexer lexer(floats_stream.str());
auto t = lexer.parse();
auto iter = floats.cbegin();
while (t.type != tok::eof && iter != floats.cend()) {
......
......@@ -9,23 +9,23 @@ TEST(Optimizer, constant_folding) {
auto v = make_unique<ConstantFolderVisitor>();
{
auto e = parse_line_expression("x = 2*3");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
EXPECT_EQ(e->is_assignment()->rhs()->is_number()->value(), 6);
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
auto e = parse_line_expression("x = 1 + 2 + 3");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
EXPECT_EQ(e->is_assignment()->rhs()->is_number()->value(), 6);
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
auto e = parse_line_expression("x = exp(2)");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
// The tolerance has to be loosend to 1e-15, because the optimizer performs
// all intermediate calculations in 80 bit precision, which disagrees in
......@@ -33,24 +33,24 @@ TEST(Optimizer, constant_folding) {
// This is a good thing: by using the constant folder we increase accuracy
// over the unoptimized code!
EXPECT_EQ(std::fabs(e->is_assignment()->rhs()->is_number()->value()-std::exp(2.0))<1e-15, true);
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
auto e = parse_line_expression("x= 2*2 + 3");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
EXPECT_EQ(e->is_assignment()->rhs()->is_number()->value(), 7);
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
auto e = parse_line_expression("x= 3 + 2*2");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
EXPECT_EQ(e->is_assignment()->rhs()->is_number()->value(), 7);
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
// this doesn't work: the (y+2) expression is not a constant, so folding stops.
......@@ -58,23 +58,23 @@ TEST(Optimizer, constant_folding) {
// one approach would be try sorting communtative operations so that numbers
// are adjacent to one another in the tree
auto e = parse_line_expression("x= y + 2 + 3");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( "" )
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT( "" );
}
{
auto e = parse_line_expression("x= 2 + 3 + y");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT("");
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT("");;
}
{
auto e = parse_line_expression("foo(2+3, log(32), 2*3 + x)");
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT( e->to_string() );
e->accept(v.get());
VERBOSE_PRINT( e->to_string() )
VERBOSE_PRINT("");
VERBOSE_PRINT( e->to_string() );
VERBOSE_PRINT("");;
}
}
This diff is collapsed.
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment