ashok
ashok

Reputation: 1268

How to write grammar in Antlr4 for function with zero arguments

I'm having function with arguments grammar like below lexer and parser:

MyFunctionsLexer.g4

lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Za-z0-9]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
WS : [ \t\r\n]+ -> skip;

MyFunctionsParser.g4

parser grammar MyFunctionsParser;
options { tokenVocab=MyFunctionsLexer; }
functions : function* EOF;
function : FUNCTION '.' NAME '(' (function | argument (',' argument)*) ')';
argument: (NAME | function);

But in parser is accepting function with arguments or function with argument as function(nested function). I am using visitor pattern for validation. But now if I pass function with no arguments it is throwing error. How to accept function with zero argument in the above parser?

Example For Working input:

FUNCTION.toString(String)

Example For Not Working input:

FUNCTION.getTimestamp()

Upvotes: 2

Views: 1483

Answers (1)

sepp2k
sepp2k

Reputation: 370112

function : FUNCTION '.' NAME '(' (function | argument (',' argument)*) ')';

First of all the function | here is really odd. At the face of it, it would mean that you can call a function with only a single function call as its argument or with arbitrarily many arguments. But since argument itself already contains function as an alternative, it's simply redundant. So let's simplify the rule by removing that part:

function : FUNCTION '.' NAME '(' (argument (',' argument)*) ')';

So why does this not match function calls without arguments? Because the argument before the comma is not optional. The ',' argument part has a * applied to it, so it can appear any number of times - including zero. But the first argument doesn't have any modifiers, so it needs to be there.

So how can we change that? Given that I just identified the problem as the first argument not being optional, one's first thought might be to just make the argument optional by adding a ? directly after it (i.e. argument? (',' argument)*), but that would also allow constructions such as FUNCTION.f(,X), which you presumably don't want to allow.

Instead you should apply ? to the whole list of arguments, like this:

(argument (',' argument)*)?

That way it can match either "an argument followed by zero or more instances of 'comma followed by argument'" or nothing.

Upvotes: 4

Related Questions