4

I'm trying to use an ANTLR 4.5.3 parser in C# on Mono (running from Xamarin Studio 6.1.2 on macOS 10.11.3), but the code generated by the antlr4 Java command-line tool has one error which prevents compilation.

My grammar is as follows:

grammar Hello;

HELLO: 'hello';
WORD: [a-z]+;

greeting: HELLO WORD;

WS: [ \n\t\r]+ -> skip;

When the grammar is passed through antlr4 there are no errors or warnings, but in Xamarin Studio compilation of the resulting HelloParser class fails with:

Error CS0534: HelloParser does not implement inherited abstract member Antlr4.Runtime.Recognizer<Antlr4.Runtime.IToken,Antlr4.Runtime.Atn.ParserATNSimulator>.TokenNames.get (CS0534)

I've got the corresponding ANTLR 4.5.3 NuGet package, and there are no other errors. The rest of the resulting parser class appears to be OK. (A GreetingContext class and a HelloParser.greeting method are generated.)

Why is ANTLR not generating this method, and how can I fix this error?

If needed, here is the entire of the HelloParser.cs file:

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     ANTLR Version: 4.5.3
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

// Generated from Hello.g4 by ANTLR 4.5.3

// Unreachable code detected
#pragma warning disable 0162
// The variable '...' is assigned but its value is never used
#pragma warning disable 0219
// Missing XML comment for publicly visible type or member '...'
#pragma warning disable 1591
// Ambiguous reference in cref attribute
#pragma warning disable 419

using System;
using System.Text;
using System.Diagnostics;
using System.Collections.Generic;
using Antlr4.Runtime;
using Antlr4.Runtime.Atn;
using Antlr4.Runtime.Misc;
using Antlr4.Runtime.Tree;
using DFA = Antlr4.Runtime.Dfa.DFA;

[System.CodeDom.Compiler.GeneratedCode("ANTLR", "4.5.3")]
[System.CLSCompliant(false)]
public partial class HelloParser : Parser {
    public const int
        HELLO=1, WORD=2, WS=3;
    public const int
        RULE_greeting = 0;
    public static readonly string[] ruleNames = {
        "greeting"
    };

    private static readonly string[] _LiteralNames = {
        null, "'hello'"
    };
    private static readonly string[] _SymbolicNames = {
        null, "HELLO", "WORD", "WS"
    };
    public static readonly IVocabulary DefaultVocabulary = new Vocabulary(_LiteralNames, _SymbolicNames);

    [NotNull]
    public override IVocabulary Vocabulary
    {
        get
        {
            return DefaultVocabulary;
        }
    }

    public override string GrammarFileName { get { return "Hello.g4"; } }

    public override string[] RuleNames { get { return ruleNames; } }

    public override string SerializedAtn { get { return _serializedATN; } }

    public HelloParser(ITokenStream input)
        : base(input)
    {
        Interpreter = new ParserATNSimulator(this,_ATN);
    }
    public partial class GreetingContext : ParserRuleContext {
        public ITerminalNode HELLO() { return GetToken(HelloParser.HELLO, 0); }
        public ITerminalNode WORD() { return GetToken(HelloParser.WORD, 0); }
        public GreetingContext(ParserRuleContext parent, int invokingState)
            : base(parent, invokingState)
        {
        }
        public override int RuleIndex { get { return RULE_greeting; } }
        public override void EnterRule(IParseTreeListener listener) {
            IHelloListener typedListener = listener as IHelloListener;
            if (typedListener != null) typedListener.EnterGreeting(this);
        }
        public override void ExitRule(IParseTreeListener listener) {
            IHelloListener typedListener = listener as IHelloListener;
            if (typedListener != null) typedListener.ExitGreeting(this);
        }
    }

    [RuleVersion(0)]
    public GreetingContext greeting() {
        GreetingContext _localctx = new GreetingContext(Context, State);
        EnterRule(_localctx, 0, RULE_greeting);
        try {
            EnterOuterAlt(_localctx, 1);
            {
            State = 2; Match(HELLO);
            State = 3; Match(WORD);
            }
        }
        catch (RecognitionException re) {
            _localctx.exception = re;
            ErrorHandler.ReportError(this, re);
            ErrorHandler.Recover(this, re);
        }
        finally {
            ExitRule();
        }
        return _localctx;
    }

    private static string _serializedATN = _serializeATN();
    private static string _serializeATN()
    {
        StringBuilder sb = new StringBuilder();
        sb.Append("\x3\x430\xD6D1\x8206\xAD2D\x4417\xAEF1\x8D80\xAADD\x3\x5");
        sb.Append("\b\x4\x2\t\x2\x3\x2\x3\x2\x3\x2\x3\x2\x2\x2\x3\x2\x2\x2\x6\x2");
        sb.Append("\x4\x3\x2\x2\x2\x4\x5\a\x3\x2\x2\x5\x6\a\x4\x2\x2\x6\x3\x3\x2");
        sb.Append("\x2\x2\x2");
        return sb.ToString();
    }

    public static readonly ATN _ATN =
        new ATNDeserializer().Deserialize(_serializedATN.ToCharArray());
}

Comment if you need any of the other generated files in case the error isn't reproducible with your own ANTLR.

Aaron Christiansen
  • 11,584
  • 5
  • 52
  • 78
  • 1
    You most probably have a version mismatch between the tool and the runtime library. Double check that. Also, IIRC you need to use Sam Harwell's tool version if you use the runtime from NuGet, unless that changed. To make sure, grab the NuGet, unzip it and use the tool that's inside. – Lucas Trzesniewski Dec 30 '16 at 20:03
  • 1
    Awesome! I went into the *tools* directory of the NuGet package and replaced my ANTLR jar with the one in there, and now it works fine (though I did have to change my command to `antlr4 Hello.g4 -Dlanguage=CSharp_v4_5` instead of `antlr4 Hello.g4 -Dlanguage=CSharp`). Post as an answer and I'll accept. – Aaron Christiansen Dec 30 '16 at 20:15

1 Answers1

3

The NuGet packages use Sam Harwell's optimized C# target instead of the standard one. You can't use the tool from one version along with the runtime library from the other, they're not compatible: look at the release notes here.

So if you want to keep using the NuGet package for convenience, you can use the tool that's inside - the package is just a zip file.

I don't know if you can simplify this workflow with Xamarin Studio, but with Visual Studio you can completely skip the manual parser generation step, as the package integrates with MSBuild to generate the parser code at compile time.

Sam Harwell
  • 97,721
  • 20
  • 209
  • 280
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158