diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
index 2e3a8e7bc7c0b8520d56344bc060b18852f27bdf..d8a65710b8a59d2f00c74e55072ad024cd100207 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/ParserGeneration.java
@@ -94,6 +94,7 @@ public class ParserGeneration {
         "pass along TruffleRLanguage",
         "convert line endings",
         "handle four and more dots as identifier",
-        "allow greek characters in identifiers"
+        "allow greek characters in identifiers",
+        "allow everything but newlines in %<ident>% operators"
     };
 }
diff --git a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
index 8e11dfacc9b097e2e20a305bb50b232f23b9a981..ee3092702168a8da6dc98dc1eb0717e273874404 100644
--- a/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
+++ b/com.oracle.truffle.r.parser/src/com/oracle/truffle/r/parser/R.g
@@ -695,7 +695,7 @@ ID
     | '`' BACKTICK_NAME
     ;
 
-OP : '%' OP_NAME+ '%' ;
+OP : '%' (~('%' | '\n' | '\r' | '\f'))+ '%' ;
 
 fragment BACKTICK_NAME
     @init { final StringBuilder buf = new StringBuilder(); }
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
index 2a5c05f9d5f5e7d081d06d50d2491a96819121dc..4231476011c26ece8a58fcf9761ecac6eda2daf6 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test
@@ -160766,6 +160766,22 @@ non-integer value 12345678909876543212L qualified with L; using numeric value
 #'\ ' == ' '
 [1] TRUE
 
+##com.oracle.truffle.r.test.parser.TestParser.testUserOp#
+#`%!@#$^&*()%` <- function(a,b) 1; 10 %!@#$^&*()% 20
+[1] 1
+
+##com.oracle.truffle.r.test.parser.TestParser.testUserOp#
+#`%5%` <- function(a,b) 1; 10 %5% 20
+[1] 1
+
+##com.oracle.truffle.r.test.parser.TestParser.testUserOp#
+#`%foo%` <- function(a,b) 1; 10 %foo% 20
+[1] 1
+
+##com.oracle.truffle.r.test.parser.TestParser.testUserOp#
+#`%Å %` <- function(a,b) 1; 10 %Å % 20
+[1] 1
+
 ##com.oracle.truffle.r.test.rffi.TestUserRNG.testUserRNG#
 #{ dyn.load("tmptest/userrng/liburand.so"); RNGkind("user"); print(RNGkind()); set.seed(4567); runif(10) }
 [1] "user-supplied" "Inversion"
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/parser/TestParser.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/parser/TestParser.java
index 9f9de365a6800be6007de366c8609813ea74a528..f2689a28d2d0de17a9b3d3c295862fb759211fbf 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/parser/TestParser.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/parser/TestParser.java
@@ -150,6 +150,14 @@ public class TestParser extends TestBase {
         assertEval("{ ...... <- 42; cat(......); }");
     }
 
+    @Test
+    public void testUserOp() {
+        assertEval("`%foo%` <- function(a,b) 1; 10 %foo% 20");
+        assertEval("`%5%` <- function(a,b) 1; 10 %5% 20");
+        assertEval("`%Å %` <- function(a,b) 1; 10 %Å % 20");
+        assertEval("`%!@#$^&*()%` <- function(a,b) 1; 10 %!@#$^&*()% 20");
+    }
+
     /**
      * Recursively look for .r source files in the args[0] directory and parse them.
      */