diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index 3df94adeb5f6b2628e155046868fa10f6280a2c3..004ef00391e0417bea13374007b7cf7421d7806b 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -22,6 +22,8 @@
  */
 package com.oracle.truffle.r.engine;
 
+import java.io.PrintStream;
+import java.io.PrintWriter;
 import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -380,11 +382,15 @@ final class REngine implements Engine, Engine.Timings {
             } catch (ReturnException ex) {
                 return ex.getResult();
             } catch (DebugExitException | JumpToTopLevelException | ExitException | ThreadDeath e) {
+                CompilerDirectives.transferToInterpreter();
                 throw e;
             } catch (RError e) {
                 CompilerDirectives.transferToInterpreter();
                 throw e;
             } catch (Throwable t) {
+                CompilerDirectives.transferToInterpreter();
+                // other errors didn't produce an output yet
+                RInternalError.reportError(t);
                 throw t;
             } finally {
                 RContext.setThreadLocalInstance(oldContext);
diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
index 0901e341ed7968d6bd23a261cc6ee89e9fa31920..a173a08ec6434ba0b0ac7cf5e8bba231bb3e4fe7 100644
--- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
+++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java
@@ -269,7 +269,7 @@ public class RCommand {
                             } else if (e.isExit()) {
                                 // usually from quit
                                 throw new ExitException(e.getExitStatus());
-                            } else if (e.isHostException()) {
+                            } else if (e.isHostException() || e.isInternalError()) {
                                 // we continue the repl even though the system may be broken
                                 lastStatus = 1;
                             } else if (e.isGuestException()) {
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
index 79152550b9fa1d292b20e134f0182470f1179629..ccc5f3390a4957c3831ae29c75721005c5d54f9a 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/GrepFunctions.java
@@ -39,6 +39,7 @@ import com.oracle.truffle.r.nodes.attributes.SetFixedAttributeNode;
 import com.oracle.truffle.r.nodes.builtin.NodeWithArgumentCasts.Casts;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.RError.Message;
 import com.oracle.truffle.r.runtime.RInternalError;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.RegExp;
@@ -221,81 +222,85 @@ public class GrepFunctions {
 
         protected Object doGrep(String patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean value, boolean perlPar, boolean fixed,
                         @SuppressWarnings("unused") boolean useBytes, boolean invert, boolean grepl) {
-            boolean perl = perlPar;
-            perl = checkPerlFixed(perlPar, fixed);
-            checkCaseFixed(ignoreCase, fixed);
-
-            String pattern = patternArg;
-            int len = vector.getLength();
-            if (RRuntime.isNA(pattern)) {
-                return value ? allStringNAResult(len) : allIntNAResult(len);
-            }
-            boolean[] matches = new boolean[len];
-            if (!perl) {
-                // TODO case
-                if (!fixed) {
-                    pattern = RegExp.checkPreDefinedClasses(pattern);
+            try {
+                boolean perl = perlPar;
+                perl = checkPerlFixed(perlPar, fixed);
+                checkCaseFixed(ignoreCase, fixed);
+
+                String pattern = patternArg;
+                int len = vector.getLength();
+                if (RRuntime.isNA(pattern)) {
+                    return value ? allStringNAResult(len) : allIntNAResult(len);
                 }
-                findAllMatches(matches, pattern, vector, fixed, ignoreCase);
-            } else {
-                PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase);
-                // TODO pcre_study for vectors > 10 ? (cf GnuR)
-                int[] ovector = new int[30];
-                for (int i = 0; i < len; i++) {
-                    String text = vector.getDataAt(i);
-                    if (!RRuntime.isNA(text)) {
-                        if (execNode.execute(pcre.result, 0, text, 0, 0, ovector) >= 0) {
-                            matches[i] = true;
+                boolean[] matches = new boolean[len];
+                if (!perl) {
+                    // TODO case
+                    if (!fixed) {
+                        pattern = RegExp.checkPreDefinedClasses(pattern);
+                    }
+                    findAllMatches(matches, pattern, vector, fixed, ignoreCase);
+                } else {
+                    PCRERFFI.Result pcre = compilePerlPattern(pattern, ignoreCase);
+                    // TODO pcre_study for vectors > 10 ? (cf GnuR)
+                    int[] ovector = new int[30];
+                    for (int i = 0; i < len; i++) {
+                        String text = vector.getDataAt(i);
+                        if (!RRuntime.isNA(text)) {
+                            if (execNode.execute(pcre.result, 0, text, 0, 0, ovector) >= 0) {
+                                matches[i] = true;
+                            }
                         }
                     }
                 }
-            }
 
-            if (grepl) {
-                byte[] data = new byte[len];
-                for (int i = 0; i < len; i++) {
-                    data[i] = RRuntime.asLogical(matches[i]);
+                if (grepl) {
+                    byte[] data = new byte[len];
+                    for (int i = 0; i < len; i++) {
+                        data[i] = RRuntime.asLogical(matches[i]);
+                    }
+                    return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR);
                 }
-                return RDataFactory.createLogicalVector(data, RDataFactory.COMPLETE_VECTOR);
-            }
 
-            int nmatches = 0;
-            for (int i = 0; i < len; i++) {
-                if (invert ^ matches[i]) {
-                    nmatches++;
+                int nmatches = 0;
+                for (int i = 0; i < len; i++) {
+                    if (invert ^ matches[i]) {
+                        nmatches++;
+                    }
                 }
-            }
 
-            if (nmatches == 0) {
-                return value ? RDataFactory.createEmptyStringVector() : RDataFactory.createEmptyIntVector();
-            } else {
-                if (value) {
-                    RStringVector oldNames = vector.getNames();
-                    String[] newNames = null;
-                    if (oldNames != null) {
-                        newNames = new String[nmatches];
-                    }
-                    String[] data = new String[nmatches];
-                    int j = 0;
-                    for (int i = 0; i < len; i++) {
-                        if (invert ^ matches[i]) {
-                            if (newNames != null) {
-                                newNames[j] = oldNames.getDataAt(i);
+                if (nmatches == 0) {
+                    return value ? RDataFactory.createEmptyStringVector() : RDataFactory.createEmptyIntVector();
+                } else {
+                    if (value) {
+                        RStringVector oldNames = vector.getNames();
+                        String[] newNames = null;
+                        if (oldNames != null) {
+                            newNames = new String[nmatches];
+                        }
+                        String[] data = new String[nmatches];
+                        int j = 0;
+                        for (int i = 0; i < len; i++) {
+                            if (invert ^ matches[i]) {
+                                if (newNames != null) {
+                                    newNames[j] = oldNames.getDataAt(i);
+                                }
+                                data[j++] = vector.getDataAt(i);
                             }
-                            data[j++] = vector.getDataAt(i);
                         }
-                    }
-                    return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, newNames == null ? null : RDataFactory.createStringVector(newNames, RDataFactory.COMPLETE_VECTOR));
-                } else {
-                    int[] data = new int[nmatches];
-                    int j = 0;
-                    for (int i = 0; i < len; i++) {
-                        if (invert ^ matches[i]) {
-                            data[j++] = i + 1;
+                        return RDataFactory.createStringVector(data, RDataFactory.COMPLETE_VECTOR, newNames == null ? null : RDataFactory.createStringVector(newNames, RDataFactory.COMPLETE_VECTOR));
+                    } else {
+                        int[] data = new int[nmatches];
+                        int j = 0;
+                        for (int i = 0; i < len; i++) {
+                            if (invert ^ matches[i]) {
+                                data[j++] = i + 1;
+                            }
                         }
+                        return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
                     }
-                    return RDataFactory.createIntVector(data, RDataFactory.COMPLETE_VECTOR);
                 }
+            } catch (PatternSyntaxException e) {
+                throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage());
             }
         }
 
@@ -543,8 +548,7 @@ public class GrepFunctions {
                 ret.copyAttributesFrom(vector);
                 return ret;
             } catch (PatternSyntaxException e) {
-                CompilerDirectives.transferToInterpreter();
-                throw new RInternalError(e, "internal error: %s", e.getMessage());
+                throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage());
             }
         }
 
@@ -784,71 +788,76 @@ public class GrepFunctions {
         @TruffleBoundary
         protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean perl, boolean fixed, boolean useBytesL,
                         @Cached("createCommon()") CommonCodeNode common) {
-            common.checkExtraArgs(false, false, false, useBytesL, false);
-            if (patternArg.getLength() > 1) {
-                throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet");
-            }
-            String pattern = patternArg.getDataAt(0);
-            if (!perl) {
-                pattern = RegExp.checkPreDefinedClasses(pattern);
-            }
-            // TODO: useBytes normally depends on the value of the parameter and (if false) on
-            // whether the string is ASCII
-            boolean useBytes = true;
-            boolean hasAnyCapture = false;
-            int[] result = new int[vector.getLength()];
-            int[] matchLength = new int[vector.getLength()];
-            String[] captureNames = null;
-            int[] captureStart = null;
-            int[] captureLength = null;
-            if (pattern.length() == 0) {
-                // emtpy pattern
-                Arrays.fill(result, 1);
-            } else {
-                for (int i = 0; i < vector.getLength(); i++) {
-                    Info res = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0);
-                    result[i] = res.index;
-                    matchLength[i] = res.size;
-                    if (res.hasCapture) {
-                        hasAnyCapture = true;
-                        if (captureNames == null) {
-                            // first time we see captures
-                            captureNames = res.captureNames;
-                            captureStart = new int[captureNames.length * vector.getLength()];
-                            captureLength = new int[captureNames.length * vector.getLength()];
-                            // previous matches had no capture - fill in result with -1-s
-                            for (int k = 0; k < i; k++) {
-                                setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), k);
+            try {
+                common.checkExtraArgs(false, false, false, useBytesL, false);
+                if (patternArg.getLength() > 1) {
+                    throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet");
+                }
+                String pattern = patternArg.getDataAt(0);
+                if (!perl) {
+                    pattern = RegExp.checkPreDefinedClasses(pattern);
+                }
+                // TODO: useBytes normally depends on the value of the parameter and (if false) on
+                // whether the string is ASCII
+                boolean useBytes = true;
+                boolean hasAnyCapture = false;
+                int[] result = new int[vector.getLength()];
+                int[] matchLength = new int[vector.getLength()];
+                String[] captureNames = null;
+                int[] captureStart = null;
+                int[] captureLength = null;
+                if (pattern.length() == 0) {
+                    // emtpy pattern
+                    Arrays.fill(result, 1);
+                } else {
+                    for (int i = 0; i < vector.getLength(); i++) {
+                        Info res = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed).get(0);
+                        result[i] = res.index;
+                        matchLength[i] = res.size;
+                        if (res.hasCapture) {
+                            hasAnyCapture = true;
+                            if (captureNames == null) {
+                                // first time we see captures
+                                captureNames = res.captureNames;
+                                captureStart = new int[captureNames.length * vector.getLength()];
+                                captureLength = new int[captureNames.length * vector.getLength()];
+                                // previous matches had no capture - fill in result with -1-s
+                                for (int k = 0; k < i; k++) {
+                                    setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), k);
+                                }
                             }
+                            assert captureNames.length == res.captureStart.length;
+                            assert captureNames.length == res.captureLength.length;
+                            for (int j = 0; j < captureNames.length; j++) {
+                                captureStart[j * vector.getLength() + i] = res.captureStart[j];
+                                captureLength[j * vector.getLength() + i] = res.captureLength[j];
+                            }
+                        } else if (hasAnyCapture) {
+                            // no capture for this part of the vector, but there are previous
+                            // captures
+                            setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), i);
                         }
-                        assert captureNames.length == res.captureStart.length;
-                        assert captureNames.length == res.captureLength.length;
-                        for (int j = 0; j < captureNames.length; j++) {
-                            captureStart[j * vector.getLength() + i] = res.captureStart[j];
-                            captureLength[j * vector.getLength() + i] = res.captureLength[j];
-                        }
-                    } else if (hasAnyCapture) {
-                        // no capture for this part of the vector, but there are previous captures
-                        setNoCaptureValues(captureStart, captureLength, captureNames.length, vector.getLength(), i);
                     }
                 }
+                RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR);
+                setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
+                if (useBytes) {
+                    setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
+                }
+                if (hasAnyCapture) {
+                    RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR);
+                    RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
+                    setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                    setCaptureStartAttrNode.execute(ret, captureStartVec);
+                    RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
+                    setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
+                    setCaptureLengthAttrNode.execute(ret, captureLengthVec);
+                    setCaptureNamesAttrNode.execute(ret, captureNamesVec);
+                }
+                return ret;
+            } catch (PatternSyntaxException e) {
+                throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage());
             }
-            RIntVector ret = RDataFactory.createIntVector(result, RDataFactory.COMPLETE_VECTOR);
-            setMatchLengthAttrNode.execute(ret, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
-            if (useBytes) {
-                setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
-            }
-            if (hasAnyCapture) {
-                RStringVector captureNamesVec = RDataFactory.createStringVector(captureNames, RDataFactory.COMPLETE_VECTOR);
-                RIntVector captureStartVec = RDataFactory.createIntVector(captureStart, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                setDimNamesAttrNode.execute(captureStartVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                setCaptureStartAttrNode.execute(ret, captureStartVec);
-                RIntVector captureLengthVec = RDataFactory.createIntVector(captureLength, RDataFactory.COMPLETE_VECTOR, new int[]{vector.getLength(), captureNames.length});
-                setDimNamesAttrNode.execute(captureLengthVec, RDataFactory.createList(new Object[]{RNull.instance, captureNamesVec.copy()}));
-                setCaptureLengthAttrNode.execute(ret, captureLengthVec);
-                setCaptureNamesAttrNode.execute(ret, captureNamesVec);
-            }
-            return ret;
         }
 
         protected List<Info> getInfo(CommonCodeNode common, String pattern, String text, boolean ignoreCase, boolean perl, boolean fixed) {
@@ -960,39 +969,43 @@ public class GrepFunctions {
         @TruffleBoundary
         protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCase, boolean fixed, boolean useBytes,
                         @Cached("createCommon()") CommonCodeNode common) {
-            common.checkExtraArgs(false, false, false, useBytes, false);
-            if (patternArg.getLength() > 1) {
-                throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet");
-            }
-            RList ret = RDataFactory.createList(vector.getLength());
-            String pattern = patternArg.getDataAt(0);
-            pattern = RegExp.checkPreDefinedClasses(pattern);
-            // TODO: useBytes normally depends on the value of the parameter and (if false) on
-            // whether the string is ASCII
-            for (int i = 0; i < vector.getLength(); i++) {
-                int[] matchPos;
-                int[] matchLength;
-                if (pattern.length() == 0) {
-                    // emtpy pattern
-                    matchPos = new int[]{1};
-                    matchLength = new int[]{0};
-                } else {
-                    List<Info> res = getInfo(pattern, vector.getDataAt(i), ignoreCase, fixed);
-                    matchPos = new int[res.size()];
-                    matchLength = new int[res.size()];
-                    for (int j = 0; j < res.size(); j++) {
-                        matchPos[j] = res.get(j).index;
-                        matchLength[j] = res.get(j).size;
+            try {
+                common.checkExtraArgs(false, false, false, useBytes, false);
+                if (patternArg.getLength() > 1) {
+                    throw RInternalError.unimplemented("multi-element patterns in regexpr not implemented yet");
+                }
+                RList ret = RDataFactory.createList(vector.getLength());
+                String pattern = patternArg.getDataAt(0);
+                pattern = RegExp.checkPreDefinedClasses(pattern);
+                // TODO: useBytes normally depends on the value of the parameter and (if false) on
+                // whether the string is ASCII
+                for (int i = 0; i < vector.getLength(); i++) {
+                    int[] matchPos;
+                    int[] matchLength;
+                    if (pattern.length() == 0) {
+                        // emtpy pattern
+                        matchPos = new int[]{1};
+                        matchLength = new int[]{0};
+                    } else {
+                        List<Info> res = getInfo(pattern, vector.getDataAt(i), ignoreCase, fixed);
+                        matchPos = new int[res.size()];
+                        matchLength = new int[res.size()];
+                        for (int j = 0; j < res.size(); j++) {
+                            matchPos[j] = res.get(j).index;
+                            matchLength[j] = res.get(j).size;
+                        }
                     }
+                    RIntVector matches = RDataFactory.createIntVector(matchPos, RDataFactory.COMPLETE_VECTOR);
+                    setMatchLengthAttrNode.execute(matches, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
+                    ret.setElement(i, matches);
                 }
-                RIntVector matches = RDataFactory.createIntVector(matchPos, RDataFactory.COMPLETE_VECTOR);
-                setMatchLengthAttrNode.execute(matches, RDataFactory.createIntVector(matchLength, RDataFactory.COMPLETE_VECTOR));
-                ret.setElement(i, matches);
-            }
-            if (useBytes) {
-                setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
+                if (useBytes) {
+                    setUseBytesAttrNode.execute(ret, RRuntime.LOGICAL_TRUE);
+                }
+                return ret;
+            } catch (PatternSyntaxException e) {
+                throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage());
             }
-            return ret;
         }
 
         protected List<Info> getInfo(String pattern, String text, boolean ignoreCase, boolean fixed) {
@@ -1069,68 +1082,72 @@ public class GrepFunctions {
         @Override
         protected Object regexp(RAbstractStringVector patternArg, RAbstractStringVector vector, boolean ignoreCaseL, boolean perlL, boolean fixedL, boolean useBytesL,
                         @Cached("createCommon()") CommonCodeNode common) {
-            common.checkExtraArgs(false, false, false, useBytesL, false);
-            boolean ignoreCase = ignoreCaseL;
-            boolean fixed = fixedL;
-            boolean perl = perlL;
-            if (patternArg.getLength() > 1) {
-                throw RInternalError.unimplemented("multi-element patterns in gregexpr not implemented yet");
-            }
-            String pattern = patternArg.getDataAt(0);
-            if (!perl) {
-                pattern = RegExp.checkPreDefinedClasses(pattern);
-            }
-            // TODO: useBytes normally depends on the value of the parameter and (if false) on
-            // whether the string is ASCII
-            boolean useBytes = true;
-            Object[] result = new Object[vector.getLength()];
-            boolean hasAnyCapture = false;
-            RStringVector captureNames = null;
-            for (int i = 0; i < vector.getLength(); i++) {
-                RIntVector res;
-                if (pattern.length() == 0) {
-                    String txt = vector.getDataAt(i);
-                    res = RDataFactory.createIntVector(txt.length());
-                    for (int j = 0; j < txt.length(); j++) {
-                        res.setDataAt(res.getDataWithoutCopying(), j, j + 1);
-                    }
-                    setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length()));
-                    if (useBytes) {
-                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
-                    }
-                } else {
-                    List<Info> l = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
-                    res = toIndexOrSizeVector(l, true);
-                    setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false));
-                    if (useBytes) {
-                        setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
-                    }
-                    RIntVector captureStart = toCaptureStartOrLength(l, true);
-                    if (captureStart != null) {
-                        RIntVector captureLength = toCaptureStartOrLength(l, false);
-                        assert captureLength != null;
-                        captureNames = getCaptureNamesVector(l);
-                        assert captureNames.getLength() > 0;
-                        if (!hasAnyCapture) {
-                            // set previous result list elements to "no capture"
-                            for (int j = 0; j < i; j++) {
-                                setNoCaptureAttributes((RIntVector) result[j], captureNames);
+            try {
+                common.checkExtraArgs(false, false, false, useBytesL, false);
+                boolean ignoreCase = ignoreCaseL;
+                boolean fixed = fixedL;
+                boolean perl = perlL;
+                if (patternArg.getLength() > 1) {
+                    throw RInternalError.unimplemented("multi-element patterns in gregexpr not implemented yet");
+                }
+                String pattern = patternArg.getDataAt(0);
+                if (!perl) {
+                    pattern = RegExp.checkPreDefinedClasses(pattern);
+                }
+                // TODO: useBytes normally depends on the value of the parameter and (if false) on
+                // whether the string is ASCII
+                boolean useBytes = true;
+                Object[] result = new Object[vector.getLength()];
+                boolean hasAnyCapture = false;
+                RStringVector captureNames = null;
+                for (int i = 0; i < vector.getLength(); i++) {
+                    RIntVector res;
+                    if (pattern.length() == 0) {
+                        String txt = vector.getDataAt(i);
+                        res = RDataFactory.createIntVector(txt.length());
+                        for (int j = 0; j < txt.length(); j++) {
+                            res.setDataAt(res.getDataWithoutCopying(), j, j + 1);
+                        }
+                        setMatchLengthAttrNode.execute(res, RDataFactory.createIntVector(txt.length()));
+                        if (useBytes) {
+                            setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
+                        }
+                    } else {
+                        List<Info> l = getInfo(common, pattern, vector.getDataAt(i), ignoreCase, perl, fixed);
+                        res = toIndexOrSizeVector(l, true);
+                        setMatchLengthAttrNode.execute(res, toIndexOrSizeVector(l, false));
+                        if (useBytes) {
+                            setUseBytesAttrNode.execute(res, RRuntime.LOGICAL_TRUE);
+                        }
+                        RIntVector captureStart = toCaptureStartOrLength(l, true);
+                        if (captureStart != null) {
+                            RIntVector captureLength = toCaptureStartOrLength(l, false);
+                            assert captureLength != null;
+                            captureNames = getCaptureNamesVector(l);
+                            assert captureNames.getLength() > 0;
+                            if (!hasAnyCapture) {
+                                // set previous result list elements to "no capture"
+                                for (int j = 0; j < i; j++) {
+                                    setNoCaptureAttributes((RIntVector) result[j], captureNames);
+                                }
                             }
+                            hasAnyCapture = true;
+                            setCaptureStartAttrNode.execute(res, captureStart);
+                            setCaptureLengthAttrNode.execute(res, captureLength);
+                            setCaptureNamesAttrNode.execute(res, captureNames);
+                        } else if (hasAnyCapture) {
+                            assert captureNames != null;
+                            // it's capture names from previous iteration, so copy
+                            setNoCaptureAttributes(res, (RStringVector) captureNames.copy());
                         }
-                        hasAnyCapture = true;
-                        setCaptureStartAttrNode.execute(res, captureStart);
-                        setCaptureLengthAttrNode.execute(res, captureLength);
-                        setCaptureNamesAttrNode.execute(res, captureNames);
-                    } else if (hasAnyCapture) {
-                        assert captureNames != null;
-                        // it's capture names from previous iteration, so copy
-                        setNoCaptureAttributes(res, (RStringVector) captureNames.copy());
                     }
-                }
 
-                result[i] = res;
+                    result[i] = res;
+                }
+                return RDataFactory.createList(result);
+            } catch (PatternSyntaxException e) {
+                throw error(Message.INVALID_REGEXP_REASON, patternArg, e.getMessage());
             }
-            return RDataFactory.createList(result);
         }
 
         private static RIntVector toIndexOrSizeVector(List<Info> list, boolean index) {
@@ -1374,30 +1391,34 @@ public class GrepFunctions {
                     continue;
                 }
                 String currentSplit = splits[i % splits.length];
-                if (currentSplit.isEmpty()) {
-                    result[i] = na.check(data) ? RDataFactory.createNAStringVector() : emptySplitIntl(data);
-                } else if (RRuntime.isNA(currentSplit)) {
-                    // NA doesn't split
-                    result[i] = RDataFactory.createStringVectorFromScalar(data);
-                } else {
-                    RStringVector resultItem;
-                    if (na.check(data)) {
-                        resultItem = RDataFactory.createNAStringVector();
+                try {
+                    if (currentSplit.isEmpty()) {
+                        result[i] = na.check(data) ? RDataFactory.createNAStringVector() : emptySplitIntl(data);
+                    } else if (RRuntime.isNA(currentSplit)) {
+                        // NA doesn't split
+                        result[i] = RDataFactory.createStringVectorFromScalar(data);
                     } else {
-                        if (perl) {
-                            resultItem = splitPerl(data, pcreSplits[i % splits.length]);
+                        RStringVector resultItem;
+                        if (na.check(data)) {
+                            resultItem = RDataFactory.createNAStringVector();
                         } else {
-                            resultItem = splitIntl(data, currentSplit, fixed);
-                        }
-                        if (resultItem.getLength() == 0) {
-                            if (fixed) {
-                                resultItem = RDataFactory.createStringVector(data);
+                            if (perl) {
+                                resultItem = splitPerl(data, pcreSplits[i % splits.length]);
                             } else {
-                                resultItem = RDataFactory.createStringVector(data.length());
+                                resultItem = splitIntl(data, currentSplit, fixed);
+                            }
+                            if (resultItem.getLength() == 0) {
+                                if (fixed) {
+                                    resultItem = RDataFactory.createStringVector(data);
+                                } else {
+                                    resultItem = RDataFactory.createStringVector(data.length());
+                                }
                             }
                         }
+                        result[i] = resultItem;
                     }
-                    result[i] = resultItem;
+                } catch (PatternSyntaxException e) {
+                    throw error(Message.INVALID_REGEXP_REASON, currentSplit, e.getMessage());
                 }
             }
             RList ret = RDataFactory.createList(result);
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
index 9194da7ea85e1b5ce831b8ee9be14bbce72b7ebc..983421fd3ae1dde3d2cd91a6cdc7bb731278090e 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RError.java
@@ -636,6 +636,7 @@ public final class RError extends RuntimeException implements TruffleException {
         FIRST_ARGUMENT_MUST_BE_CHARACTER("the first argument must be of mode character"),
         ALL_ATTRIBUTES_NAMES("all attributes must have names [%d does not]"),
         INVALID_REGEXP("invalid regular expression '%s'"),
+        INVALID_REGEXP_REASON("invalid regular expression '%s': %s"),
         COERCING_ARGUMENT("coercing argument of type '%s' to %s"),
         MUST_BE_TRUE_FALSE_ENVIRONMENT("'%s' must be TRUE, FALSE or an environment"),
         UNKNOWN_OBJECT_MODE("object '%s' of mode '%s' was not found"),
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
index 05cbf60199af40a84500f1c03bf8633d4ff5ec4f..a115d68198ca807b5c99bde0ba01ec0d2706b6c8 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RInternalError.java
@@ -179,6 +179,7 @@ public final class RInternalError extends Error implements TruffleException {
                     System.err.println(out.toString());
                     System.err.println(verboseStackTrace);
                 }
+                String message = t instanceof RInternalError && t.getMessage() != null && !t.getMessage().isEmpty() ? t.getMessage() : "internal error: " + t.getClass().getSimpleName();
                 if (FastROptions.PrintErrorStacktracesToFile.getBooleanValue()) {
                     String suffix = contextId == 0 ? "" : "-" + Integer.toString(contextId);
                     Path logfile = Utils.getLogPath("fastr_errors.log" + suffix);
@@ -190,12 +191,14 @@ public final class RInternalError extends Error implements TruffleException {
                     } catch (IOException e) {
                         e.printStackTrace();
                     }
-                    String message = t instanceof RInternalError && t.getMessage() != null && !t.getMessage().isEmpty() ? t.getMessage() : "internal error: " + t.getClass().getSimpleName();
-                    System.out.println(message + " (see fastr_errors.log" + suffix + ")");
+                    System.err.println(message + " (see fastr_errors.log" + suffix + ")");
                     if (RContext.isEmbedded()) {
                         Utils.rSuicide("FastR internal error");
                     }
                 }
+                if (!FastROptions.PrintErrorStacktraces.getBooleanValue() && !FastROptions.PrintErrorStacktracesToFile.getBooleanValue()) {
+                    System.err.println(message);
+                }
             }
         } catch (Throwable t) {
             System.err.println("error while reporting internal error:");
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java
index 519a11a0231f4c3b5d4a622b7bf1e6bb195ef8e6..d0be846c39ceb35722674b2e739774f67a6dddb3 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RegExp.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -68,14 +68,33 @@ public class RegExp {
          * predefined classes like "[:alpha:]" with "\p{Alpha}".
          */
         boolean withinCharClass = false;
+        int parensNesting = 0;
         int i = 0;
         while (i < result.length()) {
             switch (result.charAt(i)) {
+                case '(':
+                    if (withinCharClass) {
+                        result = result.substring(0, i) + '\\' + result.substring(i);
+                        i++; // skip the newly inserted '\\'
+                    } else {
+                        parensNesting++;
+                    }
+                    break;
+                case ')':
+                    if (withinCharClass || parensNesting == 0) {
+                        result = result.substring(0, i) + '\\' + result.substring(i);
+                        i++; // skip the newly inserted '\\'
+                    } else {
+                        parensNesting--;
+                    }
+                    break;
                 case '\\':
                     if (withinCharClass) {
                         result = result.substring(0, i) + '\\' + result.substring(i);
+                        i++; // skip the newly inserted '\\'
+                    } else {
+                        i++; // skip the next character
                     }
-                    i++;
                     break;
                 case '[':
                     if (withinCharClass) {
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 612e6518136b6eab6f4ada74465779a2f2af4ed8..d95319518ad0ca4ef9b50fb14346f19b24b0e1a7 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
@@ -25512,6 +25512,41 @@ attr(,"useBytes")
 [1] TRUE
 
 
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage#
+#grep('(()', ')')
+Error in grep("(()", ")") :
+  invalid regular expression '(()', reason 'Missing ')''
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('(())', ')')
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage#
+#grep('([(]', ')')
+Error in grep("([(]", ")") :
+  invalid regular expression '([(]', reason 'Missing ')''
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#Output.IgnoreErrorMessage#
+#grep('([)]', ')')
+Error in grep("([)]", ")") :
+  invalid regular expression '([)]', reason 'Missing ')''
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('))', ')')
+integer(0)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('))', '))')
+[1] 1
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('[(]', ')')
+integer(0)
+
+##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
+#grep('[)]', ')')
+[1] 1
+
 ##com.oracle.truffle.r.test.builtins.TestBuiltin_grep.testGrep#
 #{ .Internal(grep("7", 7, F, F, F, F, F, F)) }
 Error: invalid 'text' argument
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
index cedba3a7b675e17cae5911a62c6df338d04ac1be..d5c5148e5700bf77b247ef7607dab95add6a7a71 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_grep.java
@@ -98,6 +98,15 @@ public class TestBuiltin_grep extends TestBase {
         // Expected output: integer(0)
         // FastR output: [1] 1
         assertEval(Ignored.ImplementationError, "{ grep('^ *$', ' \\n') }");
+
+        assertEval("grep('[(]', ')')");
+        assertEval("grep('[)]', ')')");
+        assertEval("grep('(())', ')')");
+        assertEval("grep('))', ')')");
+        assertEval("grep('))', '))')");
+        assertEval(Output.IgnoreErrorMessage, "grep('([)]', ')')");
+        assertEval(Output.IgnoreErrorMessage, "grep('([(]', ')')");
+        assertEval(Output.IgnoreErrorMessage, "grep('(()', ')')");
     }
 
     @Test