ABW
ABW

Reputation: 161

Ways of keeping ANTLR4 grammar target independent

I'm writing a grammar for C++ target, however I'd like to keep it working with Java as well since ANTLR comes with great tools that work for grammars with Java target. The book ("The Definitive ANTLR 4 Reference") says that the way of achieving target independence is to use listeners and/or visitors. There is one problem though. Any predicate, local variable, custom constructor, custom token class etc. that I might need introduces target language dependence that cannot be removed, at least according to the information I took from the book. Since the book might be outdated here are the questions:

Is there a way of declaring primitive variables in language independent way, something like:

item[$bool hasAttr]
:
  type ( { $hasAttr }? attr | ) ID
;

where $bool would be translated to bool in C++, but to boolean in Java (workaround would be to use int in that case but most likely not in all potential targets)

Is there a way of declaring certain code fragments to be for specific target only, something like:

parser grammar testParser;
options
{
tokenVocab=testLexer;
}

@header
<lang=Cpp>{
#include "utils/helper.h"
}
<lang=Java>{
import test.utils.THelper;
}

@members
<lang=Cpp>{
public:
  testParser(antlr4::TokenStream *input, utils::THelper *helper);

private:
  utils::THelper *Helper;

public:
}
<lang=Java>{
public testParser(TokenStream input, THelper helper) {
  this(input);
  Helper = helper;
}

private THelper Helper;
}

start
:
  (
  <lang=Cpp>{ Helper->OnUnitStart(this); }
  <lang=Java>{ Helper.OnUnitStart(this); }
  unit
  <lang=Cpp>{ _localctx = Helper->OnUnitEnd(this); }
  <lang=Java>{ _localctx = Helper.OnUnitEnd(this); }
  )*
  EOF
;

...

For the time being I'm keeping two separate grammars changing the Java one and merging the changes to C++ one once I'm happy with the results, but if possible I'd rather keep it in one file.

Upvotes: 4

Views: 615

Answers (1)

Mike Lischke
Mike Lischke

Reputation: 53317

This target dependency is a real nuisance and I'm thinking for a while already how to get rid of that in a good way. Haven't still found something fully usable.

What you can do is to stay with syntax that both Java and C++ can understand (e.g. write a predicate like a function call: a: { isValid() }? b c; and implement such functions in a base class from which you derive your parser (ANTLR allows to specify such a base class via the grammar option superClass).

The C++ target also got a number of additional named actions which you can use to specify C++ specific stuff only.

Upvotes: 2

Related Questions