diff --git a/pynestml/grammars/generate_lexer_parser b/pynestml/grammars/generate_lexer_parser
index 6f695a202..c2248afab 100755
--- a/pynestml/grammars/generate_lexer_parser
+++ b/pynestml/grammars/generate_lexer_parser
@@ -22,4 +22,4 @@
 
 # Do not change the position of this file! In order to generate the corresponding code into `pynestml/generated`, this script has to be executed from `pynestml/grammars`.
 
-antlr4 -Dlanguage=Python3 *.g4 -visitor -no-listener -o ../generated
+antlr4 -encoding UTF8 -Dlanguage=Python3 *.g4 -visitor -no-listener -o ../generated
diff --git a/pynestml/utils/error_listener.py b/pynestml/utils/error_listener.py
index b4bd4c126..3666949d2 100644
--- a/pynestml/utils/error_listener.py
+++ b/pynestml/utils/error_listener.py
@@ -36,3 +36,7 @@ def error_occurred(self):
 
     def syntaxError(self, recognizer, offendingSymbol, line, column, msg, e):
         self._error_occurred = True
+        self.offendingSymbol = offendingSymbol
+        self.line = line
+        self.column = column
+        self.msg = msg
diff --git a/pynestml/utils/messages.py b/pynestml/utils/messages.py
index 9c6157fb4..26fe8d519 100644
--- a/pynestml/utils/messages.py
+++ b/pynestml/utils/messages.py
@@ -182,8 +182,8 @@ def get_no_code_generated(cls):
         return MessageCode.NO_CODE_GENERATED, message
 
     @classmethod
-    def get_lexer_error(cls):
-        message = 'Error occurred during lexing: abort'
+    def get_lexer_error(cls, msg):
+        message = 'Error occurred during lexing: ' + msg
         return MessageCode.LEXER_ERROR, message
 
     @classmethod
@@ -192,8 +192,8 @@ def get_could_not_determine_cond_based(cls, type_str, name):
         return MessageCode.LEXER_ERROR, message
 
     @classmethod
-    def get_parser_error(cls):
-        message = 'Error occurred during parsing: abort'
+    def get_parser_error(cls, msg):
+        message = 'Error occurred during parsing: ' + msg
         return MessageCode.PARSER_ERROR, message
 
     @classmethod
diff --git a/pynestml/utils/model_parser.py b/pynestml/utils/model_parser.py
index 295740809..f05cdf0e1 100644
--- a/pynestml/utils/model_parser.py
+++ b/pynestml/utils/model_parser.py
@@ -89,7 +89,7 @@ def parse_file(cls, file_path=None):
         :rtype: ASTNestMLCompilationUnit
         """
         try:
-            input_file = FileStream(file_path)
+            input_file = FileStream(file_path, encoding='utf-8')
         except IOError:
             code, message = Messages.get_input_path_not_found(path=file_path)
             Logger.log_message(node=None, code=None, message=message,
@@ -101,7 +101,6 @@ def parse_file(cls, file_path=None):
         # create a lexer and hand over the input
         lexer = PyNestMLLexer()
         lexer.removeErrorListeners()
-        lexer.addErrorListener(ConsoleErrorListener())
         lexerErrorListener = NestMLErrorListener()
         lexer.addErrorListener(lexerErrorListener)
         lexer._errHandler = BailErrorStrategy()  # halt immediately on lexer errors
@@ -111,14 +110,18 @@ def parse_file(cls, file_path=None):
         stream = CommonTokenStream(lexer)
         stream.fill()
         if lexerErrorListener._error_occurred:
-            code, message = Messages.get_lexer_error()
+            error_location = ASTSourceLocation(lexerErrorListener.line,
+                                               lexerErrorListener.column,
+                                               lexerErrorListener.line,
+                                               lexerErrorListener.column)
+            code, message = Messages.get_lexer_error(lexerErrorListener.msg)
             Logger.log_message(node=None, code=None, message=message,
-                               error_position=None, log_level=LoggingLevel.ERROR)
+                               error_position=error_location, log_level=LoggingLevel.ERROR)
             return
+
         # parse the file
         parser = PyNestMLParser(None)
         parser.removeErrorListeners()
-        parser.addErrorListener(ConsoleErrorListener())
         parserErrorListener = NestMLErrorListener()
         parser.addErrorListener(parserErrorListener)
         # parser._errHandler = BailErrorStrategy()	# N.B. uncomment this line and the next to halt immediately on parse errors
@@ -126,9 +129,13 @@ def parse_file(cls, file_path=None):
         parser.setTokenStream(stream)
         compilation_unit = parser.nestMLCompilationUnit()
         if parserErrorListener._error_occurred:
-            code, message = Messages.get_parser_error()
+            error_location = ASTSourceLocation(parserErrorListener.line,
+                                               parserErrorListener.column,
+                                               parserErrorListener.line,
+                                               parserErrorListener.column)
+            code, message = Messages.get_parser_error(parserErrorListener.msg)
             Logger.log_message(node=None, code=None, message=message,
-                               error_position=None, log_level=LoggingLevel.ERROR)
+                               error_position=error_location, log_level=LoggingLevel.ERROR)
             return
 
         # create a new visitor and return the new AST