diff --git a/common/libeval_compiler/grammar.lemon b/common/libeval_compiler/grammar.lemon
index 9d6b3190ab..7e1d184d84 100644
--- a/common/libeval_compiler/grammar.lemon
+++ b/common/libeval_compiler/grammar.lemon
@@ -24,6 +24,7 @@
 %type nt {LIBEVAL::TREE_NODE*}
 
 %nonassoc G_IDENTIFIER G_ASSIGN G_SEMCOL.
+%left G_COMMA.
 %left G_BOOL_AND.
 %left G_BOOL_OR.
 %left G_BOOL_XOR.
@@ -78,6 +79,13 @@ nt(A) ::= G_IDENTIFIER(B).
     A = newNode( pEval, TR_IDENTIFIER, B.value );
 }
 
+nt(A) ::= nt(B) G_COMMA nt(C).
+{
+    A = newNode( pEval, TR_ARG_LIST );
+    A->leaf[0] = B;
+    A->leaf[1] = C;
+}
+
 nt(A) ::= nt(B) G_LESS_THAN nt(C).
 {
     A = newNode( pEval, TR_OP_LESS );
diff --git a/common/libeval_compiler/libeval_compiler.cpp b/common/libeval_compiler/libeval_compiler.cpp
index 1e1d6b2595..d3ad994d0a 100644
--- a/common/libeval_compiler/libeval_compiler.cpp
+++ b/common/libeval_compiler/libeval_compiler.cpp
@@ -21,6 +21,7 @@
 #include <memory>
 #include <set>
 #include <vector>
+#include <algorithm>
 
 #ifdef DEBUG
 #include <cstdarg>
@@ -518,6 +519,8 @@ bool COMPILER::lexDefault( T_TOKEN& aToken )
         case ')': retval.token = G_PARENR;       break;
         case ';': retval.token = G_SEMCOL;       break;
         case '.': retval.token = G_STRUCT_REF;   break;
+        case ',': retval.token = G_COMMA;        break;
+
 
         default:
             reportError( CST_PARSE, wxString::Format( _( "Unrecognized character '%c'" ), (char) ch ) );
@@ -569,6 +572,17 @@ void dumpNode( wxString& buf, TREE_NODE* tok, int depth = 0 )
 
         break;
 
+    case TR_ARG_LIST:
+        buf += "ARG_LIST: ";
+        buf += formatNode( tok );
+
+        if( tok->leaf[0] )
+            dumpNode( buf, tok->leaf[0], depth + 1 );
+        if( tok->leaf[1] )
+            dumpNode( buf, tok->leaf[1], depth + 1 );
+
+        break;
+
     case TR_STRING:
         buf += "STRING: ";
         buf +=  formatNode( tok );
@@ -698,6 +712,44 @@ static void prepareTree( LIBEVAL::TREE_NODE *node )
         prepareTree( node->leaf[1] );
 }
 
+static std::vector<TREE_NODE*> squashParamList( TREE_NODE* root )
+{
+    std::vector<TREE_NODE*> args;
+
+    if( !root )
+    {
+        return args;
+    }
+
+    if( root->op != TR_ARG_LIST && root->op != TR_NULL )
+    {
+        args.push_back( root );
+    }
+    else
+    {
+        TREE_NODE *n = root;
+        do
+        {
+            if( n->leaf[1] )
+                args.push_back(n->leaf[1]);
+
+            n = n->leaf[0];
+        } while ( n && n->op == TR_ARG_LIST );
+
+        if( n )
+        {
+            args.push_back(n);
+        }
+    }
+
+    std::reverse( args.begin(), args.end() );
+
+    for(int i = 0; i < args.size(); i++ )
+        libeval_dbg(10, "squash arg%d: %s\n", i, (const char*) *args[i]->value.str );
+
+    return args;
+}
+
 
 bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
 {
@@ -800,6 +852,7 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
 
                     wxString functionName = *node->leaf[1]->leaf[0]->value.str;
                     auto  func = aCode->CreateFuncCall( functionName );
+                    std::vector<TREE_NODE*> params = squashParamList( node->leaf[1]->leaf[1] );
 
                     libeval_dbg( 10, "emit func call: %s\n", functionName );
 
@@ -812,22 +865,18 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
                     if( func )
                     {
                         // Preflight the function call
-                        auto argsLeaf = node->leaf[1]->leaf[1];
-                        wxString paramStr;
 
-                        if( argsLeaf->op != TR_NULL ) // function has an argument
+                        for( auto pnode : params )
                         {
-                            paramStr = *node->leaf[1]->leaf[1]->value.str;
                             VALUE*   param = aPreflightContext->AllocValue();
-
-                            param->Set( paramStr );
+                            param->Set( *pnode->value.str );
                             aPreflightContext->Push( param );
                         }
 
                         aPreflightContext->SetErrorCallback(
                                 [&]( const wxString& aMessage, int aOffset )
                                 {
-                                    size_t loc = node->leaf[1]->leaf[1]->srcPos- paramStr.Length();
+                                    size_t loc = node->leaf[1]->leaf[1]->srcPos;
                                     reportError( CST_CODEGEN, aMessage, (int) loc - 1 );
                                 } );
 
@@ -851,7 +900,10 @@ bool COMPILER::generateUCode( UCODE* aCode, CONTEXT* aPreflightContext )
                     // a TR_OP_FUNC_CALL and its function parameter
                     stack.pop_back();
                     stack.push_back( node->leaf[1] );
-                    stack.push_back( node->leaf[1]->leaf[1] );
+                    for( auto pnode : params )
+                    {
+                        stack.push_back( pnode );
+                    }
 
                     node->leaf[1]->SetUop( TR_OP_METHOD_CALL, func, std::move( vref ) );
                     node->isTerminal = false;
diff --git a/include/libeval_compiler/libeval_compiler.h b/include/libeval_compiler/libeval_compiler.h
index 0ce7f542ea..8471db754b 100644
--- a/include/libeval_compiler/libeval_compiler.h
+++ b/include/libeval_compiler/libeval_compiler.h
@@ -95,7 +95,8 @@ enum TOKEN_TYPE_T
     TR_STRUCT_REF = 4,
     TR_STRING     = 5,
     TR_UNIT       = 6,
-    TR_NULL       = 7
+    TR_ARG_LIST   = 7,
+    TR_NULL       = 8
 };
 
 class UOP;