Updated spec_parser such that it runs with ANTLR v4

Change-Id: Ib0711ebc125f4fadb5a526c3538d5c3a35f11234
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97320
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/tools/spec_parse.py b/tools/spec_parse.py
index 79ba306..ba87ff8 100755
--- a/tools/spec_parse.py
+++ b/tools/spec_parse.py
@@ -4,14 +4,14 @@
 # for details. All rights reserved. Use of this source code is governed by a
 # BSD-style license that can be found in the LICENSE file.
 
-# This script runs the parser which is generated using ANTLR 3 from
+# This script runs the parser which is generated using ANTLR 4 from
 # docs/language/Dart.g. It relies on a certain environment and is hence
 # usable locally where this environment can be obtained, but it may not be
 # possible to run it, e.g., on build bots. The requirements are as follows:
 #
 #   - `make parser` in spec_parser has been executed successfully.
 #   - A suitable JVM is in the PATH and may be executed as 'java'.
-#   - the ANTLR3 jar is available as /usr/share/java/antlr3-runtime.jar.
+#   - the ANTLR3 jar is available as /usr/share/java/antlr4-runtime.jar.
 
 import os
 import string
@@ -32,7 +32,7 @@
   tools_dir = os.path.dirname(os.path.realpath(__file__))
   spec_parser_dir = os.path.join(tools_dir, 'spec_parser')
   spec_parser_file = os.path.join(spec_parser_dir, 'SpecParser.class')
-  antlr_jar = '/usr/share/java/antlr3-runtime.jar'
+  antlr_jar = '/usr/share/java/antlr4-runtime.jar'
   class_path = string.join([spec_parser_dir, antlr_jar], ':')
   command = ['java', '-cp', class_path, 'SpecParser'] + args
 
diff --git a/tools/spec_parser/.gitignore b/tools/spec_parser/.gitignore
index 5810652..8f983c7 100644
--- a/tools/spec_parser/.gitignore
+++ b/tools/spec_parser/.gitignore
@@ -1,5 +1,6 @@
 *Lexer.java
 *Parser.java
+*Listener.java
 *.tokens
 *.class
 *.dot
diff --git a/docs/language/Dart.g b/tools/spec_parser/Dart.g
similarity index 77%
rename from docs/language/Dart.g
rename to tools/spec_parser/Dart.g
index f586c96..099964f 100644
--- a/docs/language/Dart.g
+++ b/tools/spec_parser/Dart.g
@@ -43,29 +43,6 @@
     return !errorHasOccurred;
   }
 
-  /// Produce grammar debugging friendly output, as described in 'The
-  /// Definitive ANTLR Reference', p247.
-  public String getErrorMessage(RecognitionException e, String[] tokenNames) {
-    List stack = getRuleInvocationStack(e, this.getClass().getName());
-    String msg = null;
-    if (e instanceof NoViableAltException) {
-      NoViableAltException nvae = (NoViableAltException)e;
-      msg = "no viable alt; token=" + e.token +
-          " (decision=" + nvae.decisionNumber +
-          " state " + nvae.stateNumber + ")" +
-          " decision=<<" + nvae.grammarDecisionDescription + ">>";
-    }
-    else {
-      msg = super.getErrorMessage(e, tokenNames);
-    }
-    if (!errorHasOccurred) prepareForErrors();
-    return stack + " " + msg;
-  }
-
-  public String getTokenErrorDisplay(Token t) {
-    return t.toString();
-  }
-
   // Enable the parser to treat ASYNC/AWAIT/YIELD as keywords in the body of an
   // `async`, `async*`, or `sync*` function. Access via methods below.
   private Stack<Boolean> asyncEtcAreKeywords = new Stack<Boolean>();
@@ -89,20 +66,6 @@
     }
     return false;
   }
-
-  // Debugging support methods.
-  void dp(int indent, String method, String sep) {
-    for (int i = 0; i < indent; i++) {
-      System.out.print("  ");
-    }
-    System.out.println(method + sep + " " + input.LT(1) + " " + state.failed);
-  }
-
-  void dpBegin(int indent, String method) { dp(indent, method, ":"); }
-  void dpEnd(int indent, String method) { dp(indent, method, " END:"); }
-  void dpCall(int indent, String method) { dp(indent, method, "?"); }
-  void dpCalled(int indent, String method) { dp(indent, method, ".."); }
-  void dpResult(int indent, String method) { dp(indent, method, "!"); }
 }
 
 @lexer::members{
@@ -112,13 +75,6 @@
   public static final int BRACE_THREE_SINGLE = 4;
   public static final int BRACE_THREE_DOUBLE = 5;
 
-  /// This override ensures that lexer errors are recognized as errors,
-  /// but does not change the format of the reported error.
-  public String getErrorMessage(RecognitionException e, String[] tokenNames) {
-    if (!DartParser.errorHasOccurred) DartParser.prepareForErrors();
-    return super.getErrorMessage(e, tokenNames);
-  }
-
   // Enable the parser to handle string interpolations via brace matching.
   // The top of the `braceLevels` stack describes the most recent unmatched
   // '{'. This is needed in order to enable/disable certain lexer rules.
@@ -171,9 +127,9 @@
 
 libraryDefinition
     :    FEFF? SCRIPT_TAG?
-         ((metadata LIBRARY) => libraryName)?
-         ((metadata (IMPORT | EXPORT)) => importOrExport)*
-         ((metadata PART) => partDirective)*
+         libraryName?
+         importOrExport*
+         partDirective*
          (metadata topLevelDefinition)*
          EOF
     ;
@@ -181,16 +137,13 @@
 topLevelDefinition
     :    classDefinition
     |    enumType
-    |    (TYPEDEF typeIdentifier typeParameters? '=') => typeAlias
-    |    (TYPEDEF functionPrefix ('<' | '(')) => typeAlias
-    |    (EXTERNAL functionSignature ';') => EXTERNAL functionSignature ';'
-    |    (EXTERNAL getterSignature) => EXTERNAL getterSignature ';'
-    |    (EXTERNAL type? SET identifier '(') =>
-         EXTERNAL setterSignature ';'
-    |    (getterSignature functionBodyPrefix) => getterSignature functionBody
-    |    (type? SET identifier '(') => setterSignature functionBody
-    |    (type? identifierNotFUNCTION typeParameters? '(') =>
-         functionSignature functionBody
+    |    typeAlias
+    |    EXTERNAL functionSignature ';'
+    |    EXTERNAL getterSignature ';'
+    |    EXTERNAL setterSignature ';'
+    |    getterSignature functionBody
+    |    setterSignature functionBody
+    |    functionSignature functionBody
     |    (FINAL | CONST) type? staticFinalDeclarationList ';'
     |    topLevelVariableDeclaration ';'
     ;
@@ -276,9 +229,8 @@
     ;
 
 normalFormalParameterNoMetadata
-    :    (COVARIANT? type? identifierNotFUNCTION formalParameterPart) =>
-         functionFormalParameter
-    |    (finalConstVarOrType? THIS) => fieldFormalParameter
+    :    functionFormalParameter
+    |    fieldFormalParameter
     |    simpleFormalParameter
     ;
 
@@ -310,11 +262,9 @@
     ;
 
 classDefinition
-    :    (ABSTRACT? CLASS typeApplication (EXTENDS|IMPLEMENTS|LBRACE)) =>
-         ABSTRACT? CLASS typeApplication (superclass mixins?)? interfaces?
+    :    ABSTRACT? CLASS typeApplication (superclass mixins?)? interfaces?
          LBRACE (metadata classMemberDefinition)* RBRACE
-    |    (ABSTRACT? CLASS typeApplication '=') =>
-         ABSTRACT? CLASS mixinApplicationClass
+    |    ABSTRACT? CLASS mixinApplicationClass
     ;
 
 mixins
@@ -322,18 +272,17 @@
     ;
 
 classMemberDefinition
-    :    (methodSignature functionBodyPrefix) => methodSignature functionBody
+    :    methodSignature functionBody
     |    declaration ';'
     ;
 
 methodSignature
-    :    (constructorSignature ':') => constructorSignature initializers
-    |    (FACTORY constructorName '(') => factoryConstructorSignature
-    |    (STATIC? type? identifierNotFUNCTION typeParameters? '(') =>
-         STATIC? functionSignature
-    |    (STATIC? type? GET) => STATIC? getterSignature
-    |    (STATIC? type? SET) => STATIC? setterSignature
-    |    (type? OPERATOR operator '(') => operatorSignature
+    :    constructorSignature initializers
+    |    factoryConstructorSignature
+    |    STATIC? functionSignature
+    |    STATIC? getterSignature
+    |    STATIC? setterSignature
+    |    operatorSignature
     |    constructorSignature
     ;
 
@@ -355,25 +304,17 @@
 // check.
 
 declaration
-    :    (EXTERNAL CONST? FACTORY constructorName '(') =>
-         EXTERNAL factoryConstructorSignature
-    |    (EXTERNAL CONST constructorName '(') =>
-         EXTERNAL constantConstructorSignature
-    |    (EXTERNAL constructorName '(') => EXTERNAL constructorSignature
-    |    ((EXTERNAL STATIC?)? type? GET identifier) =>
-         (EXTERNAL STATIC?)? getterSignature
-    |    ((EXTERNAL STATIC?)? type? SET identifier) =>
-         (EXTERNAL STATIC?)? setterSignature
-    |    (EXTERNAL? type? OPERATOR) => EXTERNAL? operatorSignature
-    |    (STATIC (FINAL | CONST)) =>
-         STATIC (FINAL | CONST) type? staticFinalDeclarationList
+    :    EXTERNAL factoryConstructorSignature
+    |    EXTERNAL constantConstructorSignature
+    |    EXTERNAL constructorSignature
+    |    (EXTERNAL STATIC?)? getterSignature
+    |    (EXTERNAL STATIC?)? setterSignature
+    |    EXTERNAL? operatorSignature
+    |    STATIC (FINAL | CONST) type? staticFinalDeclarationList
     |    FINAL type? initializedIdentifierList
-    |    ((STATIC | COVARIANT)? (VAR | type) identifier ('=' | ',' | ';')) =>
-         (STATIC | COVARIANT)? (VAR | type) initializedIdentifierList
-    |    (EXTERNAL? STATIC? functionSignature ';') =>
-         EXTERNAL? STATIC? functionSignature
-    |    (CONST? FACTORY constructorName formalParameterList '=') =>
-         redirectingFactoryConstructorSignature
+    |    (STATIC | COVARIANT)? (VAR | type) initializedIdentifierList
+    |    EXTERNAL? STATIC? functionSignature
+    |    redirectingFactoryConstructorSignature
     |    constantConstructorSignature (redirection | initializers)?
     |    constructorSignature (redirection | initializers)?
     ;
@@ -400,7 +341,7 @@
 binaryOperator
     :    multiplicativeOperator
     |    additiveOperator
-    |    (shiftOperator) => shiftOperator
+    |    shiftOperator
     |    relationalOperator
     |    '=='
     |    bitwiseOperator
@@ -496,20 +437,16 @@
     ;
 
 expression
-    :    (formalParameterPart functionExpressionBodyPrefix) =>
-         functionExpression
+    :    functionExpression
     |    throwExpression
-    |    (assignableExpression assignmentOperator) =>
-         assignableExpression assignmentOperator expression
+    |    assignableExpression assignmentOperator expression
     |    conditionalExpression cascadeSection*
     ;
 
 expressionWithoutCascade
-    :    (formalParameterPart functionExpressionBodyPrefix) =>
-         functionExpressionWithoutCascade
+    :    functionExpressionWithoutCascade
     |    throwExpressionWithoutCascade
-    |    (assignableExpression assignmentOperator) =>
-         assignableExpression assignmentOperator expressionWithoutCascade
+    |    assignableExpression assignmentOperator expressionWithoutCascade
     |    conditionalExpression
     ;
 
@@ -520,9 +457,9 @@
 primary
     :    thisExpression
     |    SUPER unconditionalAssignableSelector
-    |    (CONST constructorDesignation) => constObjectExpression
+    |    constObjectExpression
     |    newExpression
-    |    (formalParameterPart functionPrimaryBodyPrefix) => functionPrimary
+    |    functionPrimary
     |    '(' expression ')'
     |    literal
     |    identifier
@@ -534,7 +471,7 @@
     |    numericLiteral
     |    stringLiteral
     |    symbolLiteral
-    |    (CONST? typeArguments? LBRACE) => mapLiteral
+    |    mapLiteral
     |    listLiteral
     ;
 
@@ -770,8 +707,8 @@
     ;
 
 unaryExpression
-    :    (prefixOperator ~SUPER) => prefixOperator unaryExpression
-    |    (awaitExpression) => awaitExpression
+    :    prefixOperator unaryExpression
+    |    awaitExpression
     |    postfixExpression
     |    (minusOperator | tildeOperator) SUPER
     |    incrementOperator assignableExpression
@@ -804,11 +741,9 @@
 // sequence of two relational expressions.
 
 postfixExpression
-    :    (assignableExpression postfixOperator) =>
-         assignableExpression postfixOperator
-    |    (typeName typeArguments '.') =>
-         constructorInvocation ((selector) => selector)*
-    |    primary ((selector) => selector)*
+    :    assignableExpression postfixOperator
+    |    constructorInvocation selector*
+    |    primary selector*
     ;
 
 constructorInvocation
@@ -841,15 +776,10 @@
 // relationalOperator, not the beginning of typeArguments.
 
 assignableExpression
-    :    (SUPER unconditionalAssignableSelector
-            ~('<' | '(' | '[' | '.' | '?.')) =>
-         SUPER unconditionalAssignableSelector
-    |    (typeName typeArguments '.' identifier '(') =>
-         constructorInvocation
-         ((assignableSelectorPart) => assignableSelectorPart)+
-    |    (identifier ~('<' | '(' | '[' | '.' | '?.')) => identifier
-    |    (primary assignableSelectorPart) =>
-         primary ((assignableSelectorPart) => assignableSelectorPart)+
+    :    SUPER unconditionalAssignableSelector
+    |    constructorInvocation assignableSelectorPart+
+    |    identifier
+    |    primary assignableSelectorPart+
     |    identifier
     ;
 
@@ -891,7 +821,7 @@
     |    ON // Not a built-in identifier.
     |    SHOW // Not a built-in identifier.
     |    SYNC // Not a built-in identifier.
-    |    { asyncEtcPredicate(input.LA(1)) }? (ASYNC|AWAIT|YIELD)
+    |    { asyncEtcPredicate(getCurrentToken().getType()) }? (ASYNC|AWAIT|YIELD)
     ;
 
 identifier
@@ -913,7 +843,7 @@
     |    ON // Not a built-in identifier.
     |    SHOW // Not a built-in identifier.
     |    SYNC // Not a built-in identifier.
-    |    { asyncEtcPredicate(input.LA(1)) }? (ASYNC|AWAIT|YIELD)
+    |    { asyncEtcPredicate(getCurrentToken().getType()) }? (ASYNC|AWAIT|YIELD)
     ;
 
 typeTest
@@ -947,10 +877,9 @@
 // add another statement which can start with LBRACE we must adjust this
 // check.
 nonLabelledStatement
-    :    (LBRACE) => block
-    |    (metadata declaredIdentifier ('='|','|';')) =>
-         localVariableDeclaration
-    |    (AWAIT? FOR) => forStatement
+    :    block
+    |    localVariableDeclaration
+    |    forStatement
     |    whileStatement
     |    doStatement
     |    switchStatement
@@ -960,10 +889,9 @@
     |    breakStatement
     |    continueStatement
     |    returnStatement
-    |    (metadata functionSignature functionBodyPrefix) =>
-         localFunctionDeclaration
+    |    localFunctionDeclaration
     |    assertStatement
-    |    (YIELD ~'*') => yieldStatement
+    |    yieldStatement
     |    yieldEachStatement
     |    expressionStatement
     ;
@@ -985,7 +913,7 @@
     ;
 
 ifStatement
-    :    IF '(' expression ')' statement ((ELSE) => ELSE statement | ())
+    :    IF '(' expression ')' statement (ELSE statement | ())
     ;
 
 forStatement
@@ -993,16 +921,15 @@
     ;
 
 forLoopParts
-    :    (metadata declaredIdentifier IN) =>
-         metadata declaredIdentifier IN expression
-    |    (metadata identifier IN) => metadata identifier IN expression
+    :    metadata declaredIdentifier IN expression
+    |    metadata identifier IN expression
     |    forInitializerStatement expression? ';' expressionList?
     ;
 
 // The localVariableDeclaration cannot be CONST, but that can
 // be enforced in a later phase, and the grammar allows it.
 forInitializerStatement
-    :    (localVariableDeclaration) => localVariableDeclaration
+    :    localVariableDeclaration
     |    expression? ';'
     ;
 
@@ -1040,7 +967,7 @@
     ;
 
 onParts
-    :    (onPart (ON|CATCH)) => onPart onParts
+    :    onPart onParts
     |    onPart
     ;
 
@@ -1089,8 +1016,8 @@
     ;
 
 importOrExport
-    :    (metadata IMPORT) => libraryImport
-    |    (metadata EXPORT) => libraryExport
+    :    libraryImport
+    |    libraryExport
     ;
 
 libraryImport
@@ -1132,9 +1059,8 @@
     ;
 
 type
-    :    (FUNCTION ('('|'<')) => functionTypeTails
-    |    (typeNotFunction FUNCTION ('('|'<')) =>
-         typeNotFunction functionTypeTails
+    :    functionTypeTails
+    |    typeNotFunction functionTypeTails
     |    typeNotFunction
     ;
 
@@ -1144,7 +1070,7 @@
     ;
 
 typeNotVoid
-    :    (typeNotFunction? FUNCTION ('('|'<')) => functionType
+    :    functionType
     |    typeNotVoidNotFunction
     ;
 
@@ -1170,8 +1096,7 @@
     ;
 
 typeAlias
-    :    (TYPEDEF typeIdentifier typeParameters? '=') =>
-         TYPEDEF typeIdentifier typeParameters? '=' functionType ';'
+    :    TYPEDEF typeIdentifier typeParameters? '=' functionType ';'
     |    TYPEDEF functionTypeAlias
     ;
 
@@ -1180,7 +1105,7 @@
     ;
 
 functionPrefix
-    :    (type identifier) => type identifier
+    :    type identifier
     |    identifier
     ;
 
@@ -1189,22 +1114,19 @@
     ;
 
 functionTypeTails
-    :    (functionTypeTail FUNCTION ('<'|'(')) =>
-         functionTypeTail functionTypeTails
+    :    functionTypeTail functionTypeTails
     |    functionTypeTail
     ;
 
 functionType
-    :    (FUNCTION ('<'|'(')) => functionTypeTails
+    :    functionTypeTails
     |    typeNotFunction functionTypeTails
     ;
 
 parameterTypeList
-    :    ('(' ')') => '(' ')'
-    |    ('(' normalParameterTypes ',' ('['|'{')) =>
-         '(' normalParameterTypes ',' optionalParameterTypes ')'
-    |    ('(' normalParameterTypes ','? ')') =>
-         '(' normalParameterTypes ','? ')'
+    :    '(' ')'
+    |    '(' normalParameterTypes ',' optionalParameterTypes ')'
+    |    '(' normalParameterTypes ','? ')'
     |    '(' optionalParameterTypes ')'
     ;
 
@@ -1213,7 +1135,7 @@
     ;
 
 normalParameterType
-    :    (typedIdentifier) => typedIdentifier
+    :    typedIdentifier
     |    type
     ;
 
@@ -1239,9 +1161,8 @@
     |    typeName typeArguments ('.' identifier)?
     ;
 
-// Predicate: Force resolution as composite symbolLiteral as far as possible.
 symbolLiteral
-    :    '#' (operator | (identifier (('.' identifier) => '.' identifier)*))
+    :    '#' (operator | (identifier ('.' identifier)*))
     ;
 
 singleLineStringWithoutInterpolation
@@ -1536,7 +1457,7 @@
     ;
 
 NUMBER
-    :    (DIGIT+ '.' DIGIT) => DIGIT+ '.' DIGIT+ EXPONENT?
+    :    DIGIT+ '.' DIGIT+ EXPONENT?
     |    DIGIT+ EXPONENT?
     |    '.' DIGIT+ EXPONENT?
     ;
@@ -1552,8 +1473,8 @@
     ;
 
 RAW_MULTI_LINE_STRING
-    :    'r' '"""' (options {greedy=false;} : .)* '"""'
-    |    'r' '\'\'\'' (options {greedy=false;} : .)* '\'\'\''
+    :    'r' '"""' (.)*? '"""'
+    |    'r' '\'\'\'' (.)*? '\'\'\''
     ;
 
 fragment
@@ -1577,15 +1498,13 @@
     ;
 
 SINGLE_LINE_STRING_SQ_MID_MID
-    :    { currentBraceLevel(BRACE_SINGLE) }? =>
-         ('}' STRING_CONTENT_SQ* '${') =>
+    :    { currentBraceLevel(BRACE_SINGLE) }?
          { exitBrace(); } '}' STRING_CONTENT_SQ* '${'
          { enterBraceSingleQuote(); }
     ;
 
 SINGLE_LINE_STRING_SQ_MID_END
-    :    { currentBraceLevel(BRACE_SINGLE) }? =>
-         ('}' STRING_CONTENT_SQ* '\'') =>
+    :    { currentBraceLevel(BRACE_SINGLE) }?
          { exitBrace(); } '}' STRING_CONTENT_SQ* '\''
     ;
 
@@ -1605,15 +1524,13 @@
     ;
 
 SINGLE_LINE_STRING_DQ_MID_MID
-    :    { currentBraceLevel(BRACE_DOUBLE) }? =>
-         ('}' STRING_CONTENT_DQ* '${') =>
+    :    { currentBraceLevel(BRACE_DOUBLE) }?
          { exitBrace(); } '}' STRING_CONTENT_DQ* '${'
          { enterBraceDoubleQuote(); }
     ;
 
 SINGLE_LINE_STRING_DQ_MID_END
-    :    { currentBraceLevel(BRACE_DOUBLE) }? =>
-         ('}' STRING_CONTENT_DQ* '"') =>
+    :    { currentBraceLevel(BRACE_DOUBLE) }?
          { exitBrace(); } '}' STRING_CONTENT_DQ* '"'
     ;
 
@@ -1644,15 +1561,13 @@
     ;
 
 MULTI_LINE_STRING_SQ_MID_MID
-    :    { currentBraceLevel(BRACE_THREE_SINGLE) }? =>
-         ('}' STRING_CONTENT_TSQ* QUOTES_SQ '${') =>
+    :    { currentBraceLevel(BRACE_THREE_SINGLE) }?
          { exitBrace(); } '}' STRING_CONTENT_TSQ* QUOTES_SQ '${'
          { enterBraceThreeSingleQuotes(); }
     ;
 
 MULTI_LINE_STRING_SQ_MID_END
-    :    { currentBraceLevel(BRACE_THREE_SINGLE) }? =>
-         ('}' STRING_CONTENT_TSQ* '\'\'\'') =>
+    :    { currentBraceLevel(BRACE_THREE_SINGLE) }?
          { exitBrace(); } '}' STRING_CONTENT_TSQ* '\'\'\''
     ;
 
@@ -1682,15 +1597,13 @@
     ;
 
 MULTI_LINE_STRING_DQ_MID_MID
-    :    { currentBraceLevel(BRACE_THREE_DOUBLE) }? =>
-         ('}' STRING_CONTENT_TDQ* QUOTES_DQ '${') =>
+    :    { currentBraceLevel(BRACE_THREE_DOUBLE) }?
          { exitBrace(); } '}' STRING_CONTENT_TDQ* QUOTES_DQ '${'
          { enterBraceThreeDoubleQuotes(); }
     ;
 
 MULTI_LINE_STRING_DQ_MID_END
-    :    { currentBraceLevel(BRACE_THREE_DOUBLE) }? =>
-         ('}' STRING_CONTENT_TDQ* '"""') =>
+    :    { currentBraceLevel(BRACE_THREE_DOUBLE) }?
          { exitBrace(); } '}' STRING_CONTENT_TDQ* '"""'
     ;
 
@@ -1699,7 +1612,7 @@
     ;
 
 RBRACE
-    :    { currentBraceLevel(BRACE_NORMAL) }? => ('}') => { exitBrace(); } '}'
+    :    { currentBraceLevel(BRACE_NORMAL) }? { exitBrace(); } '}'
     ;
 
 fragment
@@ -1745,7 +1658,7 @@
     ;
 
 MULTI_LINE_COMMENT
-    :    '/*' (options {greedy=false;} : (MULTI_LINE_COMMENT | .))* '*/'
+    :    '/*' (MULTI_LINE_COMMENT | .)*? '*/'
          { skip(); }
     ;
 
diff --git a/tools/spec_parser/Makefile b/tools/spec_parser/Makefile
index f91e7d3..dca1088 100644
--- a/tools/spec_parser/Makefile
+++ b/tools/spec_parser/Makefile
@@ -6,9 +6,9 @@
 JAVA_PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin
 JAVA=$(JAVA_PATH)/java
 JAVAC=javac
-ANTLR_JAR=/usr/share/java/antlr3-runtime.jar
+ANTLR_JAR=/usr/share/java/antlr4-runtime.jar
 ANTLR_FILES=DartLexer.java DartParser.java Dart.tokens
-ANTLR_CMD=PATH=$(JAVA_PATH):$(PATH) antlr3 -dfa -fo . $<
+ANTLR_CMD=PATH=$(JAVA_PATH):$(PATH) antlr4 $<
 JAVA_FILES=DartLexer.java DartParser.java
 CLASS_FILES=SpecParser.class SpecParserRunner.class DartLexer.class DartParser.class
 
@@ -21,11 +21,11 @@
 SpecParser.class: $(ANTLR_FILES) SpecParser.java
 	$(JAVAC) -cp .:$(ANTLR_JAR) SpecParser.java
 
-%Lexer.java: ../../docs/language/%.g Makefile ; $(ANTLR_CMD)
+%Lexer.java: %.g Makefile ; $(ANTLR_CMD)
 
-%Parser.java: ../../docs/language/%.g Makefile ; $(ANTLR_CMD)
+%Parser.java: %.g Makefile ; $(ANTLR_CMD)
 
-%.tokens: ../../docs/language/%.g Makefile ; $(ANTLR_CMD)
+%.tokens: %.g Makefile ; $(ANTLR_CMD)
 
 clean:
 	rm -f $(CLASS_FILES) $(ANTLR_FILES)
diff --git a/tools/spec_parser/SpecParser.java b/tools/spec_parser/SpecParser.java
index 0f6ba68..cc9d1ea 100644
--- a/tools/spec_parser/SpecParser.java
+++ b/tools/spec_parser/SpecParser.java
@@ -4,13 +4,52 @@
 
 import java.io.*;
 import java.util.*;
-import org.antlr.runtime.*;
+import org.antlr.v4.runtime.*;
+import org.antlr.v4.runtime.dfa.*;
+import org.antlr.v4.runtime.atn.*;
 
 class ParsingResult {
   public int numberOfFileArguments;
   public int numberOfFailures;
 }
 
+class DartErrorListener implements ANTLRErrorListener {
+  public void reportAmbiguity(
+      Parser recognizer,
+      DFA dfa,
+      int startIndex,
+      int stopIndex,
+      boolean exact,
+      BitSet ambigAlts,
+      ATNConfigSet configs) {}
+
+  public void reportAttemptingFullContext(
+      Parser recognizer,
+      DFA dfa,
+      int startIndex,
+      int stopIndex,
+      BitSet conflictingAlts,
+      ATNConfigSet configs) {}
+
+  public void reportContextSensitivity(
+      Parser recognizer,
+      DFA dfa,
+      int startIndex,
+      int stopIndex,
+      int prediction,
+      ATNConfigSet configs) {}
+
+  public void syntaxError(
+      Recognizer<?,?> recognizer,
+      Object offendingSymbol,
+      int line,
+      int charPositionInLine,
+      String msg,
+      RecognitionException e) {
+    if (!DartParser.errorHasOccurred) DartParser.prepareForErrors();
+  }
+}
+
 /// Class for `main` which will parse files given as command line arguments.
 public class SpecParser {
   private static void normalExit() {
@@ -83,8 +122,11 @@
         continue;
       }
       if (verbose) System.err.println("Parsing file: " + filePath);
-      DartParser parser = new DartParser(new CommonTokenStream(
-          new DartLexer(new ANTLRFileStream(filePath))));
+      DartLexer lexer = new DartLexer(new ANTLRFileStream(filePath));
+      DartParser parser = new DartParser(new CommonTokenStream(lexer));
+      ANTLRErrorListener errorListener = new DartErrorListener();
+      lexer.addErrorListener(errorListener);
+      parser.addErrorListener(errorListener);
       if (!parser.parseLibrary(filePath)) result.numberOfFailures++;
     }
     return result;